diff --git a/src/vs/platform/terminal/common/terminal.ts b/src/vs/platform/terminal/common/terminal.ts index 673356130d9..0a477ac20d0 100644 --- a/src/vs/platform/terminal/common/terminal.ts +++ b/src/vs/platform/terminal/common/terminal.ts @@ -680,6 +680,7 @@ export interface ITerminalChildProcess { onProcessData: Event; onProcessReady: Event; + onProcessReplayComplete?: Event; onDidChangeProperty: Event>; onProcessExit: Event; onRestoreCommands?: Event; diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index 1972f4f3422..43137f9dd62 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -536,6 +536,7 @@ export interface ITerminalInstance { onDisposed: Event; onProcessIdReady: Event; + onProcessReplayComplete: Event; onRequestExtHostProcess: Event; onDimensionsChanged: Event; onMaximumDimensionsChanged: Event; diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index 3f906f9a9f8..3958743aa77 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -288,6 +288,8 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { readonly onDisposed = this._onDisposed.event; private readonly _onProcessIdReady = this._register(new Emitter()); readonly onProcessIdReady = this._onProcessIdReady.event; + private readonly _onProcessReplayComplete = this._register(new Emitter()); + readonly onProcessReplayComplete = this._onProcessReplayComplete.event; private readonly _onTitleChanged = this._register(new Emitter()); readonly onTitleChanged = this._onTitleChanged.event; private readonly _onIconChanged = this._register(new Emitter<{ instance: ITerminalInstance; userInitiated: boolean }>()); @@ -1395,6 +1397,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { this._initialDataEvents?.push(ev.data); this._onData.fire(ev.data); }); + processManager.onProcessReplayComplete(() => this._onProcessReplayComplete.fire()); processManager.onEnvironmentVariableInfoChanged(e => this._onEnvironmentVariableInfoChanged(e)); processManager.onPtyDisconnect(() => { if (this.xterm) { diff --git a/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts b/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts index 274c159b5b8..16e37b75b15 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts @@ -108,6 +108,8 @@ export class TerminalProcessManager extends Disposable implements ITerminalProce readonly onBeforeProcessData = this._onBeforeProcessData.event; private readonly _onProcessData = this._register(new Emitter()); readonly onProcessData = this._onProcessData.event; + private readonly _onProcessReplayComplete = this._register(new Emitter()); + readonly onProcessReplayComplete = this._onProcessReplayComplete.event; private readonly _onDidChangeProperty = this._register(new Emitter>()); readonly onDidChangeProperty = this._onDidChangeProperty.event; private readonly _onEnvironmentVariableInfoChange = this._register(new Emitter()); @@ -375,10 +377,11 @@ export class TerminalProcessManager extends Disposable implements ITerminalProce this._onDidChangeProperty.fire({ type, value }); }) ]; + if (newProcess.onProcessReplayComplete) { + this._processListeners.push(newProcess.onProcessReplayComplete(() => this._onProcessReplayComplete.fire())); + } if (newProcess.onRestoreCommands) { - this._processListeners.push(newProcess.onRestoreCommands(e => { - this._onRestoreCommands.fire(e); - })); + this._processListeners.push(newProcess.onRestoreCommands(e => this._onRestoreCommands.fire(e))); } setTimeout(() => { if (this.processState === ProcessState.Launching) { diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index 047cacfb5c2..3c11906dfde 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -95,6 +95,8 @@ export class TerminalService implements ITerminalService { return this._detachedXterms; } + private _reconnectedTerminalGroups: Promise | undefined; + private _reconnectedTerminals: Map = new Map(); getReconnectedTerminals(reconnectionOwner: string): ITerminalInstance[] | undefined { return this._reconnectedTerminals.get(reconnectionOwner); @@ -292,6 +294,13 @@ export class TerminalService implements ITerminalService { reconnectedPromise.then(async () => { this._setConnected(); mark('code/terminal/didReconnect'); + mark('code/terminal/willReplay'); + const instances = await this._reconnectedTerminalGroups?.then(groups => groups.map(e => e.terminalInstances).flat()) ?? []; + await Promise.all(instances.map(e => new Promise(r => Event.once(e.onProcessReplayComplete)(() => { + mark(`code/terminal/replay/${e.shellLaunchConfig.attachPersistentProcess?.id}`); + r(); + })))); + mark('code/terminal/didReplay'); for (const backend of this._terminalInstanceService.getRegisteredBackends()) { mark('code/terminal/willGetPerformanceMarks'); this._timerService.setPerformanceMarks(backend.remoteAuthority === undefined ? 'localPtyHost' : 'remotePtyHost', await backend.getPerformanceMarks()); @@ -450,7 +459,7 @@ export class TerminalService implements ITerminalService { mark('code/terminal/didGetTerminalLayoutInfo'); if (layoutInfo && layoutInfo.tabs.length > 0) { mark('code/terminal/willRecreateTerminalGroups'); - this._restoredGroupCount = await this._recreateTerminalGroups(layoutInfo); + this._reconnectedTerminalGroups = this._recreateTerminalGroups(layoutInfo); mark('code/terminal/didRecreateTerminalGroups'); } // now that terminals have been restored, @@ -458,17 +467,17 @@ export class TerminalService implements ITerminalService { this._attachProcessLayoutListeners(); } - private async _recreateTerminalGroups(layoutInfo?: ITerminalsLayoutInfo): Promise { + private _recreateTerminalGroups(layoutInfo?: ITerminalsLayoutInfo): Promise { + const groupPromises: Promise[] = []; let reconnectCounter = 0; let activeGroup: Promise | undefined; if (layoutInfo) { - const tabPromises: Promise[] = []; for (const tabLayout of layoutInfo.tabs) { const terminalLayouts = tabLayout.terminals.filter(t => t.terminal && t.terminal.isOrphan); if (terminalLayouts.length) { reconnectCounter += terminalLayouts.length; const promise = this._recreateTerminalGroup(tabLayout, terminalLayouts); - tabPromises.push(promise); + groupPromises.push(promise); if (tabLayout.isActive) { activeGroup = promise; } @@ -482,7 +491,7 @@ export class TerminalService implements ITerminalService { activeGroup?.then(group => this._terminalGroupService.activeGroup = group); } } - return reconnectCounter; + return Promise.all(groupPromises).then(result => result.filter(e => !!e) as ITerminalGroup[]); } private async _recreateTerminalGroup(tabLayout: IRawTerminalTabLayoutInfo, terminalLayouts: IRawTerminalInstanceLayoutInfo[]): Promise { @@ -502,7 +511,6 @@ export class TerminalService implements ITerminalService { }); group = lastInstance.then(instance => this._terminalGroupService.getGroupForInstance(instance)); } else { - // TODO: Make parentInstance a promise? // add split terminals to this group lastInstance = this.createTerminal({ config: { attachPersistentProcess }, diff --git a/src/vs/workbench/contrib/terminal/common/terminal.ts b/src/vs/workbench/contrib/terminal/common/terminal.ts index f5a5970f1c1..53548188003 100644 --- a/src/vs/workbench/contrib/terminal/common/terminal.ts +++ b/src/vs/workbench/contrib/terminal/common/terminal.ts @@ -280,6 +280,7 @@ export interface ITerminalProcessManager extends IDisposable { readonly onProcessReady: Event; readonly onBeforeProcessData: Event; readonly onProcessData: Event; + readonly onProcessReplayComplete: Event; readonly onEnvironmentVariableInfoChanged: Event; readonly onDidChangeProperty: Event>; readonly onProcessExit: Event; diff --git a/src/vs/workbench/contrib/terminal/electron-sandbox/localPty.ts b/src/vs/workbench/contrib/terminal/electron-sandbox/localPty.ts index 7bdd1cd26a1..566f77bc792 100644 --- a/src/vs/workbench/contrib/terminal/electron-sandbox/localPty.ts +++ b/src/vs/workbench/contrib/terminal/electron-sandbox/localPty.ts @@ -32,8 +32,8 @@ export class LocalPty extends Disposable implements ITerminalChildProcess { private readonly _onProcessData = this._register(new Emitter()); readonly onProcessData = this._onProcessData.event; - private readonly _onProcessReplay = this._register(new Emitter()); - readonly onProcessReplay = this._onProcessReplay.event; + private readonly _onProcessReplayComplete = this._register(new Emitter()); + readonly onProcessReplayComplete = this._onProcessReplayComplete.event; private readonly _onProcessReady = this._register(new Emitter()); readonly onProcessReady = this._onProcessReady.event; private readonly _onDidChangeProperty = this._register(new Emitter>()); @@ -162,6 +162,8 @@ export class LocalPty extends Disposable implements ITerminalChildProcess { // remove size override this._onDidChangeProperty.fire({ type: ProcessPropertyType.OverrideDimensions, value: undefined }); + + this._onProcessReplayComplete.fire(); } handleOrphanQuestion() {