From 86fe048df9ef2a70de85bb3265cdc7955178ea04 Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Fri, 22 Oct 2021 14:08:44 -0500 Subject: [PATCH] migrate process properties to use generic onDidChangeProperty (#135610) --- src/vs/platform/terminal/common/terminal.ts | 30 +++---- .../platform/terminal/node/ptyHostService.ts | 20 +---- src/vs/platform/terminal/node/ptyService.ts | 55 ++++--------- .../platform/terminal/node/terminalProcess.ts | 61 ++++++++------- src/vs/server/remoteTerminalChannel.ts | 14 ++-- .../api/browser/mainThreadTerminalService.ts | 22 ++---- .../workbench/api/common/extHost.protocol.ts | 9 +-- .../api/common/extHostTerminalService.ts | 30 +++---- .../contrib/terminal/browser/remotePty.ts | 67 ++++++---------- .../terminal/browser/remoteTerminalService.ts | 24 +++--- .../terminal/browser/terminalInstance.ts | 78 +++++++++++-------- .../browser/terminalProcessExtHostProxy.ts | 37 +++++---- .../browser/terminalProcessManager.ts | 37 +++------ .../terminal/common/remoteTerminalChannel.ts | 17 +--- .../contrib/terminal/common/terminal.ts | 13 +--- .../terminal/electron-sandbox/localPty.ts | 64 ++++++--------- .../electron-sandbox/localTerminalService.ts | 17 ++-- .../browser/testingOutputTerminalService.ts | 13 ++-- 18 files changed, 243 insertions(+), 365 deletions(-) diff --git a/src/vs/platform/terminal/common/terminal.ts b/src/vs/platform/terminal/common/terminal.ts index 833f556f807..f88b26a669c 100644 --- a/src/vs/platform/terminal/common/terminal.ts +++ b/src/vs/platform/terminal/common/terminal.ts @@ -181,7 +181,13 @@ export const IPtyService = createDecorator('ptyService'); export const enum ProcessPropertyType { Cwd = 'cwd', InitialCwd = 'initialCwd', - FixedDimensions = 'fixedDimensions' + FixedDimensions = 'fixedDimensions', + Title = 'title', + ShellType = 'shellType', + HasChildProcesses = 'hasChildProcesses', + ResolvedShellLaunchConfig = 'resolvedShellLaunchConfig', + OverrideDimensions = 'overrideDimensions', + Exit = 'exit' } export interface IProcessProperty { @@ -192,7 +198,13 @@ export interface IProcessProperty { export interface IProcessPropertyMap { [ProcessPropertyType.Cwd]: string, [ProcessPropertyType.InitialCwd]: string, - [ProcessPropertyType.FixedDimensions]: IFixedTerminalDimensions + [ProcessPropertyType.FixedDimensions]: IFixedTerminalDimensions, + [ProcessPropertyType.Title]: string + [ProcessPropertyType.ShellType]: TerminalShellType | undefined, + [ProcessPropertyType.HasChildProcesses]: boolean, + [ProcessPropertyType.ResolvedShellLaunchConfig]: IShellLaunchConfig, + [ProcessPropertyType.OverrideDimensions]: ITerminalDimensionsOverride | undefined, + [ProcessPropertyType.Exit]: number | undefined } export interface IFixedTerminalDimensions { @@ -218,16 +230,10 @@ export interface IPtyService { readonly onPtyHostRequestResolveVariables?: Event; readonly onProcessData: Event<{ id: number, event: IProcessDataEvent | string }>; - readonly onProcessExit: Event<{ id: number, event: number | undefined }>; - readonly onProcessReady: Event<{ id: number, event: { pid: number, cwd: string, capabilities: ProcessCapability[] } }>; - readonly onProcessTitleChanged: Event<{ id: number, event: string }>; - readonly onProcessShellTypeChanged: Event<{ id: number, event: TerminalShellType }>; - readonly onProcessOverrideDimensions: Event<{ id: number, event: ITerminalDimensionsOverride | undefined }>; - readonly onProcessResolvedShellLaunchConfig: Event<{ id: number, event: IShellLaunchConfig }>; + readonly onProcessReady: Event<{ id: number, event: IProcessReadyEvent }>; readonly onProcessReplay: Event<{ id: number, event: IPtyHostProcessReplayEvent }>; readonly onProcessOrphanQuestion: Event<{ id: number }>; readonly onDidRequestDetach: Event<{ requestId: number, workspaceId: string, instanceId: number }>; - readonly onProcessDidChangeHasChildProcesses: Event<{ id: number, event: boolean }>; readonly onDidChangeProperty: Event<{ id: number, property: IProcessProperty }> restartPtyHost?(): Promise; @@ -527,13 +533,7 @@ export interface ITerminalChildProcess { capabilities: ProcessCapability[]; onProcessData: Event; - onProcessExit: Event; onProcessReady: Event; - onProcessTitleChanged: Event; - onProcessShellTypeChanged: Event; - onProcessOverrideDimensions?: Event; - onProcessResolvedShellLaunchConfig?: Event; - onDidChangeHasChildProcesses?: Event; onDidChangeProperty: Event>; /** diff --git a/src/vs/platform/terminal/node/ptyHostService.ts b/src/vs/platform/terminal/node/ptyHostService.ts index e13e7730b6d..4d9a16fcbf7 100644 --- a/src/vs/platform/terminal/node/ptyHostService.ts +++ b/src/vs/platform/terminal/node/ptyHostService.ts @@ -17,7 +17,7 @@ import { ILogService } from 'vs/platform/log/common/log'; import { LogLevelChannelClient } from 'vs/platform/log/common/logIpc'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { RequestStore } from 'vs/platform/terminal/common/requestStore'; -import { HeartbeatConstants, IHeartbeatService, IProcessDataEvent, IPtyService, IReconnectConstants, IRequestResolveVariablesEvent, IShellLaunchConfig, ITerminalDimensionsOverride, ITerminalLaunchError, ITerminalProfile, ITerminalsLayoutInfo, TerminalIcon, TerminalIpcChannels, IProcessProperty, TerminalShellType, TitleEventSource, ProcessPropertyType, ProcessCapability, IProcessPropertyMap, TerminalSettingId } from 'vs/platform/terminal/common/terminal'; +import { HeartbeatConstants, IHeartbeatService, IProcessDataEvent, IPtyService, IReconnectConstants, IRequestResolveVariablesEvent, IShellLaunchConfig, ITerminalLaunchError, ITerminalProfile, ITerminalsLayoutInfo, TerminalIcon, TerminalIpcChannels, IProcessProperty, TitleEventSource, ProcessPropertyType, ProcessCapability, IProcessPropertyMap, TerminalSettingId } from 'vs/platform/terminal/common/terminal'; import { registerTerminalPlatformConfiguration } from 'vs/platform/terminal/common/terminalPlatformConfiguration'; import { IGetTerminalLayoutInfoArgs, IProcessDetails, IPtyHostProcessReplayEvent, ISetTerminalLayoutInfoArgs } from 'vs/platform/terminal/common/terminalProcess'; import { detectAvailableProfiles } from 'vs/platform/terminal/node/terminalProfiles'; @@ -64,26 +64,14 @@ export class PtyHostService extends Disposable implements IPtyService { private readonly _onProcessData = this._register(new Emitter<{ id: number, event: IProcessDataEvent | string }>()); readonly onProcessData = this._onProcessData.event; - private readonly _onProcessExit = this._register(new Emitter<{ id: number, event: number | undefined }>()); - readonly onProcessExit = this._onProcessExit.event; private readonly _onProcessReady = this._register(new Emitter<{ id: number, event: { pid: number, cwd: string, capabilities: ProcessCapability[] } }>()); readonly onProcessReady = this._onProcessReady.event; private readonly _onProcessReplay = this._register(new Emitter<{ id: number, event: IPtyHostProcessReplayEvent }>()); readonly onProcessReplay = this._onProcessReplay.event; - private readonly _onProcessTitleChanged = this._register(new Emitter<{ id: number, event: string }>()); - readonly onProcessTitleChanged = this._onProcessTitleChanged.event; - private readonly _onProcessShellTypeChanged = this._register(new Emitter<{ id: number, event: TerminalShellType }>()); - readonly onProcessShellTypeChanged = this._onProcessShellTypeChanged.event; - private readonly _onProcessOverrideDimensions = this._register(new Emitter<{ id: number, event: ITerminalDimensionsOverride | undefined }>()); - readonly onProcessOverrideDimensions = this._onProcessOverrideDimensions.event; - private readonly _onProcessResolvedShellLaunchConfig = this._register(new Emitter<{ id: number, event: IShellLaunchConfig }>()); - readonly onProcessResolvedShellLaunchConfig = this._onProcessResolvedShellLaunchConfig.event; private readonly _onProcessOrphanQuestion = this._register(new Emitter<{ id: number }>()); readonly onProcessOrphanQuestion = this._onProcessOrphanQuestion.event; private readonly _onDidRequestDetach = this._register(new Emitter<{ requestId: number, workspaceId: string, instanceId: number }>()); readonly onDidRequestDetach = this._onDidRequestDetach.event; - private readonly _onProcessDidChangeHasChildProcesses = this._register(new Emitter<{ id: number, event: boolean }>()); - readonly onProcessDidChangeHasChildProcesses = this._onProcessDidChangeHasChildProcesses.event; private readonly _onDidChangeProperty = this._register(new Emitter<{ id: number, property: IProcessProperty }>()); readonly onDidChangeProperty = this._onDidChangeProperty.event; @@ -202,13 +190,7 @@ export class PtyHostService extends Disposable implements IPtyService { // Create proxy and forward events const proxy = ProxyChannel.toService(client.getChannel(TerminalIpcChannels.PtyHost)); this._register(proxy.onProcessData(e => this._onProcessData.fire(e))); - this._register(proxy.onProcessExit(e => this._onProcessExit.fire(e))); this._register(proxy.onProcessReady(e => this._onProcessReady.fire(e))); - this._register(proxy.onProcessTitleChanged(e => this._onProcessTitleChanged.fire(e))); - this._register(proxy.onProcessShellTypeChanged(e => this._onProcessShellTypeChanged.fire(e))); - this._register(proxy.onProcessOverrideDimensions(e => this._onProcessOverrideDimensions.fire(e))); - this._register(proxy.onProcessResolvedShellLaunchConfig(e => this._onProcessResolvedShellLaunchConfig.fire(e))); - this._register(proxy.onProcessDidChangeHasChildProcesses(e => this._onProcessDidChangeHasChildProcesses.fire(e))); this._register(proxy.onDidChangeProperty(e => this._onDidChangeProperty.fire(e))); this._register(proxy.onProcessReplay(e => this._onProcessReplay.fire(e))); this._register(proxy.onProcessOrphanQuestion(e => this._onProcessOrphanQuestion.fire(e))); diff --git a/src/vs/platform/terminal/node/ptyService.ts b/src/vs/platform/terminal/node/ptyService.ts index 5d2ae38fc73..55388c0df37 100644 --- a/src/vs/platform/terminal/node/ptyService.ts +++ b/src/vs/platform/terminal/node/ptyService.ts @@ -12,7 +12,7 @@ import { URI } from 'vs/base/common/uri'; import { getSystemShell } from 'vs/base/node/shell'; import { ILogService } from 'vs/platform/log/common/log'; import { RequestStore } from 'vs/platform/terminal/common/requestStore'; -import { IProcessDataEvent, IProcessReadyEvent, IPtyService, IRawTerminalInstanceLayoutInfo, IReconnectConstants, IRequestResolveVariablesEvent, IShellLaunchConfig, ITerminalDimensionsOverride, ITerminalInstanceLayoutInfoById, ITerminalLaunchError, ITerminalsLayoutInfo, ITerminalTabLayoutInfoById, TerminalIcon, IProcessProperty, TerminalShellType, TitleEventSource, ProcessPropertyType, ProcessCapability, IProcessPropertyMap, IFixedTerminalDimensions } from 'vs/platform/terminal/common/terminal'; +import { IProcessDataEvent, IProcessReadyEvent, IPtyService, IRawTerminalInstanceLayoutInfo, IReconnectConstants, IRequestResolveVariablesEvent, IShellLaunchConfig, ITerminalDimensionsOverride, ITerminalInstanceLayoutInfoById, ITerminalLaunchError, ITerminalsLayoutInfo, ITerminalTabLayoutInfoById, TerminalIcon, IProcessProperty, TitleEventSource, ProcessPropertyType, IProcessPropertyMap, IFixedTerminalDimensions, ProcessCapability } from 'vs/platform/terminal/common/terminal'; import { TerminalDataBufferer } from 'vs/platform/terminal/common/terminalDataBuffering'; import { escapeNonWindowsPath } from 'vs/platform/terminal/common/terminalEnvironment'; import { Terminal as XtermTerminal } from 'xterm-headless'; @@ -44,24 +44,12 @@ export class PtyService extends Disposable implements IPtyService { readonly onProcessData = this._onProcessData.event; private readonly _onProcessReplay = this._register(new Emitter<{ id: number, event: IPtyHostProcessReplayEvent }>()); readonly onProcessReplay = this._onProcessReplay.event; - private readonly _onProcessExit = this._register(new Emitter<{ id: number, event: number | undefined }>()); - readonly onProcessExit = this._onProcessExit.event; private readonly _onProcessReady = this._register(new Emitter<{ id: number, event: { pid: number, cwd: string, capabilities: ProcessCapability[] } }>()); readonly onProcessReady = this._onProcessReady.event; - private readonly _onProcessTitleChanged = this._register(new Emitter<{ id: number, event: string }>()); - readonly onProcessTitleChanged = this._onProcessTitleChanged.event; - private readonly _onProcessShellTypeChanged = this._register(new Emitter<{ id: number, event: TerminalShellType }>()); - readonly onProcessShellTypeChanged = this._onProcessShellTypeChanged.event; - private readonly _onProcessOverrideDimensions = this._register(new Emitter<{ id: number, event: ITerminalDimensionsOverride | undefined }>()); - readonly onProcessOverrideDimensions = this._onProcessOverrideDimensions.event; - private readonly _onProcessResolvedShellLaunchConfig = this._register(new Emitter<{ id: number, event: IShellLaunchConfig }>()); - readonly onProcessResolvedShellLaunchConfig = this._onProcessResolvedShellLaunchConfig.event; private readonly _onProcessOrphanQuestion = this._register(new Emitter<{ id: number }>()); readonly onProcessOrphanQuestion = this._onProcessOrphanQuestion.event; private readonly _onDidRequestDetach = this._register(new Emitter<{ requestId: number, workspaceId: string, instanceId: number }>()); readonly onDidRequestDetach = this._onDidRequestDetach.event; - private readonly _onProcessDidChangeHasChildProcesses = this._register(new Emitter<{ id: number, event: boolean }>()); - readonly onProcessDidChangeHasChildProcesses = this._onProcessDidChangeHasChildProcesses.event; private readonly _onDidChangeProperty = this._register(new Emitter<{ id: number, property: IProcessProperty }>()); readonly onDidChangeProperty = this._onDidChangeProperty.event; @@ -195,31 +183,21 @@ export class PtyService extends Disposable implements IPtyService { const id = ++this._lastPtyId; const process = new TerminalProcess(shellLaunchConfig, cwd, cols, rows, env, executableEnv, windowsEnableConpty, this._logService); process.onProcessData(event => this._onProcessData.fire({ id, event })); - process.onProcessExit(event => this._onProcessExit.fire({ id, event })); - if (process.onProcessOverrideDimensions) { - process.onProcessOverrideDimensions(event => this._onProcessOverrideDimensions.fire({ id, event })); - } - if (process.onProcessResolvedShellLaunchConfig) { - process.onProcessResolvedShellLaunchConfig(event => this._onProcessResolvedShellLaunchConfig.fire({ id, event })); - } - if (process.onDidChangeHasChildProcesses) { - process.onDidChangeHasChildProcesses(event => this._onProcessDidChangeHasChildProcesses.fire({ id, event })); - } const processLaunchOptions: IPersistentTerminalProcessLaunchOptions = { env, executableEnv, windowsEnableConpty }; const persistentProcess = new PersistentTerminalProcess(id, process, workspaceId, workspaceName, shouldPersist, cols, rows, processLaunchOptions, unicodeVersion, this._reconnectConstants, this._logService, isReviving ? shellLaunchConfig.initialText : undefined, shellLaunchConfig.icon, shellLaunchConfig.color, shellLaunchConfig.fixedDimensions); - process.onProcessExit(() => { - persistentProcess.dispose(); - this._ptys.delete(id); + process.onDidChangeProperty(property => { + if (property.type === ProcessPropertyType.Exit) { + persistentProcess.dispose(); + this._ptys.delete(id); + } + this._onDidChangeProperty.fire({ id, property }); }); - process.onDidChangeProperty(property => this._onDidChangeProperty.fire({ id, property })); persistentProcess.onProcessReplay(event => this._onProcessReplay.fire({ id, event })); persistentProcess.onProcessReady(event => this._onProcessReady.fire({ id, event })); - persistentProcess.onProcessTitleChanged(event => this._onProcessTitleChanged.fire({ id, event })); - persistentProcess.onProcessShellTypeChanged(event => this._onProcessShellTypeChanged.fire({ id, event })); persistentProcess.onProcessOrphanQuestion(() => this._onProcessOrphanQuestion.fire({ id })); persistentProcess.onDidChangeProperty(property => this._onDidChangeProperty.fire({ id, property })); this._ptys.set(id, persistentProcess); @@ -428,10 +406,6 @@ export class PersistentTerminalProcess extends Disposable { readonly onProcessReplay = this._onProcessReplay.event; private readonly _onProcessReady = this._register(new Emitter()); readonly onProcessReady = this._onProcessReady.event; - private readonly _onProcessTitleChanged = this._register(new Emitter()); - readonly onProcessTitleChanged = this._onProcessTitleChanged.event; - private readonly _onProcessShellTypeChanged = this._register(new Emitter()); - readonly onProcessShellTypeChanged = this._onProcessShellTypeChanged.event; private readonly _onProcessOverrideDimensions = this._register(new Emitter()); readonly onProcessOverrideDimensions = this._onProcessOverrideDimensions.event; private readonly _onProcessData = this._register(new Emitter()); @@ -511,20 +485,21 @@ export class PersistentTerminalProcess extends Disposable { this._logService.info(`Persistent process "${this._persistentProcessId}": The short reconnection grace time of ${printTime(reconnectConstants.shortGraceTime)} has expired, shutting down pid ${this._pid}`); this.shutdown(true); }, reconnectConstants.shortGraceTime)); - + this._register(this._terminalProcess.onDidChangeProperty(e => { + if (e.type === ProcessPropertyType.Exit) { + this._bufferer.stopBuffering(this._persistentProcessId); + } + this._onDidChangeProperty.fire(e); + })); this._register(this._terminalProcess.onProcessReady(e => { this._pid = e.pid; this._cwd = e.cwd; this._onProcessReady.fire(e); })); - this._register(this._terminalProcess.onProcessTitleChanged(e => this._onProcessTitleChanged.fire(e))); - this._register(this._terminalProcess.onProcessShellTypeChanged(e => this._onProcessShellTypeChanged.fire(e))); - this._register(this._terminalProcess.onDidChangeProperty(e => this._onDidChangeProperty.fire(e))); // Data buffering to reduce the amount of messages going to the renderer this._bufferer = new TerminalDataBufferer((_, data) => this._onProcessData.fire(data)); this._register(this._bufferer.startBuffering(this._persistentProcessId, this._terminalProcess.onProcessData)); - this._register(this._terminalProcess.onProcessExit(() => this._bufferer.stopBuffering(this._persistentProcessId))); // Data recording for reconnect this._register(this.onProcessData(e => this._serializer.handleData(e))); @@ -579,8 +554,8 @@ export class PersistentTerminalProcess extends Disposable { } } else { this._onProcessReady.fire({ pid: this._pid, cwd: this._cwd, capabilities: this._terminalProcess.capabilities, requiresWindowsMode: isWindows && getWindowsBuildNumber() < 21376 }); - this._onProcessTitleChanged.fire(this._terminalProcess.currentTitle); - this._onProcessShellTypeChanged.fire(this._terminalProcess.shellType); + this._onDidChangeProperty.fire({ type: ProcessPropertyType.Title, value: this._terminalProcess.currentTitle }); + this._onDidChangeProperty.fire({ type: ProcessPropertyType.ShellType, value: this._terminalProcess.shellType }); this.triggerReplay(); } return undefined; diff --git a/src/vs/platform/terminal/node/terminalProcess.ts b/src/vs/platform/terminal/node/terminalProcess.ts index 8fa92e037ed..45f72dc0b8b 100644 --- a/src/vs/platform/terminal/node/terminalProcess.ts +++ b/src/vs/platform/terminal/node/terminalProcess.ts @@ -14,7 +14,7 @@ import { URI } from 'vs/base/common/uri'; import { Promises } from 'vs/base/node/pfs'; import { localize } from 'vs/nls'; import { ILogService } from 'vs/platform/log/common/log'; -import { FlowControlConstants, IProcessReadyEvent, IShellLaunchConfig, ITerminalChildProcess, ITerminalDimensionsOverride, ITerminalLaunchError, IProcessProperty, IProcessPropertyMap as IProcessPropertyMap, ProcessPropertyType, TerminalShellType, ProcessCapability } from 'vs/platform/terminal/common/terminal'; +import { FlowControlConstants, IShellLaunchConfig, ITerminalChildProcess, ITerminalLaunchError, IProcessProperty, IProcessPropertyMap as IProcessPropertyMap, ProcessPropertyType, TerminalShellType, ProcessCapability, IProcessReadyEvent } from 'vs/platform/terminal/common/terminal'; import { ChildProcessMonitor } from 'vs/platform/terminal/node/childProcessMonitor'; import { findExecutable, getWindowsBuildNumber } from 'vs/platform/terminal/node/terminalEnvironment'; import { WindowsShellHelper } from 'vs/platform/terminal/node/windowsShellHelper'; @@ -79,7 +79,13 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess private _properties: IProcessPropertyMap = { cwd: '', initialCwd: '', - fixedDimensions: { cols: undefined, rows: undefined } + fixedDimensions: { cols: undefined, rows: undefined }, + title: '', + shellType: undefined, + hasChildProcesses: true, + resolvedShellLaunchConfig: {}, + overrideDimensions: undefined, + exit: undefined }; private static _lastKillOrStart = 0; private _exitCode: number | undefined; @@ -110,22 +116,11 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess private readonly _onProcessData = this._register(new Emitter()); readonly onProcessData = this._onProcessData.event; - private readonly _onProcessExit = this._register(new Emitter()); - readonly onProcessExit = this._onProcessExit.event; private readonly _onProcessReady = this._register(new Emitter()); readonly onProcessReady = this._onProcessReady.event; - private readonly _onProcessTitleChanged = this._register(new Emitter()); - readonly onProcessTitleChanged = this._onProcessTitleChanged.event; - private readonly _onProcessShellTypeChanged = this._register(new Emitter()); - readonly onProcessShellTypeChanged = this._onProcessShellTypeChanged.event; - private readonly _onDidChangeHasChildProcesses = this._register(new Emitter()); - readonly onDidChangeHasChildProcesses = this._onDidChangeHasChildProcesses.event; private readonly _onDidChangeProperty = this._register(new Emitter>()); readonly onDidChangeProperty = this._onDidChangeProperty.event; - onProcessOverrideDimensions?: Event | undefined; - onProcessResolvedShellLaunchConfig?: Event | undefined; - constructor( readonly shellLaunchConfig: IShellLaunchConfig, cwd: string, @@ -178,8 +173,8 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess // WindowsShellHelper is used to fetch the process title and shell type this.onProcessReady(e => { this._windowsShellHelper = this._register(new WindowsShellHelper(e.pid)); - this._register(this._windowsShellHelper.onShellTypeChanged(e => this._onProcessShellTypeChanged.fire(e))); - this._register(this._windowsShellHelper.onShellNameChanged(e => this._onProcessTitleChanged.fire(e))); + this._register(this._windowsShellHelper.onShellTypeChanged(e => this._onDidChangeProperty.fire({ type: ProcessPropertyType.ShellType, value: e }))); + this._register(this._windowsShellHelper.onShellNameChanged(e => this._onDidChangeProperty.fire({ type: ProcessPropertyType.Title, value: e }))); }); } // Enable the cwd detection capability if the process supports it @@ -253,7 +248,7 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess const ptyProcess = (await import('node-pty')).spawn(shellLaunchConfig.executable!, args, options); this._ptyProcess = ptyProcess; this._childProcessMonitor = this._register(new ChildProcessMonitor(ptyProcess.pid, this._logService)); - this._childProcessMonitor.onDidChangeHasChildProcesses(this._onDidChangeHasChildProcesses.fire, this._onDidChangeHasChildProcesses); + this._childProcessMonitor.onDidChangeHasChildProcesses(value => this._onDidChangeProperty.fire({ type: ProcessPropertyType.HasChildProcesses, value })); this._processStartupComplete = new Promise(c => { this.onProcessReady(() => c()); }); @@ -334,7 +329,7 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess } catch (ex) { // Swallow, the pty has already been killed } - this._onProcessExit.fire(this._exitCode || 0); + this._onDidChangeProperty.fire({ type: ProcessPropertyType.Exit, value: this._exitCode || 0 }); this.dispose(); } @@ -360,7 +355,7 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess return; } this._currentTitle = ptyProcess.process; - this._onProcessTitleChanged.fire(this._currentTitle); + this._onDidChangeProperty.fire({ type: ProcessPropertyType.Title, value: this._currentTitle }); } shutdown(immediate: boolean): void { @@ -402,21 +397,31 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess } async refreshProperty(type: ProcessPropertyType): Promise { - if (type === ProcessPropertyType.Cwd) { - const newCwd = await this.getCwd(); - if (newCwd !== this._properties.cwd) { - this._properties.cwd = newCwd; - this._onDidChangeProperty.fire({ type: ProcessPropertyType.Cwd, value: this._properties.cwd }); - } - return newCwd; - } else { - return this.getInitialCwd(); + switch (type) { + case ProcessPropertyType.Cwd: + const newCwd = await this.getCwd(); + if (newCwd !== this._properties.cwd) { + this._properties.cwd = newCwd; + this._onDidChangeProperty.fire({ type: ProcessPropertyType.Cwd, value: this._properties.cwd }); + } + return newCwd as IProcessPropertyMap[T]; + case ProcessPropertyType.InitialCwd: + const initialCwd = await this.getInitialCwd(); + if (initialCwd !== this._properties.initialCwd) { + this._properties.initialCwd = initialCwd; + this._onDidChangeProperty.fire({ type: ProcessPropertyType.InitialCwd, value: this._properties.initialCwd }); + } + return initialCwd as IProcessPropertyMap[T]; + case ProcessPropertyType.Title: + return this.currentTitle as IProcessPropertyMap[T]; + default: + return this.shellType as IProcessPropertyMap[T]; } } async updateProperty(type: ProcessPropertyType, value: IProcessPropertyMap[T]): Promise { //TODO: why is the type check necessary? - if (type === ProcessPropertyType.FixedDimensions && typeof value !== 'string') { + if (type === ProcessPropertyType.FixedDimensions && typeof value !== 'string' && value && ('cols' in value || 'rows' in value)) { this._properties.fixedDimensions = value; } } diff --git a/src/vs/server/remoteTerminalChannel.ts b/src/vs/server/remoteTerminalChannel.ts index dec98015031..380fda531a2 100644 --- a/src/vs/server/remoteTerminalChannel.ts +++ b/src/vs/server/remoteTerminalChannel.ts @@ -15,7 +15,7 @@ import { IServerChannel } from 'vs/base/parts/ipc/common/ipc'; 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'; -import { IPtyService, IShellLaunchConfig, ITerminalProfile, ITerminalsLayoutInfo } from 'vs/platform/terminal/common/terminal'; +import { IPtyService, IShellLaunchConfig, ITerminalProfile, ITerminalsLayoutInfo, ProcessPropertyType } from 'vs/platform/terminal/common/terminal'; import { IGetTerminalLayoutInfoArgs, ISetTerminalLayoutInfoArgs } from 'vs/platform/terminal/common/terminalProcess'; import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { createRemoteURITransformer } from 'vs/server/remoteUriTransformer'; @@ -148,15 +148,9 @@ export class RemoteTerminalChannel extends Disposable implements IServerChannel< case '$onPtyHostResponsiveEvent': return this._ptyService.onPtyHostResponsive || Event.None; case '$onPtyHostRequestResolveVariablesEvent': return this._ptyService.onPtyHostRequestResolveVariables || Event.None; case '$onProcessDataEvent': return this._ptyService.onProcessData; - case '$onProcessExitEvent': return this._ptyService.onProcessExit; case '$onProcessReadyEvent': return this._ptyService.onProcessReady; case '$onProcessReplayEvent': return this._ptyService.onProcessReplay; - case '$onProcessTitleChangedEvent': return this._ptyService.onProcessTitleChanged; - case '$onProcessShellTypeChangedEvent': return this._ptyService.onProcessShellTypeChanged; - case '$onProcessOverrideDimensionsEvent': return this._ptyService.onProcessOverrideDimensions; - case '$onProcessResolvedShellLaunchConfigEvent': return this._ptyService.onProcessResolvedShellLaunchConfig; case '$onProcessOrphanQuestion': return this._ptyService.onProcessOrphanQuestion; - case '$onProcessDidChangeHasChildProcesses': return this._ptyService.onProcessDidChangeHasChildProcesses; case '$onExecuteCommand': return this.onExecuteCommand; case '$onDidRequestDetach': return this._ptyService.onDidRequestDetach || Event.None; case '$onDidChangeProperty': return this._ptyService.onDidChangeProperty; @@ -245,7 +239,11 @@ export class RemoteTerminalChannel extends Disposable implements IServerChannel< const cliServer = new CLIServerBase(commandsExecuter, this._logService, ipcHandlePath); const id = await this._ptyService.createProcess(shellLaunchConfig, initialCwd, args.cols, args.rows, args.unicodeVersion, env, baseEnv, false, args.shouldPersistTerminal, args.workspaceId, args.workspaceName); - this._ptyService.onProcessExit(e => e.id === id && cliServer.dispose()); + this._ptyService.onDidChangeProperty(e => { + if (e.property.type === ProcessPropertyType.Exit && e.id === id) { + cliServer.dispose(); + } + }); return { persistentTerminalId: id, diff --git a/src/vs/workbench/api/browser/mainThreadTerminalService.ts b/src/vs/workbench/api/browser/mainThreadTerminalService.ts index 68c5acf3c18..9f430d4e99d 100644 --- a/src/vs/workbench/api/browser/mainThreadTerminalService.ts +++ b/src/vs/workbench/api/browser/mainThreadTerminalService.ts @@ -10,7 +10,7 @@ import { URI } from 'vs/base/common/uri'; import { StopWatch } from 'vs/base/common/stopwatch'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ILogService } from 'vs/platform/log/common/log'; -import { IShellLaunchConfig, IShellLaunchConfigDto, ITerminalDimensions, TerminalLocation, TitleEventSource } from 'vs/platform/terminal/common/terminal'; +import { IProcessProperty, IShellLaunchConfig, IShellLaunchConfigDto, TerminalLocation, TitleEventSource } from 'vs/platform/terminal/common/terminal'; import { TerminalDataBufferer } from 'vs/platform/terminal/common/terminalDataBuffering'; import { ITerminalEditorService, ITerminalExternalLinkProvider, ITerminalGroupService, ITerminalInstance, ITerminalInstanceService, ITerminalLink, ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal'; import { TerminalProcessExtHostProxy } from 'vs/workbench/contrib/terminal/browser/terminalProcessExtHostProxy'; @@ -323,26 +323,14 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape this._terminalProcessProxies.get(terminalId)?.emitReady(pid, cwd); } + public $sendProcessProperty(terminalId: number, property: IProcessProperty): void { + this._terminalProcessProxies.get(terminalId)?.emitProcessProperty(property); + } + public $sendProcessExit(terminalId: number, exitCode: number | undefined): void { this._terminalProcessProxies.get(terminalId)?.emitExit(exitCode); } - public $sendOverrideDimensions(terminalId: number, dimensions: ITerminalDimensions | undefined): void { - this._terminalProcessProxies.get(terminalId)?.emitOverrideDimensions(dimensions); - } - - public $sendProcessInitialCwd(terminalId: number, initialCwd: string): void { - this._terminalProcessProxies.get(terminalId)?.emitInitialCwd(initialCwd); - } - - public $sendProcessCwd(terminalId: number, cwd: string): void { - this._terminalProcessProxies.get(terminalId)?.emitCwd(cwd); - } - - public $sendResolvedLaunchConfig(terminalId: number, shellLaunchConfig: IShellLaunchConfig): void { - this._getTerminalProcess(terminalId)?.emitResolvedShellLaunchConfig(shellLaunchConfig); - } - private async _onRequestLatency(terminalId: number): Promise { const COUNT = 2; let sum = 0; diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 4d16d0c94f3..949a7641b66 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -39,7 +39,7 @@ import { IRemoteConnectionData, RemoteAuthorityResolverErrorCode, ResolverResult import { ProvidedPortAttributes, TunnelCreationOptions, TunnelOptions, TunnelProviderFeatures } from 'vs/platform/remote/common/tunnel'; import { ClassifiedEvent, GDPRClassification, StrictPropertyCheck } from 'vs/platform/telemetry/common/gdprTypings'; import { ITelemetryInfo } from 'vs/platform/telemetry/common/telemetry'; -import { ICreateContributedTerminalProfileOptions, IShellLaunchConfig, IShellLaunchConfigDto, ITerminalDimensions, ITerminalEnvironment, ITerminalLaunchError, ITerminalProfile, TerminalLocation } from 'vs/platform/terminal/common/terminal'; +import { ICreateContributedTerminalProfileOptions, IProcessProperty, IShellLaunchConfigDto, ITerminalEnvironment, ITerminalLaunchError, ITerminalProfile, TerminalLocation } from 'vs/platform/terminal/common/terminal'; import { ThemeColor, ThemeIcon } from 'vs/platform/theme/common/themeService'; import { IExtensionIdWithVersion } from 'vs/platform/userDataSync/common/extensionsStorageSync'; import { WorkspaceTrustRequestOptions } from 'vs/platform/workspace/common/workspaceTrust'; @@ -504,14 +504,9 @@ export interface MainThreadTerminalServiceShape extends IDisposable { $setEnvironmentVariableCollection(extensionIdentifier: string, persistent: boolean, collection: ISerializableEnvironmentVariableCollection | undefined): void; // Process - $sendProcessTitle(terminalId: number, title: string): void; $sendProcessData(terminalId: number, data: string): void; $sendProcessReady(terminalId: number, pid: number, cwd: string): void; - $sendProcessExit(terminalId: number, exitCode: number | undefined): void; - $sendProcessInitialCwd(terminalId: number, cwd: string): void; - $sendProcessCwd(terminalId: number, initialCwd: string): void; - $sendOverrideDimensions(terminalId: number, dimensions: ITerminalDimensions | undefined): void; - $sendResolvedLaunchConfig(terminalId: number, shellLaunchConfig: IShellLaunchConfig): void; + $sendProcessProperty(terminalId: number, property: IProcessProperty): void; } export interface TransferQuickPickItems extends quickInput.IQuickPickItem { diff --git a/src/vs/workbench/api/common/extHostTerminalService.ts b/src/vs/workbench/api/common/extHostTerminalService.ts index 0309ac1ff3b..392f0e1be17 100644 --- a/src/vs/workbench/api/common/extHostTerminalService.ts +++ b/src/vs/workbench/api/common/extHostTerminalService.ts @@ -18,7 +18,7 @@ import { serializeEnvironmentVariableCollection } from 'vs/workbench/contrib/ter import { CancellationTokenSource } from 'vs/base/common/cancellation'; import { generateUuid } from 'vs/base/common/uuid'; import { ISerializableEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariable'; -import { ICreateContributedTerminalProfileOptions, IProcessReadyEvent, IShellLaunchConfigDto, ITerminalChildProcess, ITerminalDimensionsOverride, ITerminalLaunchError, ITerminalProfile, TerminalIcon, TerminalLocation, IProcessProperty, TerminalShellType, IShellLaunchConfig, ProcessPropertyType, ProcessCapability, IProcessPropertyMap } from 'vs/platform/terminal/common/terminal'; +import { ICreateContributedTerminalProfileOptions, IProcessReadyEvent, IShellLaunchConfigDto, ITerminalChildProcess, ITerminalDimensionsOverride, ITerminalLaunchError, ITerminalProfile, TerminalIcon, TerminalLocation, IProcessProperty, TerminalShellType, ProcessPropertyType, ProcessCapability, IProcessPropertyMap } from 'vs/platform/terminal/common/terminal'; import { TerminalDataBufferer } from 'vs/platform/terminal/common/terminalDataBuffering'; import { ThemeColor } from 'vs/platform/theme/common/themeService'; import { withNullAsUndefined } from 'vs/base/common/types'; @@ -262,17 +262,14 @@ export class ExtHostPseudoterminal implements ITerminalChildProcess { private readonly _onDidChangeProperty = new Emitter>(); public readonly onDidChangeProperty = this._onDidChangeProperty.event; - constructor(private readonly _pty: vscode.Pseudoterminal) { } - onProcessResolvedShellLaunchConfig?: Event | undefined; - onDidChangeHasChildProcesses?: Event | undefined; refreshProperty(property: ProcessPropertyType): Promise { - return Promise.resolve(''); + throw new Error(`refreshProperty is not suppported in extension owned terminals. property: ${property}`); } - async updateProperty(property: ProcessPropertyType, value: IProcessPropertyMap[T]): Promise { - Promise.resolve(''); + updateProperty(property: ProcessPropertyType, value: IProcessPropertyMap[T]): Promise { + throw new Error(`updateProperty is not suppported in extension owned terminals. property: ${property}, value: ${value}`); } async start(): Promise { @@ -589,17 +586,17 @@ 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.onProcessTitleChanged(title => this._proxy.$sendProcessTitle(id, title))); + disposables.add(p.onDidChangeProperty(property => { + if (property.type === ProcessPropertyType.Exit) { + this._onProcessExit(id, property.value); + } + this._proxy.$sendProcessProperty(id, property); + })); // Buffer data events to reduce the amount of messages going to the renderer this._bufferer.startBuffering(id, p.onProcessData); - disposables.add(p.onProcessExit(exitCode => this._onProcessExit(id, exitCode))); - if (p.onProcessOverrideDimensions) { - disposables.add(p.onProcessOverrideDimensions(e => this._proxy.$sendOverrideDimensions(id, e))); - } this._terminalProcesses.set(id, p); const awaitingStart = this._extensionTerminalAwaitingStart[id]; @@ -642,11 +639,11 @@ export abstract class BaseExtHostTerminalService extends Disposable implements I } public $acceptProcessRequestInitialCwd(id: number): void { - this._terminalProcesses.get(id)?.getInitialCwd().then(initialCwd => this._proxy.$sendProcessInitialCwd(id, initialCwd)); + this._terminalProcesses.get(id)?.getInitialCwd().then(initialCwd => this._proxy.$sendProcessProperty(id, { type: ProcessPropertyType.InitialCwd, value: initialCwd })); } public $acceptProcessRequestCwd(id: number): void { - this._terminalProcesses.get(id)?.getCwd().then(cwd => this._proxy.$sendProcessCwd(id, cwd)); + this._terminalProcesses.get(id)?.getCwd().then(cwd => this._proxy.$sendProcessProperty(id, { type: ProcessPropertyType.Cwd, value: cwd })); } public $acceptProcessRequestLatency(id: number): number { @@ -777,9 +774,6 @@ export abstract class BaseExtHostTerminalService extends Disposable implements I processDiposable.dispose(); delete this._terminalProcessDisposables[id]; } - - // Send exit event to main side - this._proxy.$sendProcessExit(id, exitCode); } private _getTerminalById(id: number): ExtHostTerminal | null { diff --git a/src/vs/workbench/contrib/terminal/browser/remotePty.ts b/src/vs/workbench/contrib/terminal/browser/remotePty.ts index 1223a0d01d7..afba763788d 100644 --- a/src/vs/workbench/contrib/terminal/browser/remotePty.ts +++ b/src/vs/workbench/contrib/terminal/browser/remotePty.ts @@ -8,7 +8,7 @@ import { Emitter } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; import { ILogService } from 'vs/platform/log/common/log'; -import { IProcessDataEvent, IProcessReadyEvent, IShellLaunchConfig, ITerminalChildProcess, ITerminalDimensionsOverride, ITerminalLaunchError, IProcessProperty, IProcessPropertyMap, ProcessPropertyType, TerminalShellType, ProcessCapability } from 'vs/platform/terminal/common/terminal'; +import { IProcessDataEvent, ITerminalChildProcess, ITerminalLaunchError, IProcessProperty, IProcessPropertyMap, ProcessPropertyType, ProcessCapability, IProcessReadyEvent } from 'vs/platform/terminal/common/terminal'; import { IPtyHostProcessReplayEvent } from 'vs/platform/terminal/common/terminalProcess'; import { RemoteTerminalChannelClient } from 'vs/workbench/contrib/terminal/common/remoteTerminalChannel'; import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; @@ -16,20 +16,8 @@ import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteA export class RemotePty extends Disposable implements ITerminalChildProcess { private readonly _onProcessData = this._register(new Emitter()); readonly onProcessData = this._onProcessData.event; - private readonly _onProcessExit = this._register(new Emitter()); - readonly onProcessExit = this._onProcessExit.event; private readonly _onProcessReady = this._register(new Emitter()); readonly onProcessReady = this._onProcessReady.event; - private readonly _onProcessTitleChanged = this._register(new Emitter()); - readonly onProcessTitleChanged = this._onProcessTitleChanged.event; - private readonly _onProcessShellTypeChanged = this._register(new Emitter()); - readonly onProcessShellTypeChanged = this._onProcessShellTypeChanged.event; - private readonly _onProcessOverrideDimensions = this._register(new Emitter()); - readonly onProcessOverrideDimensions = this._onProcessOverrideDimensions.event; - private readonly _onProcessResolvedShellLaunchConfig = this._register(new Emitter()); - readonly onProcessResolvedShellLaunchConfig = this._onProcessResolvedShellLaunchConfig.event; - private readonly _onDidChangeHasChildProcesses = this._register(new Emitter()); - readonly onDidChangeHasChildProcesses = this._onDidChangeHasChildProcesses.event; private readonly _onDidChangeProperty = this._register(new Emitter>()); readonly onDidChangeProperty = this._onDidChangeProperty.event; @@ -40,7 +28,13 @@ export class RemotePty extends Disposable implements ITerminalChildProcess { private _properties: IProcessPropertyMap = { cwd: '', initialCwd: '', - fixedDimensions: { cols: undefined, rows: undefined } + fixedDimensions: { cols: undefined, rows: undefined }, + title: '', + shellType: undefined, + hasChildProcesses: true, + resolvedShellLaunchConfig: {}, + overrideDimensions: undefined, + exit: undefined }; private _capabilities: ProcessCapability[] = []; @@ -148,39 +142,24 @@ export class RemotePty extends Disposable implements ITerminalChildProcess { processBinary(e: string): Promise { return this._remoteTerminalChannel.processBinary(this._id, e); } - handleExit(e: number | undefined) { - this._onProcessExit.fire(e); - } handleReady(e: IProcessReadyEvent) { this._capabilities = e.capabilities; this._onProcessReady.fire(e); } - handleTitleChanged(e: string) { - this._onProcessTitleChanged.fire(e); - } - handleShellTypeChanged(e: TerminalShellType | undefined) { - this._onProcessShellTypeChanged.fire(e); - } - handleOverrideDimensions(e: ITerminalDimensionsOverride | undefined) { - this._onProcessOverrideDimensions.fire(e); - } - handleResolvedShellLaunchConfig(e: IShellLaunchConfig) { - // Revive the cwd URI - if (e.cwd && typeof e.cwd !== 'string') { - e.cwd = URI.revive(e.cwd); + handleDidChangeProperty({ type, value }: IProcessProperty) { + switch (type) { + case ProcessPropertyType.Cwd: + this._properties.cwd = value; + break; + case ProcessPropertyType.InitialCwd: + this._properties.initialCwd = value; + break; + case ProcessPropertyType.ResolvedShellLaunchConfig: + if (value.cwd && typeof value.cwd !== 'string') { + value.cwd = URI.revive(value.cwd); + } } - this._onProcessResolvedShellLaunchConfig.fire(e); - } - handleDidChangeHasChildProcesses(e: boolean) { - this._onDidChangeHasChildProcesses.fire(e); - } - handleDidChangeProperty(e: IProcessProperty) { - if (e.type === ProcessPropertyType.Cwd) { - this._properties.cwd = e.value; - } else if (e.type === ProcessPropertyType.InitialCwd) { - this._properties.initialCwd = e.value; - } - this._onDidChangeProperty.fire(e); + this._onDidChangeProperty.fire({ type, value }); } async handleReplay(e: IPtyHostProcessReplayEvent) { @@ -189,7 +168,7 @@ export class RemotePty extends Disposable implements ITerminalChildProcess { for (const innerEvent of e.events) { if (innerEvent.cols !== 0 || innerEvent.rows !== 0) { // never override with 0x0 as that is a marker for an unknown initial size - this._onProcessOverrideDimensions.fire({ cols: innerEvent.cols, rows: innerEvent.rows, forceExactSize: true }); + this._onDidChangeProperty.fire({ type: ProcessPropertyType.OverrideDimensions, value: { cols: innerEvent.cols, rows: innerEvent.rows, forceExactSize: true } }); } const e: IProcessDataEvent = { data: innerEvent.data, trackCommit: true }; this._onProcessData.fire(e); @@ -200,7 +179,7 @@ export class RemotePty extends Disposable implements ITerminalChildProcess { } // remove size override - this._onProcessOverrideDimensions.fire(undefined); + this._onDidChangeProperty.fire({ type: ProcessPropertyType.OverrideDimensions, value: undefined }); } handleOrphanQuestion() { diff --git a/src/vs/workbench/contrib/terminal/browser/remoteTerminalService.ts b/src/vs/workbench/contrib/terminal/browser/remoteTerminalService.ts index 3626519a4f0..434160bd1c0 100644 --- a/src/vs/workbench/contrib/terminal/browser/remoteTerminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/remoteTerminalService.ts @@ -66,23 +66,19 @@ export class RemoteTerminalService extends Disposable implements IRemoteTerminal this._remoteTerminalChannel = channel; channel.onProcessData(e => this._ptys.get(e.id)?.handleData(e.event)); - channel.onProcessExit(e => { - const pty = this._ptys.get(e.id); - if (pty) { - pty.handleExit(e.event); - this._ptys.delete(e.id); - } - }); - channel.onProcessReady(e => this._ptys.get(e.id)?.handleReady(e.event)); - channel.onProcessTitleChanged(e => this._ptys.get(e.id)?.handleTitleChanged(e.event)); - channel.onProcessShellTypeChanged(e => this._ptys.get(e.id)?.handleShellTypeChanged(e.event)); - channel.onProcessOverrideDimensions(e => this._ptys.get(e.id)?.handleOverrideDimensions(e.event)); - channel.onProcessResolvedShellLaunchConfig(e => this._ptys.get(e.id)?.handleResolvedShellLaunchConfig(e.event)); channel.onProcessReplay(e => this._ptys.get(e.id)?.handleReplay(e.event)); channel.onProcessOrphanQuestion(e => this._ptys.get(e.id)?.handleOrphanQuestion()); channel.onDidRequestDetach(e => this._onDidRequestDetach.fire(e)); - channel.onProcessDidChangeHasChildProcesses(e => this._ptys.get(e.id)?.handleDidChangeHasChildProcesses(e.event)); - channel.onDidChangeProperty(e => this._ptys.get(e.id)?.handleDidChangeProperty(e.property)); + channel.onProcessReady(e => this._ptys.get(e.id)?.handleReady(e.event)); + channel.onDidChangeProperty(e => { + if (e.property.type === ProcessPropertyType.Exit) { + const pty = this._ptys.get(e.id); + if (pty) { + this._ptys.delete(e.id); + } + } + this._ptys.get(e.id)?.handleDidChangeProperty(e.property); + }); const allowedCommands = ['_remoteCLI.openExternal', '_remoteCLI.windowOpen', '_remoteCLI.getSystemStatus', '_remoteCLI.manageExtensions']; channel.onExecuteCommand(async e => { diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index bd72c0da55e..51e95a8622f 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -1235,16 +1235,35 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { this._onTitleChanged.fire(this); }); } - this._processManager.onDidChangeProperty(e => { - if (e.type === ProcessPropertyType.Cwd) { - this._cwd = e.value; - this._labelComputer?.refreshLabel(); - } else if (e.type === ProcessPropertyType.InitialCwd) { - this._initialCwd = e.value; - this._cwd = this._initialCwd; - this.refreshTabLabels(this.title, TitleEventSource.Api); + this._processManager.onDidChangeProperty(({ type, value }) => { + switch (type) { + case ProcessPropertyType.Cwd: + this._cwd = value; + this._labelComputer?.refreshLabel(); + break; + case ProcessPropertyType.InitialCwd: + this._initialCwd = value; + this._cwd = this._initialCwd; + this.refreshTabLabels(this.title, TitleEventSource.Api); + break; + case ProcessPropertyType.Title: + this.refreshTabLabels(value ? value : '', TitleEventSource.Process); + break; + case ProcessPropertyType.OverrideDimensions: + this.setOverrideDimensions(value, true); + break; + case ProcessPropertyType.ResolvedShellLaunchConfig: + this._setResolvedShellLaunchConfig(value); + break; + case ProcessPropertyType.HasChildProcesses: + this._onDidChangeHasChildProcesses.fire(value); + break; + case ProcessPropertyType.Exit: + this._onProcessExit(value); + break; } }); + if (this._shellLaunchConfig.name) { this.refreshTabLabels(this._shellLaunchConfig.name, TitleEventSource.Api); } else { @@ -1256,32 +1275,27 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { }); }); this.refreshTabLabels(this._shellLaunchConfig.executable, TitleEventSource.Process); - this._messageTitleDisposable = this._processManager.onProcessTitle(title => this.refreshTabLabels(title ? title : '', TitleEventSource.Process)); + + this._processManager.onProcessData(ev => { + this._initialDataEvents?.push(ev.data); + this._onData.fire(ev.data); + }); + this._processManager.onEnvironmentVariableInfoChanged(e => this._onEnvironmentVariableInfoChanged(e)); + this._processManager.onPtyDisconnect(() => { + this._safeSetOption('disableStdin', true); + this.statusList.add({ + id: TerminalStatus.Disconnected, + severity: Severity.Error, + icon: Codicon.debugDisconnect, + tooltip: nls.localize('disconnectStatus', "Lost connection to process") + }); + }); + this._processManager.onPtyReconnect(() => { + this._safeSetOption('disableStdin', false); + this.statusList.remove(TerminalStatus.Disconnected); + }); } }); - this._processManager.onProcessExit(exitCode => this._onProcessExit(exitCode)); - this._processManager.onProcessData(ev => { - this._initialDataEvents?.push(ev.data); - this._onData.fire(ev.data); - }); - this._processManager.onProcessOverrideDimensions(e => this.setOverrideDimensions(e, true)); - this._processManager.onProcessResolvedShellLaunchConfig(e => this._setResolvedShellLaunchConfig(e)); - this._processManager.onProcessDidChangeHasChildProcesses(e => this._onDidChangeHasChildProcesses.fire(e)); - this._processManager.onEnvironmentVariableInfoChanged(e => this._onEnvironmentVariableInfoChanged(e)); - this._processManager.onProcessShellTypeChanged(type => this.setShellType(type)); - this._processManager.onPtyDisconnect(() => { - this._safeSetOption('disableStdin', true); - this.statusList.add({ - id: TerminalStatus.Disconnected, - severity: Severity.Error, - icon: Codicon.debugDisconnect, - tooltip: nls.localize('disconnectStatus', "Lost connection to process") - }); - }); - this._processManager.onPtyReconnect(() => { - this._safeSetOption('disableStdin', false); - this.statusList.remove(TerminalStatus.Disconnected); - }); } private async _createProcess(): Promise { diff --git a/src/vs/workbench/contrib/terminal/browser/terminalProcessExtHostProxy.ts b/src/vs/workbench/contrib/terminal/browser/terminalProcessExtHostProxy.ts index 13adb6c0130..a9af01a144c 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalProcessExtHostProxy.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalProcessExtHostProxy.ts @@ -5,7 +5,7 @@ import { Emitter, Event } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; -import { IProcessReadyEvent, IShellLaunchConfig, ITerminalChildProcess, ITerminalDimensions, ITerminalDimensionsOverride, ITerminalLaunchError, IProcessProperty, ProcessPropertyType, TerminalShellType, ProcessCapability } from 'vs/platform/terminal/common/terminal'; +import { IProcessReadyEvent, IShellLaunchConfig, ITerminalChildProcess, ITerminalDimensions, ITerminalLaunchError, IProcessProperty, ProcessPropertyType, ProcessCapability } from 'vs/platform/terminal/common/terminal'; import { ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal'; import { ITerminalProcessExtHostProxy } from 'vs/workbench/contrib/terminal/common/terminal'; @@ -20,12 +20,6 @@ export class TerminalProcessExtHostProxy extends Disposable implements ITerminal readonly onProcessExit: Event = this._onProcessExit.event; private readonly _onProcessReady = this._register(new Emitter()); get onProcessReady(): Event { return this._onProcessReady.event; } - private readonly _onProcessTitleChanged = this._register(new Emitter()); - readonly onProcessTitleChanged: Event = this._onProcessTitleChanged.event; - private readonly _onProcessOverrideDimensions = this._register(new Emitter()); - get onProcessOverrideDimensions(): Event { return this._onProcessOverrideDimensions.event; } - private readonly _onProcessResolvedShellLaunchConfig = this._register(new Emitter()); - get onProcessResolvedShellLaunchConfig(): Event { return this._onProcessResolvedShellLaunchConfig.event; } private readonly _onStart = this._register(new Emitter()); readonly onStart: Event = this._onStart.event; @@ -45,8 +39,6 @@ export class TerminalProcessExtHostProxy extends Disposable implements ITerminal readonly onRequestCwd: Event = this._onRequestCwd.event; private readonly _onRequestLatency = this._register(new Emitter()); readonly onRequestLatency: Event = this._onRequestLatency.event; - private readonly _onProcessShellTypeChanged = this._register(new Emitter()); - readonly onProcessShellTypeChanged = this._onProcessShellTypeChanged.event; private readonly _onDidChangeProperty = this._register(new Emitter>()); readonly onDidChangeProperty = this._onDidChangeProperty.event; @@ -63,31 +55,50 @@ export class TerminalProcessExtHostProxy extends Disposable implements ITerminal ) { super(); } - onDidChangeHasChildProcesses?: Event | undefined; emitData(data: string): void { this._onProcessData.fire(data); } emitTitle(title: string): void { - this._onProcessTitleChanged.fire(title); + this._onDidChangeProperty.fire({ type: ProcessPropertyType.Title, value: title }); } emitReady(pid: number, cwd: string): void { this._onProcessReady.fire({ pid, cwd, capabilities: this.capabilities }); } + emitProcessProperty({ type, value }: IProcessProperty): void { + switch (type) { + case ProcessPropertyType.Cwd: + this.emitCwd(value); + break; + case ProcessPropertyType.InitialCwd: + this.emitInitialCwd(value); + break; + case ProcessPropertyType.Title: + this.emitTitle(value); + break; + case ProcessPropertyType.OverrideDimensions: + this.emitOverrideDimensions(value); + break; + case ProcessPropertyType.ResolvedShellLaunchConfig: + this.emitResolvedShellLaunchConfig(value); + break; + } + } + emitExit(exitCode: number | undefined): void { this._onProcessExit.fire(exitCode); this.dispose(); } emitOverrideDimensions(dimensions: ITerminalDimensions | undefined): void { - this._onProcessOverrideDimensions.fire(dimensions); + this._onDidChangeProperty.fire({ type: ProcessPropertyType.OverrideDimensions, value: dimensions }); } emitResolvedShellLaunchConfig(shellLaunchConfig: IShellLaunchConfig): void { - this._onProcessResolvedShellLaunchConfig.fire(shellLaunchConfig); + this._onDidChangeProperty.fire({ type: ProcessPropertyType.ResolvedShellLaunchConfig, value: shellLaunchConfig }); } emitInitialCwd(initialCwd: string): void { diff --git a/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts b/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts index 3a240a3ed63..fd7cf95e429 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts @@ -22,7 +22,7 @@ import { withNullAsUndefined } from 'vs/base/common/types'; import { EnvironmentVariableInfoChangesActive, EnvironmentVariableInfoStale } from 'vs/workbench/contrib/terminal/browser/environmentVariableInfo'; import { IPathService } from 'vs/workbench/services/path/common/pathService'; import { IEnvironmentVariableInfo, IEnvironmentVariableService, IMergedEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariable'; -import { IProcessDataEvent, IShellLaunchConfig, ITerminalChildProcess, ITerminalDimensionsOverride, ITerminalEnvironment, ITerminalLaunchError, FlowControlConstants, TerminalShellType, ITerminalDimensions, TerminalSettingId, IProcessReadyEvent, IProcessProperty, ProcessPropertyType, IProcessPropertyMap } from 'vs/platform/terminal/common/terminal'; +import { IProcessDataEvent, IShellLaunchConfig, ITerminalChildProcess, ITerminalEnvironment, ITerminalLaunchError, FlowControlConstants, ITerminalDimensions, TerminalSettingId, IProcessReadyEvent, IProcessProperty, ProcessPropertyType, IProcessPropertyMap } from 'vs/platform/terminal/common/terminal'; import { TerminalRecorder } from 'vs/platform/terminal/common/terminalRecorder'; import { localize } from 'vs/nls'; import { formatMessageForTerminal } from 'vs/workbench/contrib/terminal/common/terminalStrings'; @@ -94,20 +94,10 @@ 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 _onProcessTitle = this._register(new Emitter()); - readonly onProcessTitle = this._onProcessTitle.event; private readonly _onDidChangeProperty = this._register(new Emitter>()); readonly onDidChangeProperty = this._onDidChangeProperty.event; - private readonly _onProcessShellTypeChanged = this._register(new Emitter()); - readonly onProcessShellTypeChanged = this._onProcessShellTypeChanged.event; private readonly _onProcessExit = this._register(new Emitter()); readonly onProcessExit = this._onProcessExit.event; - private readonly _onProcessOverrideDimensions = this._register(new Emitter()); - readonly onProcessOverrideDimensions = this._onProcessOverrideDimensions.event; - private readonly _onProcessResolvedShellLaunchConfig = this._register(new Emitter()); - readonly onProcessResolvedShellLaunchConfig = this._onProcessResolvedShellLaunchConfig.event; - private readonly _onProcessDidChangeHasChildProcesses = this._register(new Emitter()); - readonly onProcessDidChangeHasChildProcesses = this._onProcessDidChangeHasChildProcesses.event; private readonly _onEnvironmentVariableInfoChange = this._register(new Emitter()); readonly onEnvironmentVariableInfoChanged = this._onEnvironmentVariableInfoChange.event; @@ -324,23 +314,16 @@ export class TerminalProcessManager extends Disposable implements ITerminalProce this._preLaunchInputQueue.length = 0; } }), - newProcess.onProcessTitleChanged(title => this._onProcessTitle.fire(title)), - newProcess.onProcessShellTypeChanged(type => this._onProcessShellTypeChanged.fire(type)), - newProcess.onProcessExit(exitCode => this._onExit(exitCode)), - newProcess.onDidChangeProperty(property => this._onDidChangeProperty.fire(property)) + newProcess.onDidChangeProperty(({ type, value }) => { + switch (type) { + case ProcessPropertyType.HasChildProcesses: + this._hasChildProcesses = value; + case ProcessPropertyType.Exit: + this._onExit(value); + } + this._onDidChangeProperty.fire({ type, value }); + }) ]; - if (newProcess.onProcessOverrideDimensions) { - this._processListeners.push(newProcess.onProcessOverrideDimensions(e => this._onProcessOverrideDimensions.fire(e))); - } - if (newProcess.onProcessResolvedShellLaunchConfig) { - this._processListeners.push(newProcess.onProcessResolvedShellLaunchConfig(e => this._onProcessResolvedShellLaunchConfig.fire(e))); - } - if (newProcess.onDidChangeHasChildProcesses) { - this._processListeners.push(newProcess.onDidChangeHasChildProcesses(e => { - this._hasChildProcesses = e; - this._onProcessDidChangeHasChildProcesses.fire(e); - })); - } setTimeout(() => { if (this.processState === ProcessState.Launching) { diff --git a/src/vs/workbench/contrib/terminal/common/remoteTerminalChannel.ts b/src/vs/workbench/contrib/terminal/common/remoteTerminalChannel.ts index e29b58dcecd..640aade57d9 100644 --- a/src/vs/workbench/contrib/terminal/common/remoteTerminalChannel.ts +++ b/src/vs/workbench/contrib/terminal/common/remoteTerminalChannel.ts @@ -18,7 +18,7 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic import { Schemas } from 'vs/base/common/network'; import { ILabelService } from 'vs/platform/label/common/label'; import { IEnvironmentVariableService, ISerializableEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariable'; -import { IProcessDataEvent, IRequestResolveVariablesEvent, IShellLaunchConfig, IShellLaunchConfigDto, ITerminalDimensionsOverride, ITerminalEnvironment, ITerminalLaunchError, ITerminalProfile, ITerminalsLayoutInfo, ITerminalsLayoutInfoById, TerminalIcon, IProcessProperty, TerminalShellType, ProcessPropertyType, ProcessCapability, IProcessPropertyMap } from 'vs/platform/terminal/common/terminal'; +import { IProcessDataEvent, IRequestResolveVariablesEvent, IShellLaunchConfigDto, ITerminalEnvironment, ITerminalLaunchError, ITerminalProfile, ITerminalsLayoutInfo, ITerminalsLayoutInfoById, TerminalIcon, IProcessProperty, ProcessPropertyType, ProcessCapability, IProcessPropertyMap } from 'vs/platform/terminal/common/terminal'; import { IGetTerminalLayoutInfoArgs, IProcessDetails, IPtyHostProcessReplayEvent, ISetTerminalLayoutInfoArgs } from 'vs/platform/terminal/common/terminalProcess'; import { IProcessEnvironment, OperatingSystem } from 'vs/base/common/platform'; @@ -100,24 +100,9 @@ export class RemoteTerminalChannelClient { get onProcessReplay(): Event<{ id: number, event: IPtyHostProcessReplayEvent }> { return this._channel.listen<{ id: number, event: IPtyHostProcessReplayEvent }>('$onProcessReplayEvent'); } - get onProcessTitleChanged(): Event<{ id: number, event: string }> { - return this._channel.listen<{ id: number, event: string }>('$onProcessTitleChangedEvent'); - } - get onProcessShellTypeChanged(): Event<{ id: number, event: TerminalShellType | undefined }> { - return this._channel.listen<{ id: number, event: TerminalShellType | undefined }>('$onProcessShellTypeChangedEvent'); - } - get onProcessOverrideDimensions(): Event<{ id: number, event: ITerminalDimensionsOverride | undefined }> { - return this._channel.listen<{ id: number, event: ITerminalDimensionsOverride | undefined }>('$onProcessOverrideDimensionsEvent'); - } - get onProcessResolvedShellLaunchConfig(): Event<{ id: number, event: IShellLaunchConfig }> { - return this._channel.listen<{ id: number, event: IShellLaunchConfig }>('$onProcessResolvedShellLaunchConfigEvent'); - } get onProcessOrphanQuestion(): Event<{ id: number }> { return this._channel.listen<{ id: number }>('$onProcessOrphanQuestion'); } - get onProcessDidChangeHasChildProcesses(): Event<{ id: number, event: boolean }> { - return this._channel.listen<{ id: number, event: boolean }>('$onProcessDidChangeHasChildProcesses'); - } get onExecuteCommand(): Event<{ reqId: number, commandId: string, commandArgs: any[] }> { return this._channel.listen<{ reqId: number, commandId: string, commandArgs: any[] }>('$onExecuteCommand'); } diff --git a/src/vs/workbench/contrib/terminal/common/terminal.ts b/src/vs/workbench/contrib/terminal/common/terminal.ts index e427db091a3..14478a7027e 100644 --- a/src/vs/workbench/contrib/terminal/common/terminal.ts +++ b/src/vs/workbench/contrib/terminal/common/terminal.ts @@ -8,7 +8,7 @@ import { Event } from 'vs/base/common/event'; import { IDisposable } from 'vs/base/common/lifecycle'; import { IProcessEnvironment, OperatingSystem } from 'vs/base/common/platform'; import { IExtensionPointDescriptor } from 'vs/workbench/services/extensions/common/extensionsRegistry'; -import { IProcessDataEvent, IProcessReadyEvent, IShellLaunchConfig, ITerminalChildProcess, ITerminalDimensions, ITerminalDimensionsOverride, ITerminalLaunchError, ITerminalProfile, ITerminalProfileObject, ITerminalsLayoutInfo, ITerminalsLayoutInfoById, TerminalIcon, TerminalLocationString, IProcessProperty, TerminalShellType, TitleEventSource, ProcessPropertyType, IFixedTerminalDimensions } from 'vs/platform/terminal/common/terminal'; +import { IProcessDataEvent, IProcessReadyEvent, IShellLaunchConfig, ITerminalChildProcess, ITerminalLaunchError, ITerminalProfile, ITerminalProfileObject, ITerminalsLayoutInfo, ITerminalsLayoutInfoById, TerminalIcon, TerminalLocationString, IProcessProperty, TitleEventSource, ProcessPropertyType, IFixedTerminalDimensions } from 'vs/platform/terminal/common/terminal'; import { IEnvironmentVariableInfo } from 'vs/workbench/contrib/terminal/common/environmentVariable'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { URI } from 'vs/base/common/uri'; @@ -293,12 +293,7 @@ export interface ITerminalProcessManager extends IDisposable { readonly onProcessReady: Event; readonly onBeforeProcessData: Event; readonly onProcessData: Event; - readonly onProcessTitle: Event; - readonly onProcessShellTypeChanged: Event; readonly onProcessExit: Event; - readonly onProcessOverrideDimensions: Event; - readonly onProcessResolvedShellLaunchConfig: Event; - readonly onProcessDidChangeHasChildProcesses: Event; readonly onEnvironmentVariableInfoChanged: Event; readonly onDidChangeProperty: Event>; @@ -344,13 +339,9 @@ export interface ITerminalProcessExtHostProxy extends IDisposable { readonly instanceId: number; emitData(data: string): void; - emitTitle(title: string): void; + emitProcessProperty(property: IProcessProperty): void; emitReady(pid: number, cwd: string): void; emitExit(exitCode: number | undefined): void; - emitOverrideDimensions(dimensions: ITerminalDimensions | undefined): void; - emitResolvedShellLaunchConfig(shellLaunchConfig: IShellLaunchConfig): void; - emitInitialCwd(initialCwd: string): void; - emitCwd(cwd: string): void; emitLatency(latency: number): void; onInput: Event; diff --git a/src/vs/workbench/contrib/terminal/electron-sandbox/localPty.ts b/src/vs/workbench/contrib/terminal/electron-sandbox/localPty.ts index d1db62fc5fb..a233ea9a211 100644 --- a/src/vs/workbench/contrib/terminal/electron-sandbox/localPty.ts +++ b/src/vs/workbench/contrib/terminal/electron-sandbox/localPty.ts @@ -6,8 +6,9 @@ import { Emitter } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; import { ILocalPtyService } from 'vs/platform/terminal/electron-sandbox/terminal'; -import { IProcessDataEvent, IProcessReadyEvent, IShellLaunchConfig, ITerminalChildProcess, ITerminalDimensionsOverride, ITerminalLaunchError, IProcessProperty, IProcessPropertyMap, ProcessPropertyType, TerminalShellType, ProcessCapability } from 'vs/platform/terminal/common/terminal'; +import { IProcessDataEvent, ITerminalChildProcess, ITerminalLaunchError, IProcessProperty, IProcessPropertyMap, ProcessPropertyType, ProcessCapability, IProcessReadyEvent } from 'vs/platform/terminal/common/terminal'; import { IPtyHostProcessReplayEvent } from 'vs/platform/terminal/common/terminalProcess'; +import { URI } from 'vs/base/common/uri'; /** * Responsible for establishing and maintaining a connection with an existing terminal process @@ -18,7 +19,13 @@ export class LocalPty extends Disposable implements ITerminalChildProcess { private _properties: IProcessPropertyMap = { cwd: '', initialCwd: '', - fixedDimensions: { cols: undefined, rows: undefined } + fixedDimensions: { cols: undefined, rows: undefined }, + title: '', + shellType: undefined, + hasChildProcesses: true, + resolvedShellLaunchConfig: {}, + overrideDimensions: undefined, + exit: undefined, }; private _capabilities: ProcessCapability[] = []; get capabilities(): ProcessCapability[] { return this._capabilities; } @@ -26,20 +33,8 @@ export class LocalPty extends Disposable implements ITerminalChildProcess { readonly onProcessData = this._onProcessData.event; private readonly _onProcessReplay = this._register(new Emitter()); readonly onProcessReplay = this._onProcessReplay.event; - private readonly _onProcessExit = this._register(new Emitter()); - readonly onProcessExit = this._onProcessExit.event; private readonly _onProcessReady = this._register(new Emitter()); readonly onProcessReady = this._onProcessReady.event; - private readonly _onProcessTitleChanged = this._register(new Emitter()); - readonly onProcessTitleChanged = this._onProcessTitleChanged.event; - private readonly _onProcessOverrideDimensions = this._register(new Emitter()); - readonly onProcessOverrideDimensions = this._onProcessOverrideDimensions.event; - private readonly _onProcessResolvedShellLaunchConfig = this._register(new Emitter()); - readonly onProcessResolvedShellLaunchConfig = this._onProcessResolvedShellLaunchConfig.event; - private readonly _onProcessShellTypeChanged = this._register(new Emitter()); - readonly onProcessShellTypeChanged = this._onProcessShellTypeChanged.event; - private readonly _onDidChangeHasChildProcesses = this._register(new Emitter()); - readonly onDidChangeHasChildProcesses = this._onDidChangeHasChildProcesses.event; private readonly _onDidChangeProperty = this._register(new Emitter>()); readonly onDidChangeProperty = this._onDidChangeProperty.event; @@ -107,35 +102,24 @@ export class LocalPty extends Disposable implements ITerminalChildProcess { handleData(e: string | IProcessDataEvent) { this._onProcessData.fire(e); } - handleExit(e: number | undefined) { - this._onProcessExit.fire(e); - } handleReady(e: IProcessReadyEvent) { this._capabilities = e.capabilities; this._onProcessReady.fire(e); } - handleTitleChanged(e: string) { - this._onProcessTitleChanged.fire(e); - } - handleShellTypeChanged(e: TerminalShellType) { - this._onProcessShellTypeChanged.fire(e); - } - handleOverrideDimensions(e: ITerminalDimensionsOverride | undefined) { - this._onProcessOverrideDimensions.fire(e); - } - handleResolvedShellLaunchConfig(e: IShellLaunchConfig) { - this._onProcessResolvedShellLaunchConfig.fire(e); - } - handleDidChangeHasChildProcesses(e: boolean) { - this._onDidChangeHasChildProcesses.fire(e); - } - handleDidChangeProperty(e: IProcessProperty) { - if (e.type === ProcessPropertyType.Cwd) { - this._properties.cwd = e.value; - } else if (e.type === ProcessPropertyType.InitialCwd) { - this._properties.initialCwd = e.value; + handleDidChangeProperty({ type, value }: IProcessProperty) { + switch (type) { + case ProcessPropertyType.Cwd: + this._properties.cwd = value; + break; + case ProcessPropertyType.InitialCwd: + this._properties.initialCwd = value; + break; + case ProcessPropertyType.ResolvedShellLaunchConfig: + if (value.cwd && typeof value.cwd !== 'string') { + value.cwd = URI.revive(value.cwd); + } } - this._onDidChangeProperty.fire(e); + this._onDidChangeProperty.fire({ type, value }); } async handleReplay(e: IPtyHostProcessReplayEvent) { @@ -144,7 +128,7 @@ export class LocalPty extends Disposable implements ITerminalChildProcess { for (const innerEvent of e.events) { if (innerEvent.cols !== 0 || innerEvent.rows !== 0) { // never override with 0x0 as that is a marker for an unknown initial size - this._onProcessOverrideDimensions.fire({ cols: innerEvent.cols, rows: innerEvent.rows, forceExactSize: true }); + this._onDidChangeProperty.fire({ type: ProcessPropertyType.OverrideDimensions, value: { cols: innerEvent.cols, rows: innerEvent.rows, forceExactSize: true } }); } const e: IProcessDataEvent = { data: innerEvent.data, trackCommit: true }; this._onProcessData.fire(e); @@ -155,7 +139,7 @@ export class LocalPty extends Disposable implements ITerminalChildProcess { } // remove size override - this._onProcessOverrideDimensions.fire(undefined); + this._onDidChangeProperty.fire({ type: ProcessPropertyType.OverrideDimensions, value: undefined }); } handleOrphanQuestion() { diff --git a/src/vs/workbench/contrib/terminal/electron-sandbox/localTerminalService.ts b/src/vs/workbench/contrib/terminal/electron-sandbox/localTerminalService.ts index e7bfeb298a9..c1ecd823955 100644 --- a/src/vs/workbench/contrib/terminal/electron-sandbox/localTerminalService.ts +++ b/src/vs/workbench/contrib/terminal/electron-sandbox/localTerminalService.ts @@ -57,19 +57,16 @@ export class LocalTerminalService extends Disposable implements ILocalTerminalSe // Attach process listeners this._localPtyService.onProcessData(e => this._ptys.get(e.id)?.handleData(e.event)); - this._localPtyService.onProcessExit(e => { - const pty = this._ptys.get(e.id); - if (pty) { - pty.handleExit(e.event); - this._ptys.delete(e.id); + this._localPtyService.onDidChangeProperty(e => { + if (e.property.type === ProcessPropertyType.Exit) { + const pty = this._ptys.get(e.id); + if (pty) { + this._ptys.delete(e.id); + } } + this._ptys.get(e.id)?.handleDidChangeProperty(e.property); }); this._localPtyService.onProcessReady(e => this._ptys.get(e.id)?.handleReady(e.event)); - this._localPtyService.onProcessTitleChanged(e => this._ptys.get(e.id)?.handleTitleChanged(e.event)); - this._localPtyService.onProcessOverrideDimensions(e => this._ptys.get(e.id)?.handleOverrideDimensions(e.event)); - this._localPtyService.onProcessResolvedShellLaunchConfig(e => this._ptys.get(e.id)?.handleResolvedShellLaunchConfig(e.event)); - this._localPtyService.onProcessDidChangeHasChildProcesses(e => this._ptys.get(e.id)?.handleDidChangeHasChildProcesses(e.event)); - this._localPtyService.onDidChangeProperty(e => this._ptys.get(e.id)?.handleDidChangeProperty(e.property)); this._localPtyService.onProcessReplay(e => this._ptys.get(e.id)?.handleReplay(e.event)); this._localPtyService.onProcessOrphanQuestion(e => this._ptys.get(e.id)?.handleOrphanQuestion()); this._localPtyService.onDidRequestDetach(e => this._onDidRequestDetach.fire(e)); diff --git a/src/vs/workbench/contrib/testing/browser/testingOutputTerminalService.ts b/src/vs/workbench/contrib/testing/browser/testingOutputTerminalService.ts index 96f0f8e76a9..cfe41da20b7 100644 --- a/src/vs/workbench/contrib/testing/browser/testingOutputTerminalService.ts +++ b/src/vs/workbench/contrib/testing/browser/testingOutputTerminalService.ts @@ -10,7 +10,7 @@ import { listenStream } from 'vs/base/common/stream'; import { isDefined } from 'vs/base/common/types'; import { localize } from 'vs/nls'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; -import { IProcessDataEvent, IShellLaunchConfig, ITerminalChildProcess, ITerminalDimensionsOverride, ITerminalLaunchError, ProcessCapability, ProcessPropertyType, TerminalLocation, TerminalShellType } from 'vs/platform/terminal/common/terminal'; +import { IProcessDataEvent, IProcessPropertyMap, IShellLaunchConfig, ITerminalChildProcess, ITerminalDimensionsOverride, ITerminalLaunchError, ProcessCapability, ProcessPropertyType, TerminalLocation, TerminalShellType } from 'vs/platform/terminal/common/terminal'; import { IViewsService } from 'vs/workbench/common/views'; import { ITerminalEditorService, ITerminalGroupService, ITerminalInstance, ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal'; import { TERMINAL_VIEW_ID } from 'vs/workbench/contrib/terminal/common/terminal'; @@ -157,9 +157,6 @@ export class TestingOutputTerminalService implements ITestingOutputTerminalServi } class TestOutputProcess extends Disposable implements ITerminalChildProcess { - updateProperty(property: ProcessPropertyType, value: any): Promise { - throw new Error('Method not implemented.'); - } onProcessOverrideDimensions?: Event | undefined; onProcessResolvedShellLaunchConfig?: Event | undefined; onDidChangeHasChildProcesses?: Event | undefined; @@ -238,8 +235,12 @@ class TestOutputProcess extends Disposable implements ITerminalChildProcess { return Promise.resolve(0); } - refreshProperty(property: ProcessPropertyType) { - return Promise.resolve(''); + public refreshProperty(property: ProcessPropertyType): Promise { + throw new Error(`refreshProperty is not suppported in TestOutputProcesses. property: ${property}`); + } + + public updateProperty(property: ProcessPropertyType, value: any): Promise { + throw new Error(`updateProperty is not suppported in TestOutputProcesses. property: ${property}, value: ${value}`); } //#endregion }