diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts index c88fa9619d6..b27f729f46d 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts @@ -425,23 +425,24 @@ import { assertNoRpc } from '../utils'; }); suite('Extension pty terminals', () => { - test('should fire onDidOpenTerminal and onDidCloseTerminal', (done) => { - disposables.push(window.onDidOpenTerminal(term => { - try { - equal(term.name, 'c'); - } catch (e) { - done(e); - return; - } - disposables.push(window.onDidCloseTerminal(() => done())); - term.dispose(); - })); + test('should fire onDidOpenTerminal and onDidCloseTerminal', async () => { const pty: Pseudoterminal = { onDidWrite: new EventEmitter().event, open: () => { }, close: () => { } }; - window.createTerminal({ name: 'c', pty }); + const terminal = await new Promise(r => { + disposables.push(window.onDidOpenTerminal(t => { + if (t.name === 'c') { + r(t); + } + })); + window.createTerminal({ name: 'c', pty }); + }); + await new Promise(r => { + disposables.push(window.onDidCloseTerminal(() => r())); + terminal.dispose(); + }); }); // The below tests depend on global UI state and each other @@ -491,31 +492,7 @@ import { assertNoRpc } from '../utils'; // const terminal = window.createTerminal({ name: 'foo', pty }); // }); - test('should respect dimension overrides', (done) => { - disposables.push(window.onDidOpenTerminal(term => { - try { - equal(terminal, term); - } catch (e) { - done(e); - return; - } - term.show(); - disposables.push(window.onDidChangeTerminalDimensions(e => { - // The default pty dimensions have a chance to appear here since override - // dimensions happens after the terminal is created. If so just ignore and - // wait for the right dimensions - if (e.dimensions.columns === 10 || e.dimensions.rows === 5) { - try { - equal(e.terminal, terminal); - } catch (e) { - done(e); - return; - } - disposables.push(window.onDidCloseTerminal(() => done())); - terminal.dispose(); - } - })); - })); + test('should respect dimension overrides', async () => { const writeEmitter = new EventEmitter(); const overrideDimensionsEmitter = new EventEmitter(); const pty: Pseudoterminal = { @@ -524,29 +501,30 @@ import { assertNoRpc } from '../utils'; open: () => overrideDimensionsEmitter.fire({ columns: 10, rows: 5 }), close: () => { } }; - const terminal = window.createTerminal({ name: 'foo', pty }); + const terminal = await new Promise(r => { + disposables.push(window.onDidOpenTerminal(t => { + if (t === created) { + r(t); + } + })); + const created = window.createTerminal({ name: 'foo', pty }); + }); + await new Promise(r => { + disposables.push(window.onDidChangeTerminalDimensions(e => { + strictEqual(e.terminal, terminal); + // The default pty dimensions have a chance to appear here since override + // dimensions happens after the terminal is created. If so just ignore and + // wait for the right dimensions + if (e.dimensions.columns === 10 || e.dimensions.rows === 5) { + disposables.push(window.onDidCloseTerminal(() => r())); + terminal.dispose(); + } + })); + terminal.show(); + }); }); - test('should change terminal name', (done) => { - disposables.push(window.onDidOpenTerminal(term => { - try { - equal(terminal, term); - equal(terminal.name, 'foo'); - } catch (e) { - done(e); - return; - } - disposables.push(window.onDidCloseTerminal(t => { - try { - equal(terminal, t); - equal(terminal.name, 'bar'); - } catch (e) { - done(e); - return; - } - done(); - })); - })); + test('should change terminal name', async () => { const changeNameEmitter = new EventEmitter(); const closeEmitter = new EventEmitter(); const pty: Pseudoterminal = { @@ -559,29 +537,22 @@ import { assertNoRpc } from '../utils'; }, close: () => { } }; - const terminal = window.createTerminal({ name: 'foo', pty }); + await new Promise(r => { + disposables.push(window.onDidOpenTerminal(t1 => { + if (t1 === created) { + disposables.push(window.onDidCloseTerminal(t2 => { + if (t2 === created) { + strictEqual(t1.name, 'bar'); + r(); + } + })); + } + })); + const created = window.createTerminal({ name: 'foo', pty }); + }); }); - test('exitStatus.code should be set to the exit code (undefined)', (done) => { - disposables.push(window.onDidOpenTerminal(term => { - try { - equal(terminal, term); - equal(terminal.exitStatus, undefined); - } catch (e) { - done(e); - return; - } - disposables.push(window.onDidCloseTerminal(t => { - try { - equal(terminal, t); - deepEqual(terminal.exitStatus, { code: undefined }); - } catch (e) { - done(e); - return; - } - done(); - })); - })); + test('exitStatus.code should be set to the exit code (undefined)', async () => { const writeEmitter = new EventEmitter(); const closeEmitter = new EventEmitter(); const pty: Pseudoterminal = { @@ -590,29 +561,23 @@ import { assertNoRpc } from '../utils'; open: () => closeEmitter.fire(undefined), close: () => { } }; - const terminal = window.createTerminal({ name: 'foo', pty }); + await new Promise(r => { + disposables.push(window.onDidOpenTerminal(t1 => { + if (t1 === created) { + strictEqual(created.exitStatus, undefined); + disposables.push(window.onDidCloseTerminal(t2 => { + if (t2 === created) { + deepStrictEqual(created.exitStatus, { code: undefined }); + r(); + } + })); + } + })); + const created = window.createTerminal({ name: 'foo', pty }); + }); }); - test('exitStatus.code should be set to the exit code (zero)', (done) => { - disposables.push(window.onDidOpenTerminal(term => { - try { - equal(terminal, term); - equal(terminal.exitStatus, undefined); - } catch (e) { - done(e); - return; - } - disposables.push(window.onDidCloseTerminal(t => { - try { - equal(terminal, t); - deepEqual(terminal.exitStatus, { code: 0 }); - } catch (e) { - done(e); - return; - } - done(); - })); - })); + test('exitStatus.code should be set to the exit code (zero)', async () => { const writeEmitter = new EventEmitter(); const closeEmitter = new EventEmitter(); const pty: Pseudoterminal = { @@ -621,29 +586,23 @@ import { assertNoRpc } from '../utils'; open: () => closeEmitter.fire(0), close: () => { } }; - const terminal = window.createTerminal({ name: 'foo', pty }); + await new Promise(r => { + disposables.push(window.onDidOpenTerminal(t1 => { + if (t1 === created) { + strictEqual(created.exitStatus, undefined); + disposables.push(window.onDidCloseTerminal(t2 => { + if (t2 === created) { + deepStrictEqual(created.exitStatus, { code: 0 }); + r(); + } + })); + } + })); + const created = window.createTerminal({ name: 'foo', pty }); + }); }); - test('exitStatus.code should be set to the exit code (non-zero)', (done) => { - disposables.push(window.onDidOpenTerminal(term => { - try { - equal(terminal, term); - equal(terminal.exitStatus, undefined); - } catch (e) { - done(e); - return; - } - disposables.push(window.onDidCloseTerminal(t => { - try { - equal(terminal, t); - deepEqual(terminal.exitStatus, { code: 22 }); - } catch (e) { - done(e); - return; - } - done(); - })); - })); + test('exitStatus.code should be set to the exit code (non-zero)', async () => { const writeEmitter = new EventEmitter(); const closeEmitter = new EventEmitter(); const pty: Pseudoterminal = { @@ -657,20 +616,23 @@ import { assertNoRpc } from '../utils'; }, close: () => { } }; - const terminal = window.createTerminal({ name: 'foo', pty }); + await new Promise(r => { + disposables.push(window.onDidOpenTerminal(t1 => { + if (t1 === created) { + strictEqual(created.exitStatus, undefined); + disposables.push(window.onDidCloseTerminal(t2 => { + if (t2 === created) { + deepStrictEqual(created.exitStatus, { code: 22 }); + r(); + } + })); + } + })); + const created = window.createTerminal({ name: 'foo', pty }); + }); }); - test('creationOptions should be set and readonly for ExtensionTerminalOptions terminals', (done) => { - disposables.push(window.onDidOpenTerminal(term => { - try { - equal(terminal, term); - } catch (e) { - done(e); - return; - } - terminal.dispose(); - disposables.push(window.onDidCloseTerminal(() => done())); - })); + test('creationOptions should be set and readonly for ExtensionTerminalOptions terminals', async () => { const writeEmitter = new EventEmitter(); const pty: Pseudoterminal = { onDidWrite: writeEmitter.event, @@ -678,16 +640,20 @@ import { assertNoRpc } from '../utils'; close: () => { } }; const options = { name: 'foo', pty }; - const terminal = window.createTerminal(options); - try { - equal(terminal.name, 'foo'); + await new Promise(r => { + disposables.push(window.onDidOpenTerminal(term => { + if (term === terminal) { + terminal.dispose(); + disposables.push(window.onDidCloseTerminal(() => r())); + } + })); + const terminal = window.createTerminal(options); + strictEqual(terminal.name, 'foo'); const terminalOptions = terminal.creationOptions as ExtensionTerminalOptions; - equal(terminalOptions.name, 'foo'); - equal(terminalOptions.pty, pty); + strictEqual(terminalOptions.name, 'foo'); + strictEqual(terminalOptions.pty, pty); throws(() => terminalOptions.name = 'bad', 'creationOptions should be readonly at runtime'); - } catch (e) { - done(e); - } + }); }); }); diff --git a/src/vs/workbench/api/common/extHostTerminalService.ts b/src/vs/workbench/api/common/extHostTerminalService.ts index 6eb760ba348..47452b0060b 100644 --- a/src/vs/workbench/api/common/extHostTerminalService.ts +++ b/src/vs/workbench/api/common/extHostTerminalService.ts @@ -275,15 +275,11 @@ export class ExtHostPseudoterminal implements ITerminalChildProcess { } input(data: string): void { - if (this._pty.handleInput) { - this._pty.handleInput(data); - } + this._pty.handleInput?.(data); } resize(cols: number, rows: number): void { - if (this._pty.setDimensions) { - this._pty.setDimensions({ columns: cols, rows }); - } + this._pty.setDimensions?.({ columns: cols, rows }); } async processBinary(data: string): Promise { @@ -314,28 +310,22 @@ export class ExtHostPseudoterminal implements ITerminalChildProcess { startSendingEvents(initialDimensions: ITerminalDimensionsDto | undefined): void { // Attach the listeners this._pty.onDidWrite(e => this._onProcessData.fire(e)); - if (this._pty.onDidClose) { - this._pty.onDidClose((e: number | void = undefined) => { - this._onProcessExit.fire(e === void 0 ? undefined : e); - }); - } - if (this._pty.onDidOverrideDimensions) { - this._pty.onDidOverrideDimensions(e => { - if (e) { - this._onDidChangeProperty.fire({ type: ProcessPropertyType.OverrideDimensions, value: { cols: e.columns, rows: e.rows } }); - } - }); - } - if (this._pty.onDidChangeName) { - this._pty.onDidChangeName(title => { - this._onDidChangeProperty.fire({ type: ProcessPropertyType.Title, value: title }); - }); - } + this._pty.onDidClose?.((e: number | void = undefined) => { + this._onProcessExit.fire(e === void 0 ? undefined : e); + }); + this._pty.onDidOverrideDimensions?.(e => { + if (e) { + this._onDidChangeProperty.fire({ type: ProcessPropertyType.OverrideDimensions, value: { cols: e.columns, rows: e.rows } }); + } + }); + this._pty.onDidChangeName?.(title => { + this._onDidChangeProperty.fire({ type: ProcessPropertyType.Title, value: title }); + }); this._pty.open(initialDimensions ? initialDimensions : undefined); - if (this._pty.setDimensions && initialDimensions) { - this._pty.setDimensions(initialDimensions); + if (initialDimensions) { + this._pty.setDimensions?.(initialDimensions); } this._onProcessReady.fire({ pid: -1, cwd: '', capabilities: this._capabilities }); @@ -586,7 +576,7 @@ export abstract class BaseExtHostTerminalService extends Disposable implements I protected _setupExtHostProcessListeners(id: number, p: ITerminalChildProcess): IDisposable { const disposables = new DisposableStore(); - disposables.add(p.onProcessReady((e: { pid: number, cwd: string }) => this._proxy.$sendProcessReady(id, e.pid, e.cwd))); + disposables.add(p.onProcessReady(e => this._proxy.$sendProcessReady(id, e.pid, e.cwd))); disposables.add(p.onDidChangeProperty(property => this._proxy.$sendProcessProperty(id, property))); // Buffer data events to reduce the amount of messages going to the renderer