diff --git a/src/vs/platform/terminal/common/terminal.ts b/src/vs/platform/terminal/common/terminal.ts index 69ee9e1ce1792..eaa3a72697ec9 100644 --- a/src/vs/platform/terminal/common/terminal.ts +++ b/src/vs/platform/terminal/common/terminal.ts @@ -96,6 +96,7 @@ export interface IOffProcessTerminalService { listProcesses(reduceGraceTime?: boolean): Promise; setTerminalLayoutInfo(layoutInfo?: ITerminalsLayoutInfoById): Promise; getTerminalLayoutInfo(): Promise; + reduceConnectionGraceTime(): void; } export const ILocalTerminalService = createDecorator('localTerminalService'); @@ -142,10 +143,8 @@ export interface IPtyService { /** * Lists all orphaned processes, ie. those without a connected frontend. - * @param reduceGraceTime Whether to reduce the reconnection grace time for all orphaned - * terminals. */ - listProcesses(reduceGraceTime: boolean): Promise; + listProcesses(): Promise; start(id: number): Promise; shutdown(id: number, immediate: boolean): Promise; @@ -161,6 +160,7 @@ export interface IPtyService { setTerminalLayoutInfo(args: ISetTerminalLayoutInfoArgs): Promise; getTerminalLayoutInfo(args: IGetTerminalLayoutInfoArgs): Promise; + reduceConnectionGraceTime(): void; } export enum HeartbeatConstants { diff --git a/src/vs/platform/terminal/node/ptyHostService.ts b/src/vs/platform/terminal/node/ptyHostService.ts index 13b0bb8eee387..05aa00e1ef910 100644 --- a/src/vs/platform/terminal/node/ptyHostService.ts +++ b/src/vs/platform/terminal/node/ptyHostService.ts @@ -155,10 +155,12 @@ export class PtyHostService extends Disposable implements IPtyService { detachFromProcess(id: number): Promise { return this._proxy.detachFromProcess(id); } - listProcesses(reduceGraceTime: boolean): Promise { - return this._proxy.listProcesses(reduceGraceTime); + listProcesses(): Promise { + return this._proxy.listProcesses(); + } + reduceConnectionGraceTime(): void { + return this._proxy.reduceConnectionGraceTime(); } - start(id: number): Promise { return this._proxy.start(id); } diff --git a/src/vs/platform/terminal/node/ptyService.ts b/src/vs/platform/terminal/node/ptyService.ts index dd1237fe0ce7e..76e20bcfab27c 100644 --- a/src/vs/platform/terminal/node/ptyService.ts +++ b/src/vs/platform/terminal/node/ptyService.ts @@ -116,13 +116,13 @@ export class PtyService extends Disposable implements IPtyService { this._throwIfNoPty(id).detach(); } - async listProcesses(reduceGraceTime: boolean): Promise { - if (reduceGraceTime) { - for (const pty of this._ptys.values()) { - pty.reduceGraceTime(); - } + reduceConnectionGraceTime(): void { + for (const pty of this._ptys.values()) { + pty.reduceGraceTime(); } + } + async listProcesses(): Promise { const persistentProcesses = Array.from(this._ptys.entries()).filter(([_, pty]) => pty.shouldPersistTerminal); this._logService.info(`Listing ${persistentProcesses.length} persistent terminals, ${this._ptys.size} total terminals`); diff --git a/src/vs/workbench/contrib/terminal/browser/remoteTerminalService.ts b/src/vs/workbench/contrib/terminal/browser/remoteTerminalService.ts index a8b60d6a36f20..94ae8f9158b9a 100644 --- a/src/vs/workbench/contrib/terminal/browser/remoteTerminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/remoteTerminalService.ts @@ -169,8 +169,8 @@ export class RemoteTerminalService extends Disposable implements IRemoteTerminal return undefined; } - public async listProcesses(reduceGraceTime: boolean = false): Promise { - const terms = this._remoteTerminalChannel ? await this._remoteTerminalChannel.listProcesses(reduceGraceTime) : []; + public async listProcesses(): Promise { + const terms = this._remoteTerminalChannel ? await this._remoteTerminalChannel.listProcesses() : []; return terms.map(termDto => { return { id: termDto.id, @@ -191,8 +191,14 @@ export class RemoteTerminalService extends Disposable implements IRemoteTerminal return this._remoteTerminalChannel.setTerminalLayoutInfo(layout); } + public reduceConnectionGraceTime(): void { + if (!this._remoteTerminalChannel) { + throw new Error('Cannot reduce grace time when there is no remote'); + } + this._remoteTerminalChannel.reduceConnectionGraceTime(); + } + public async getTerminalLayoutInfo(): Promise { - await this._remoteTerminalChannel?.listProcesses(true); if (!this._remoteTerminalChannel) { throw new Error(`Cannot call getActiveInstanceId when there is no remote`); } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts index e00f4ff1ebbb3..9edcb33288f18 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts @@ -683,9 +683,13 @@ export function registerTerminalActions() { const labelService = accessor.get(ILabelService); const remoteAgentService = accessor.get(IRemoteAgentService); const notificationService = accessor.get(INotificationService); - const offProcTerminalService = remoteAgentService.getConnection() ? accessor.get(IRemoteTerminalService) : accessor.get(ILocalTerminalService); - const remoteTerms = await offProcTerminalService.listProcesses(); - const unattachedTerms = remoteTerms.filter(term => !terminalService.isAttachedToTerminal(term)); + let offProcTerminalService = remoteAgentService.getConnection() ? accessor.get(IRemoteTerminalService) : accessor.get(ILocalTerminalService); + + const terms = await offProcTerminalService.listProcesses(); + + offProcTerminalService.reduceConnectionGraceTime(); + + const unattachedTerms = terms.filter(term => !terminalService.isAttachedToTerminal(term)); const items = unattachedTerms.map(term => { const cwdLabel = labelService.getUriLabel(URI.file(term.cwd)); return { diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index f172b2cde497b..6e6c2f4ac92f1 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -189,6 +189,7 @@ export class TerminalService implements ITerminalService { private async _reconnectToRemoteTerminals(): Promise { // Reattach to all remote terminals const layoutInfo = await this._remoteTerminalService.getTerminalLayoutInfo(); + this._remoteTerminalService.reduceConnectionGraceTime(); const reconnectCounter = this._recreateTerminalTabs(layoutInfo); /* __GDPR__ "terminalReconnection" : { @@ -210,6 +211,7 @@ export class TerminalService implements ITerminalService { } // Reattach to all local terminals const layoutInfo = await this._localTerminalService.getTerminalLayoutInfo(); + this._localTerminalService.reduceConnectionGraceTime(); if (layoutInfo && layoutInfo.tabs.length > 0) { this._recreateTerminalTabs(layoutInfo); } diff --git a/src/vs/workbench/contrib/terminal/common/remoteTerminalChannel.ts b/src/vs/workbench/contrib/terminal/common/remoteTerminalChannel.ts index 8a587682a1978..321518c494044 100644 --- a/src/vs/workbench/contrib/terminal/common/remoteTerminalChannel.ts +++ b/src/vs/workbench/contrib/terminal/common/remoteTerminalChannel.ts @@ -235,11 +235,12 @@ export class RemoteTerminalChannelClient { public attachToProcess(id: number): Promise { return this._channel.call('$attachToProcess', [id]); } - - public listProcesses(reduceGraceTime: boolean): Promise { - return this._channel.call('$listProcesses', [reduceGraceTime]); + public listProcesses(): Promise { + return this._channel.call('$listProcesses'); + } + public reduceConnectionGraceTime(): Promise { + return this._channel.call('$reduceConnectionGraceTime'); } - public start(id: number): Promise { return this._channel.call('$start', [id]); } @@ -264,7 +265,6 @@ export class RemoteTerminalChannelClient { public orphanQuestionReply(id: number): Promise { return this._channel.call('$orphanQuestionReply', [id]); } - public sendCommandResult(reqId: number, isError: boolean, payload: any): Promise { return this._channel.call('$sendCommandResult', [reqId, isError, payload]); } diff --git a/src/vs/workbench/contrib/terminal/electron-sandbox/localTerminalService.ts b/src/vs/workbench/contrib/terminal/electron-sandbox/localTerminalService.ts index bdd6688c6d223..68ba3153571ea 100644 --- a/src/vs/workbench/contrib/terminal/electron-sandbox/localTerminalService.ts +++ b/src/vs/workbench/contrib/terminal/electron-sandbox/localTerminalService.ts @@ -116,8 +116,12 @@ export class LocalTerminalService extends Disposable implements ILocalTerminalSe return undefined; } - public async listProcesses(reduceGraceTime: boolean): Promise { - return this._localPtyService.listProcesses(reduceGraceTime); + public async listProcesses(): Promise { + return this._localPtyService.listProcesses(); + } + + public reduceConnectionGraceTime(): void { + this._localPtyService.reduceConnectionGraceTime(); } public async setTerminalLayoutInfo(layoutInfo?: ITerminalsLayoutInfoById): Promise { diff --git a/src/vs/workbench/test/browser/workbenchTestServices.ts b/src/vs/workbench/test/browser/workbenchTestServices.ts index b8a48bea90d1f..63edbb2dc5283 100644 --- a/src/vs/workbench/test/browser/workbenchTestServices.ts +++ b/src/vs/workbench/test/browser/workbenchTestServices.ts @@ -1507,6 +1507,7 @@ export class TestTerminalInstanceService implements ITerminalInstanceService { } export class TestLocalTerminalService implements ILocalTerminalService { + declare readonly _serviceBrand: undefined; onPtyHostExit = Event.None; @@ -1518,12 +1519,11 @@ export class TestLocalTerminalService implements ILocalTerminalService { return new TestTerminalChildProcess(shouldPersist); } async attachToProcess(id: number): Promise { throw new Error('Method not implemented.'); } - async listProcesses(reduceGraceTime: boolean): Promise { throw new Error('Method not implemented.'); } + async listProcesses(): Promise { throw new Error('Method not implemented.'); } async setTerminalLayoutInfo(argsOrLayout?: ISetTerminalLayoutInfoArgs | ITerminalsLayoutInfoById) { throw new Error('Method not implemented.'); } async getTerminalLayoutInfo(): Promise { throw new Error('Method not implemented.'); } - processBinary(id: number, data: string): void { - throw new Error('Method not implemented.'); - } + reduceConnectionGraceTime(): void { throw new Error('Method not implemented.'); } + processBinary(id: number, data: string): void { throw new Error('Method not implemented.'); } } class TestTerminalChildProcess implements ITerminalChildProcess {