diff --git a/src/vs/workbench/api/common/extHostTerminalService.ts b/src/vs/workbench/api/common/extHostTerminalService.ts index 01c4ece2795b326cd1ffa57b3b63ba28e9c805f5..d722f2b428ed2da34a572b04629560d1833d0af3 100644 --- a/src/vs/workbench/api/common/extHostTerminalService.ts +++ b/src/vs/workbench/api/common/extHostTerminalService.ts @@ -13,7 +13,7 @@ import { ITerminalChildProcess, ITerminalDimensions, EXT_HOST_CREATION_DELAY, IT import { timeout } from 'vs/base/common/async'; import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService'; import { TerminalDataBufferer } from 'vs/workbench/contrib/terminal/common/terminalDataBuffering'; -import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle'; +import { IDisposable, DisposableStore, Disposable } from 'vs/base/common/lifecycle'; import { Disposable as VSCodeDisposable, EnvironmentVariableMutatorType } from './extHostTypes'; import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { ISerializableEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariable'; @@ -22,7 +22,7 @@ import { NotSupportedError } from 'vs/base/common/errors'; import { serializeEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariableShared'; import { CancellationTokenSource } from 'vs/base/common/cancellation'; -export interface IExtHostTerminalService extends ExtHostTerminalServiceShape { +export interface IExtHostTerminalService extends ExtHostTerminalServiceShape, IDisposable { readonly _serviceBrand: undefined; @@ -306,14 +306,14 @@ interface ICachedLinkEntry { link: vscode.TerminalLink; } -export abstract class BaseExtHostTerminalService implements IExtHostTerminalService, ExtHostTerminalServiceShape { +export abstract class BaseExtHostTerminalService extends Disposable implements IExtHostTerminalService, ExtHostTerminalServiceShape { readonly _serviceBrand: undefined; protected _proxy: MainThreadTerminalServiceShape; protected _activeTerminal: ExtHostTerminal | undefined; protected _terminals: ExtHostTerminal[] = []; - protected _terminalProcesses: { [id: number]: ITerminalChildProcess } = {}; + protected _terminalProcesses: Map = new Map(); protected _terminalProcessDisposables: { [id: number]: IDisposable } = {}; protected _extensionTerminalAwaitingStart: { [id: number]: { initialDimensions: ITerminalDimensionsDto | undefined } | undefined } = {}; protected _getTerminalPromises: { [id: number]: Promise } = {}; @@ -342,6 +342,7 @@ export abstract class BaseExtHostTerminalService implements IExtHostTerminalServ supportsProcesses: boolean, @IExtHostRpcService extHostRpc: IExtHostRpcService ) { + super(); this._proxy = extHostRpc.getProxy(MainContext.MainThreadTerminalService); this._bufferer = new TerminalDataBufferer(this._proxy.$sendProcessData); this._onDidWriteTerminalData = new Emitter({ @@ -349,6 +350,13 @@ export abstract class BaseExtHostTerminalService implements IExtHostTerminalServ onLastListenerRemove: () => this._proxy.$stopSendingDataEvents() }); this._proxy.$registerProcessSupport(supportsProcesses); + this._register({ + dispose: () => { + for (const [_, terminalProcess] of this._terminalProcesses) { + terminalProcess.shutdown(true); + } + } + }); } public abstract createTerminal(name?: string, shellPath?: string, shellArgs?: string[] | string): vscode.Terminal; @@ -421,11 +429,9 @@ export abstract class BaseExtHostTerminalService implements IExtHostTerminalServ public async $acceptTerminalMaximumDimensions(id: number, cols: number, rows: number): Promise { await this._getTerminalByIdEventually(id); - if (this._terminalProcesses[id]) { - // Extension pty terminal only - when virtual process resize fires it means that the - // terminal's maximum dimensions changed - this._terminalProcesses[id]?.resize(cols, rows); - } + // Extension pty terminal only - when virtual process resize fires it means that the + // terminal's maximum dimensions changed + this._terminalProcesses.get(id)?.resize(cols, rows); } public async $acceptTerminalTitleChange(id: number, name: string): Promise { @@ -497,8 +503,9 @@ export abstract class BaseExtHostTerminalService implements IExtHostTerminalServ }); } - if (this._terminalProcesses[id]) { - (this._terminalProcesses[id] as ExtHostPseudoterminal).startSendingEvents(initialDimensions); + const terminalProcess = this._terminalProcesses.get(id); + if (terminalProcess) { + (terminalProcess as ExtHostPseudoterminal).startSendingEvents(initialDimensions); } else { // Defer startSendingEvents call to when _setupExtHostProcessListeners is called this._extensionTerminalAwaitingStart[id] = { initialDimensions }; @@ -520,7 +527,7 @@ export abstract class BaseExtHostTerminalService implements IExtHostTerminalServ if (p.onProcessOverrideDimensions) { disposables.add(p.onProcessOverrideDimensions(e => this._proxy.$sendOverrideDimensions(id, e))); } - this._terminalProcesses[id] = p; + this._terminalProcesses.set(id, p); const awaitingStart = this._extensionTerminalAwaitingStart[id]; if (awaitingStart && p instanceof ExtHostPseudoterminal) { @@ -532,12 +539,12 @@ export abstract class BaseExtHostTerminalService implements IExtHostTerminalServ } public $acceptProcessInput(id: number, data: string): void { - this._terminalProcesses[id]?.input(data); + this._terminalProcesses.get(id)?.input(data); } public $acceptProcessResize(id: number, cols: number, rows: number): void { try { - this._terminalProcesses[id]?.resize(cols, rows); + this._terminalProcesses.get(id)?.resize(cols, rows); } catch (error) { // We tried to write to a closed pipe / channel. if (error.code !== 'EPIPE' && error.code !== 'ERR_IPC_CHANNEL_CLOSED') { @@ -547,15 +554,15 @@ export abstract class BaseExtHostTerminalService implements IExtHostTerminalServ } public $acceptProcessShutdown(id: number, immediate: boolean): void { - this._terminalProcesses[id]?.shutdown(immediate); + this._terminalProcesses.get(id)?.shutdown(immediate); } public $acceptProcessRequestInitialCwd(id: number): void { - this._terminalProcesses[id]?.getInitialCwd().then(initialCwd => this._proxy.$sendProcessInitialCwd(id, initialCwd)); + this._terminalProcesses.get(id)?.getInitialCwd().then(initialCwd => this._proxy.$sendProcessInitialCwd(id, initialCwd)); } public $acceptProcessRequestCwd(id: number): void { - this._terminalProcesses[id]?.getCwd().then(cwd => this._proxy.$sendProcessCwd(id, cwd)); + this._terminalProcesses.get(id)?.getCwd().then(cwd => this._proxy.$sendProcessCwd(id, cwd)); } public $acceptProcessRequestLatency(id: number): number { @@ -648,7 +655,7 @@ export abstract class BaseExtHostTerminalService implements IExtHostTerminalServ this._bufferer.stopBuffering(id); // Remove process reference - delete this._terminalProcesses[id]; + this._terminalProcesses.delete(id); delete this._extensionTerminalAwaitingStart[id]; // Clean up process disposables diff --git a/src/vs/workbench/services/extensions/common/extensionHostMain.ts b/src/vs/workbench/services/extensions/common/extensionHostMain.ts index 552e08e19171fedf51d09bffc481b5bb77cf5120..e6b9d6fcb17460a191e363f74b18f00b74fe45e4 100644 --- a/src/vs/workbench/services/extensions/common/extensionHostMain.ts +++ b/src/vs/workbench/services/extensions/common/extensionHostMain.ts @@ -21,6 +21,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { IExtHostRpcService, ExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService'; import { IURITransformerService, URITransformerService } from 'vs/workbench/api/common/extHostUriTransformerService'; import { IExtHostExtensionService, IHostUtils } from 'vs/workbench/api/common/extHostExtensionService'; +import { IExtHostTerminalService } from 'vs/workbench/api/common/extHostTerminalService'; export interface IExitFn { (code?: number): any; @@ -61,6 +62,9 @@ export class ExtensionHostMain { // todo@joh // ugly self - inject + const terminalService = instaService.invokeFunction(accessor => accessor.get(IExtHostTerminalService)); + this._disposables.add(terminalService); + const logService = instaService.invokeFunction(accessor => accessor.get(ILogService)); this._disposables.add(logService);