Change:
Also repro's in stable
unsure when this started happening. I don't see any open issues about it, which makes me think this is expected in WSL?
was last working in stable 1.59
and because it was broken in stable 1.60, we can narrow it down - the breaking change happened in August
looks like perhaps a race condition - get layout info is called w the correct workpsaceId, but then set layout info is called so might be wiping out the stored info before the reconnect can occur.
I open a terminal in a Remote-SSH window, reload the window, it is not reconnected
still doesn't work for WSL. based on my investigation, the pty service gets re-created when the window is reloaded, thus losing the and maps
when connected to localhost via ssh, reloading does persist the terminals but I thought this would still be using the ... !
Yep !
Also working for me in codespaces https://user-
It does work in WSL. interestingly, other state isn't persisted that should be though (see the layout change) !
this works on all remote platforms based on my testing. i saw a few times reloading WSL didn't work, but now cannot reproduce
Oh cool, I thought the situation was much worse. I'll reopen to verify on my side since we definitely want to make sure this is working everywhere
All seems to work
verified

Discussion:
import { createRandomIPCHandle } from 'vs/base/parts/ipc/node/ipc.net'; import { ILogService } from 'vs/platform/log/common/log'; import { RemoteAgentConnectionContext } from 'vs/platform/remote/common/remoteAgentEnvironment'; <del> import { IPtyService, IShellLaunchConfig, ITerminalProfile, ITerminalsLayoutInfo } from 'vs/platform/terminal/common/terminal'; </del> <ins> import { IPtyService, IShellLaunchConfig, ITerminalProfile } from 'vs/platform/terminal/common/terminal'; </ins> import { IGetTerminalLayoutInfoArgs, ISetTerminalLayoutInfoArgs } from 'vs/platform/terminal/common/terminalProcess'; import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { createRemoteURITransformer } from 'vs/server/remoteUriTransformer';

case '$getProfiles': return this._getProfiles.apply(this, args); case '$getEnvironment': return this._getEnvironment(); case '$getWslPath': return this._getWslPath(args[0]); <del> case '$getTerminalLayoutInfo': return this._getTerminalLayoutInfo(<IGetTerminalLayoutInfoArgs>args); case '$setTerminalLayoutInfo': return this._setTerminalLayoutInfo(<ISetTerminalLayoutInfoArgs>args); </del> <ins> case '$getTerminalLayoutInfo': return this._ptyService.getTerminalLayoutInfo(<IGetTerminalLayoutInfoArgs>args); case '$setTerminalLayoutInfo': return this._ptyService.setTerminalLayoutInfo(<ISetTerminalLayoutInfoArgs>args); </ins> case '$serializeTerminalState': return this._ptyService.serializeTerminalState.apply(this._ptyService, args); case '$reviveTerminalProcesses': return this._ptyService.reviveTerminalProcesses.apply(this._ptyService, args); case '$setUnicodeVersion': return this._ptyService.setUnicodeVersion.apply(this._ptyService, args);

return this._ptyService.getWslPath(original); } <del> private _setTerminalLayoutInfo(args: ISetTerminalLayoutInfoArgs): void { this._ptyService.setTerminalLayoutInfo(args); } private async _getTerminalLayoutInfo(args: IGetTerminalLayoutInfoArgs): Promise<ITerminalsLayoutInfo | undefined> { return this._ptyService.getTerminalLayoutInfo(args); } </del> private _reduceConnectionGraceTime(): Promise<void> { return this._ptyService.reduceConnectionGraceTime();

return this._remoteTerminalChannel?.getWslPath(original) || original; } <del> setTerminalLayoutInfo(layout: ITerminalsLayoutInfoById): Promise<void> { </del> <ins> async setTerminalLayoutInfo(layout?: ITerminalsLayoutInfoById): Promise<void> { </ins> if (!this._remoteTerminalChannel) { throw new Error(`Cannot call setActiveInstanceId when there is no remote`); }

private _configHelper: TerminalConfigHelper; private _remoteTerminalsInitPromise: Promise<void> | undefined; private _localTerminalsInitPromise: Promise<void> | undefined; <del> private _connectionState: TerminalConnectionState; </del> <ins> private _connectionState: TerminalConnectionState = TerminalConnectionState.Connecting; </ins> private _nativeDelegate?: ITerminalServiceNativeDelegate; private _shutdownWindowCount?: number;

} }); <del> const enableTerminalReconnection = this.configHelper.config.enablePersistentSessions; // Connect to the extension host if it's there, set the connection state to connected when // it's done. This should happen even when there is no extension host. this._connectionState = TerminalConnectionState.Connecting; const isPersistentRemote = !!this._environmentService.remoteAuthority && enableTerminalReconnection; if (isPersistentRemote) { this._remoteTerminalsInitPromise = this._reconnectToRemoteTerminals(); } else if (enableTerminalReconnection) { this._localTerminalsInitPromise = this._reconnectToLocalTerminals(); } else { this._connectionState = TerminalConnectionState.Connected; } </del> // Create async as the class depends on `this` timeout(0).then(() => this._instantiationService.createInstance(TerminalEditorStyle, document.head)); }

handleNewRegisteredBackend(backend: ITerminalBackend) { if (backend.remoteAuthority === this._environmentService.remoteAuthority) { this._primaryBackend = backend; <ins> const enableTerminalReconnection = this.configHelper.config.enablePersistentSessions; // Connect to the extension host if it's there, set the connection state to connected when // it's done. This should happen even when there is no extension host. this._connectionState = TerminalConnectionState.Connecting; const isPersistentRemote = !!this._environmentService.remoteAuthority && enableTerminalReconnection; if (isPersistentRemote) { this._remoteTerminalsInitPromise = this._reconnectToRemoteTerminals(); } else if (enableTerminalReconnection) { this._localTerminalsInitPromise = this._reconnectToLocalTerminals(); } else { this._connectionState = TerminalConnectionState.Connected; } </ins> backend.onDidRequestDetach(async (e) => { const instanceToDetach = this.getInstanceFromResource(getTerminalUri(e.workspaceId, e.instanceId)); if (instanceToDetach) {

return this._channel.call('$getWslPath', [original]); } <del> setTerminalLayoutInfo(layout: ITerminalsLayoutInfoById): Promise<void> { </del> <ins> setTerminalLayoutInfo(layout?: ITerminalsLayoutInfoById): Promise<void> { </ins> const workspace = this._workspaceContextService.getWorkspace(); const args: ISetTerminalLayoutInfoArgs = { workspaceId: workspace.id, <del> tabs: layout.tabs </del> <ins> tabs: layout ? layout.tabs : [] </ins> }; return this._channel.call<void>('$setTerminalLayoutInfo', args); }