From b581fed30f7ca4e7b1ab13f3cb30e69315dc1b69 Mon Sep 17 00:00:00 2001 From: Seb Julliand Date: Fri, 29 Nov 2024 22:53:19 +0100 Subject: [PATCH 1/4] Enhanced Terminal opening process + set TERM=xterm Signed-off-by: Seb Julliand --- src/api/Terminal.ts | 197 ++++++++++++++++++++++++-------------------- 1 file changed, 107 insertions(+), 90 deletions(-) diff --git a/src/api/Terminal.ts b/src/api/Terminal.ts index b66630e16..f4800d65e 100644 --- a/src/api/Terminal.ts +++ b/src/api/Terminal.ts @@ -4,9 +4,10 @@ import vscode, { commands } from 'vscode'; import { instance } from '../instantiate'; import { GlobalConfiguration } from './Configuration'; import IBMi from './IBMi'; -import Instance from './Instance'; import { Tools } from './Tools'; +const PASE_INIT_FLAG = '#Code4iInitializationDone'; + function getOrDefaultToUndefined(value: string) { if (value && value !== `default`) { return value; @@ -33,6 +34,7 @@ export namespace Terminal { terminal?: string name?: string connectionString?: string + currentDirectory?: string } let terminalCount = 0; @@ -49,15 +51,14 @@ export namespace Terminal { export function registerTerminalCommands(context: vscode.ExtensionContext) { return [ vscode.commands.registerCommand(`code-for-ibmi.launchTerminalPicker`, () => { - return selectAndOpen(context, instance); + return selectAndOpen(context); }), vscode.commands.registerCommand(`code-for-ibmi.openTerminalHere`, async (ifsNode) => { const content = instance.getContent(); if (content) { const ifsPath = (await content.isDirectory(ifsNode.path)) ? ifsNode.path : path.dirname(ifsNode.path); - const terminal = await selectAndOpen(context, instance, TerminalType.PASE); - terminal?.sendText(`cd ${Tools.escapePath(ifsPath)}`); + await selectAndOpen(context, { openType: TerminalType.PASE, currentDirectory: ifsPath }); } }), @@ -71,11 +72,11 @@ export namespace Terminal { ]; } - async function selectAndOpen(context: vscode.ExtensionContext, instance: Instance, openType?: TerminalType) { + async function selectAndOpen(context: vscode.ExtensionContext, options?: { openType?: TerminalType, currentDirectory?: string }) { const connection = instance.getConnection(); const configuration = instance.getConfig(); if (connection && configuration) { - const type = openType || (await vscode.window.showQuickPick(typeItems, { + const type = options?.openType || (await vscode.window.showQuickPick(typeItems, { placeHolder: `Select a terminal type` }))?.type; @@ -83,7 +84,8 @@ export namespace Terminal { const terminalSettings: TerminalSettings = { type, location: GlobalConfiguration.get(`terminals.${type.toLowerCase()}.openInEditorArea`) ? vscode.TerminalLocation.Editor : vscode.TerminalLocation.Panel, - connectionString: configuration.connectringStringFor5250 + connectionString: configuration.connectringStringFor5250, + currentDirectory: options?.currentDirectory }; if (terminalSettings.type === TerminalType._5250) { @@ -115,102 +117,117 @@ export namespace Terminal { const HALTED = ` II`; async function createTerminal(context: vscode.ExtensionContext, connection: IBMi, terminalSettings: TerminalSettings) { + let ready = terminalSettings.type === TerminalType._5250; const writeEmitter = new vscode.EventEmitter(); - const paseWelcomeMessage = 'echo "Terminal started. Thanks for using Code for IBM i"'; - - const channel = await connection.client.requestShell(); - channel.stdout.on(`data`, (data: any) => { - const dataString: string = data.toString(); - if (dataString.trim().indexOf(paseWelcomeMessage) === -1) { + const channel = await connection.client.requestShell({ term: "xterm" }); + channel.on(`data`, (data: Buffer) => { + const dataString = data.toString(); + if (ready) { if (dataString.includes(HALTED)) { setHalted(true); } writeEmitter.fire(String(data)); } + + if (!ready) { + ready = dataString.trim().endsWith(PASE_INIT_FLAG); + } }); - const emulatorTerminal = vscode.window.createTerminal({ - name: `IBM i ${terminalSettings.type}: ${connection.config?.name}`, - location: terminalSettings.location, - pty: { - onDidWrite: writeEmitter.event, - open: () => { }, - close: () => { - channel.close(); - }, - handleInput: (data: string) => { - if (terminalSettings.type === TerminalType._5250) { - const buffer = Buffer.from(data); - - switch (buffer[0]) { - case BACKSPACE: //Backspace - //Move back one, space, move back again - deletes a character - channel.stdin.write(Buffer.from([ - 27, 79, 68, //Move back one - 27, 91, 51, 126 //Delete character - ])); - break; - - default: - if (buffer[0] === RESET || buffer[0] === ATTENTION) { - setHalted(false); - } - - channel.stdin.write(data); - break; + let emulatorTerminal: vscode.Terminal | undefined; + await new Promise((resolve) => { + vscode.window.createTerminal({ + name: `IBM i ${terminalSettings.type}: ${connection.config?.name}`, + location: terminalSettings.location, + pty: { + onDidWrite: writeEmitter.event, + open: resolve, + close: () => { + channel.close(); + }, + handleInput: (data: string) => { + if (terminalSettings.type === TerminalType._5250) { + const buffer = Buffer.from(data); + + switch (buffer[0]) { + case BACKSPACE: //Backspace + //Move back one, space, move back again - deletes a character + channel.stdin.write(Buffer.from([ + 27, 79, 68, //Move back one + 27, 91, 51, 126 //Delete character + ])); + break; + + default: + if (buffer[0] === RESET || buffer[0] === ATTENTION) { + setHalted(false); + } + + channel.stdin.write(data); + break; + } + } else { + channel.stdin.write(data); } - } else { - channel.stdin.write(data); + }, + setDimensions: (dim: vscode.TerminalDimensions) => { + channel.setWindow(String(dim.rows), String(dim.columns), `500`, `500`); } }, - setDimensions: (dim: vscode.TerminalDimensions) => { - channel.setWindow(String(dim.rows), String(dim.columns), `500`, `500`); - }, - }, - }); - channel.on(`close`, () => { - channel.destroy(); - writeEmitter.dispose(); - }); - channel.on(`exit`, (code: number, signal: any, coreDump: boolean, desc: string) => { - writeEmitter.fire(`----------\r\n`); - if (code === 0) { - writeEmitter.fire(`Completed successfully.\r\n`); - } - else if (code) { - writeEmitter.fire(`Exited with error code ${code}.\r\n`); - } - else { - writeEmitter.fire(`Exited with signal ${signal}.\r\n`); + }); + }) + + if (emulatorTerminal) { + channel.on(`close`, () => { + channel.destroy(); + writeEmitter.dispose(); + }); + channel.on(`exit`, (code: number, signal: any, coreDump: boolean, desc: string) => { + writeEmitter.fire(`----------\r\n`); + if (code === 0) { + writeEmitter.fire(`Completed successfully.\r\n`); + } + else if (code) { + writeEmitter.fire(`Exited with error code ${code}.\r\n`); + } + else { + writeEmitter.fire(`Exited with signal ${signal}.\r\n`); + } + }); + channel.on(`error`, (err: Error) => { + vscode.window.showErrorMessage(`Connection error: ${err.message}`); + emulatorTerminal.dispose(); + channel.destroy(); + }); + + emulatorTerminal!.show(); + if (terminalSettings.type === TerminalType._5250) { + channel.write([ + `/QOpenSys/pkgs/bin/tn5250`, + terminalSettings.encoding ? `map=${terminalSettings.encoding}` : ``, + terminalSettings.terminal ? `env.TERM=${terminalSettings.terminal}` : ``, + terminalSettings.name ? `env.DEVNAME=${terminalSettings.name}` : ``, + terminalSettings.connectionString || `localhost`, + `\n` + ].join(` `)); + } else { + const initialCommands = []; + if (terminalSettings.currentDirectory) { + initialCommands.push(`cd ${Tools.escapePath(terminalSettings.currentDirectory)}`); + } + initialCommands.push(`echo -e "\\0033[0;32mTerminal started, thanks for using \\0033[0;34mCode for IBM i. \\0033[0;32mCurrent directory is \\0033[0;34m"$(pwd)"\\0033[0m."`); + initialCommands.push(PASE_INIT_FLAG); + channel.write(`${initialCommands.join('; ')}\n`); } - }); - channel.on(`error`, (err: Error) => { - vscode.window.showErrorMessage(`Connection error: ${err.message}`); - emulatorTerminal.dispose(); - channel.destroy(); - }); - - emulatorTerminal.show(); - if (terminalSettings.type === TerminalType._5250) { - channel.stdin.write([ - `TERM=xterm /QOpenSys/pkgs/bin/tn5250`, - terminalSettings.encoding ? `map=${terminalSettings.encoding}` : ``, - terminalSettings.terminal ? `env.TERM=${terminalSettings.terminal}` : ``, - terminalSettings.name ? `env.DEVNAME=${terminalSettings.name}` : ``, - terminalSettings.connectionString || `localhost`, - `\n` - ].join(` `)); - } else { - channel.stdin.write(`${paseWelcomeMessage}\n`); - } - instance.subscribe( - context, - 'disconnected', - `Dispose Terminal ${terminalCount++}`, - () => emulatorTerminal.dispose(), - true); + instance.subscribe( + context, + 'disconnected', + `Dispose Terminal ${terminalCount++}`, + () => emulatorTerminal.dispose(), + true); - return emulatorTerminal; + return emulatorTerminal; + } } } \ No newline at end of file From 94185f89a23c4ca1b0fb402c57ebd09e189cbd8a Mon Sep 17 00:00:00 2001 From: Seb Julliand Date: Fri, 29 Nov 2024 23:04:27 +0100 Subject: [PATCH 2/4] Make TerminalSettings a type Signed-off-by: Seb Julliand --- src/api/Terminal.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/Terminal.ts b/src/api/Terminal.ts index f4800d65e..b7672c5d6 100644 --- a/src/api/Terminal.ts +++ b/src/api/Terminal.ts @@ -27,7 +27,7 @@ export namespace Terminal { } }); - interface TerminalSettings { + type TerminalSettings = { type: TerminalType location: vscode.TerminalLocation encoding?: string From d964d1e53bb07c04c9fd95282bd9ba0ced0afecc Mon Sep 17 00:00:00 2001 From: Seb Julliand Date: Fri, 29 Nov 2024 23:10:02 +0100 Subject: [PATCH 3/4] Forgot to reassign terminal variable Signed-off-by: Seb Julliand --- src/api/Terminal.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/api/Terminal.ts b/src/api/Terminal.ts index b7672c5d6..4ad6086c9 100644 --- a/src/api/Terminal.ts +++ b/src/api/Terminal.ts @@ -136,7 +136,7 @@ export namespace Terminal { let emulatorTerminal: vscode.Terminal | undefined; await new Promise((resolve) => { - vscode.window.createTerminal({ + emulatorTerminal = vscode.window.createTerminal({ name: `IBM i ${terminalSettings.type}: ${connection.config?.name}`, location: terminalSettings.location, pty: { @@ -196,11 +196,11 @@ export namespace Terminal { }); channel.on(`error`, (err: Error) => { vscode.window.showErrorMessage(`Connection error: ${err.message}`); - emulatorTerminal.dispose(); + emulatorTerminal!.dispose(); channel.destroy(); }); - emulatorTerminal!.show(); + emulatorTerminal.show(); if (terminalSettings.type === TerminalType._5250) { channel.write([ `/QOpenSys/pkgs/bin/tn5250`, @@ -224,7 +224,7 @@ export namespace Terminal { context, 'disconnected', `Dispose Terminal ${terminalCount++}`, - () => emulatorTerminal.dispose(), + () => emulatorTerminal!.dispose(), true); return emulatorTerminal; From 8df5d998a3c0ab997b2dbbf403aec1d05b43f203 Mon Sep 17 00:00:00 2001 From: Seb Julliand Date: Mon, 2 Dec 2024 11:21:12 +0100 Subject: [PATCH 4/4] Fixed terminal initialization flag test Signed-off-by: Seb Julliand --- src/api/Terminal.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/api/Terminal.ts b/src/api/Terminal.ts index 4ad6086c9..389e4839b 100644 --- a/src/api/Terminal.ts +++ b/src/api/Terminal.ts @@ -6,7 +6,8 @@ import { GlobalConfiguration } from './Configuration'; import IBMi from './IBMi'; import { Tools } from './Tools'; -const PASE_INIT_FLAG = '#Code4iInitializationDone'; +const PASE_INIT_FLAG = '#C4IINIT'; +const PASE_INIT_FLAG_REGEX = /#+C+4+I+I+N+I+T+$/ function getOrDefaultToUndefined(value: string) { if (value && value !== `default`) { @@ -130,7 +131,7 @@ export namespace Terminal { } if (!ready) { - ready = dataString.trim().endsWith(PASE_INIT_FLAG); + ready = PASE_INIT_FLAG_REGEX.test(dataString.trim()); } }); @@ -175,6 +176,7 @@ export namespace Terminal { } }, }); + emulatorTerminal.show(); }) if (emulatorTerminal) { @@ -200,7 +202,6 @@ export namespace Terminal { channel.destroy(); }); - emulatorTerminal.show(); if (terminalSettings.type === TerminalType._5250) { channel.write([ `/QOpenSys/pkgs/bin/tn5250`, @@ -216,7 +217,7 @@ export namespace Terminal { initialCommands.push(`cd ${Tools.escapePath(terminalSettings.currentDirectory)}`); } initialCommands.push(`echo -e "\\0033[0;32mTerminal started, thanks for using \\0033[0;34mCode for IBM i. \\0033[0;32mCurrent directory is \\0033[0;34m"$(pwd)"\\0033[0m."`); - initialCommands.push(PASE_INIT_FLAG); + initialCommands.push([PASE_INIT_FLAG].join(" ")); channel.write(`${initialCommands.join('; ')}\n`); }