diff --git a/src/vs/workbench/api/browser/mainThreadTerminalService.ts b/src/vs/workbench/api/browser/mainThreadTerminalService.ts index d299d8fabd9..f437285b00d 100644 --- a/src/vs/workbench/api/browser/mainThreadTerminalService.ts +++ b/src/vs/workbench/api/browser/mainThreadTerminalService.ts @@ -63,20 +63,20 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape this._onInstanceDimensionsChanged(instance); })); - this._toDispose.add(_terminalService.onInstanceDisposed(instance => this._onTerminalDisposed(instance))); + this._toDispose.add(_terminalService.onDidDisposeInstance(instance => this._onTerminalDisposed(instance))); this._toDispose.add(_terminalService.onInstanceProcessIdReady(instance => this._onTerminalProcessIdReady(instance))); this._toDispose.add(_terminalService.onInstanceDimensionsChanged(instance => this._onInstanceDimensionsChanged(instance))); this._toDispose.add(_terminalService.onInstanceMaximumDimensionsChanged(instance => this._onInstanceMaximumDimensionsChanged(instance))); this._toDispose.add(_terminalService.onInstanceRequestStartExtensionTerminal(e => this._onRequestStartExtensionTerminal(e))); - this._toDispose.add(_terminalService.onActiveInstanceChanged(instance => this._onActiveTerminalChanged(instance ? instance.instanceId : null))); + this._toDispose.add(_terminalService.onDidChangeActiveInstance(instance => this._onActiveTerminalChanged(instance ? instance.instanceId : null))); this._toDispose.add(_terminalService.onInstanceTitleChanged(instance => instance && this._onTitleChanged(instance.instanceId, instance.title))); // Set initial ext host state - this._terminalService.terminalInstances.forEach(t => { + this._terminalService.instances.forEach(t => { this._onTerminalOpened(t); t.processReady.then(() => this._onTerminalProcessIdReady(t)); }); - const activeInstance = this._terminalService.getActiveInstance(); + const activeInstance = this._terminalService.activeInstance; if (activeInstance) { this._proxy.$acceptActiveTerminalChanged(activeInstance.instanceId); } @@ -145,7 +145,7 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape }; let terminal: ITerminalInstance | undefined; if (launchConfig.isSplitTerminal) { - const activeInstance = this._terminalService.getActiveInstance(); + const activeInstance = this._terminalService.activeInstance; if (activeInstance) { terminal = withNullAsUndefined(this._terminalService.splitInstance(activeInstance, shellLaunchConfig)); } @@ -166,7 +166,7 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape public $hide(id: TerminalIdentifier): void { const rendererId = this._getTerminalId(id); - const instance = this._terminalService.getActiveInstance(); + const instance = this._terminalService.activeInstance; if (instance && instance.instanceId === rendererId) { this._terminalService.hidePanel(); } @@ -186,7 +186,7 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape this._onTerminalData(id, data); }); // Send initial events if they exist - this._terminalService.terminalInstances.forEach(t => { + this._terminalService.instances.forEach(t => { t.initialDataEvents?.forEach(d => this._onTerminalData(t.instanceId, d)); }); } @@ -382,9 +382,9 @@ class TerminalDataEventTracker extends Disposable { this._register(this._bufferer = new TerminalDataBufferer(this._callback)); - this._terminalService.terminalInstances.forEach(instance => this._registerInstance(instance)); + this._terminalService.instances.forEach(instance => this._registerInstance(instance)); this._register(this._terminalService.onInstanceCreated(instance => this._registerInstance(instance))); - this._register(this._terminalService.onInstanceDisposed(instance => this._bufferer.stopBuffering(instance.instanceId))); + this._register(this._terminalService.onDidDisposeInstance(instance => this._bufferer.stopBuffering(instance.instanceId))); } private _registerInstance(instance: ITerminalInstance): void { diff --git a/src/vs/workbench/contrib/remote/browser/urlFinder.ts b/src/vs/workbench/contrib/remote/browser/urlFinder.ts index b66495b0157..89352aae11e 100644 --- a/src/vs/workbench/contrib/remote/browser/urlFinder.ts +++ b/src/vs/workbench/contrib/remote/browser/urlFinder.ts @@ -33,13 +33,13 @@ export class UrlFinder extends Disposable { constructor(terminalService: ITerminalService, debugService: IDebugService) { super(); // Terminal - terminalService.terminalInstances.forEach(instance => { + terminalService.instances.forEach(instance => { this.registerTerminalInstance(instance); }); this._register(terminalService.onInstanceCreated(instance => { this.registerTerminalInstance(instance); })); - this._register(terminalService.onInstanceDisposed(instance => { + this._register(terminalService.onDidDisposeInstance(instance => { this.listeners.get(instance)?.dispose(); this.listeners.delete(instance); })); diff --git a/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts b/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts index 01a8407e50e..31e420ae126 100644 --- a/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts +++ b/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts @@ -309,7 +309,7 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { if (!terminalData) { return false; } - const activeTerminalInstance = this.terminalService.getActiveInstance(); + const activeTerminalInstance = this.terminalService.activeInstance; const isPanelShowingTerminal = !!this.viewsService.getActiveViewWithId(TERMINAL_VIEW_ID); return isPanelShowingTerminal && (activeTerminalInstance?.instanceId === terminalData.terminal.instanceId); } @@ -336,7 +336,7 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { if (isTerminalInPanel) { this.previousPanelId = this.panelService.getActivePanel()?.getId(); if (this.previousPanelId === TERMINAL_VIEW_ID) { - this.previousTerminalInstance = this.terminalService.getActiveInstance() ?? undefined; + this.previousTerminalInstance = this.terminalService.activeInstance ?? undefined; } } this.terminalService.setActiveInstance(terminalData.terminal); diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index 4377121734d..1d98964fbc7 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -111,11 +111,11 @@ export interface ICreateTerminalOptions { target?: TerminalLocation; } -export interface ITerminalService { +export interface ITerminalService extends ITerminalInstanceHost { readonly _serviceBrand: undefined; configHelper: ITerminalConfigHelper; - terminalInstances: ITerminalInstance[]; + // TODO: Remove groups - access should be exclusive to group service readonly terminalGroups: readonly ITerminalGroup[]; isProcessSupportRegistered: boolean; readonly connectionState: TerminalConnectionState; @@ -126,20 +126,14 @@ export interface ITerminalService { onActiveGroupChanged: Event; onGroupDisposed: Event; onInstanceCreated: Event; - onInstanceDisposed: Event; onInstanceProcessIdReady: Event; onInstanceDimensionsChanged: Event; onInstanceMaximumDimensionsChanged: Event; onInstanceRequestStartExtensionTerminal: Event; - /** - * An event that fires when a terminal instance is created, disposed of, or shown (in the case of a background terminal) - */ - onInstancesChanged: Event; onInstanceTitleChanged: Event; onInstanceIconChanged: Event; onInstanceColorChanged: Event; onInstancePrimaryStatusChanged: Event; - onActiveInstanceChanged: Event; onDidRegisterProcessSupport: Event; onDidChangeConnectionState: Event; onDidChangeAvailableProfiles: Event; @@ -161,7 +155,6 @@ export interface ITerminalService { getInstanceFromId(terminalId: number): ITerminalInstance | undefined; getInstanceFromIndex(terminalIndex: number): ITerminalInstance; getGroupLabels(): string[]; - getActiveInstance(): ITerminalInstance | undefined; setActiveInstance(terminalInstance: ITerminalInstance): void; getActiveOrCreateInstance(): ITerminalInstance; splitInstance(instance: ITerminalInstance, shell?: IShellLaunchConfig, cwd?: string | URI): ITerminalInstance | null; @@ -243,27 +236,24 @@ export interface ITerminalEditorService { * This service is responsible for managing terminal groups, that is the terminals that are hosted * within the terminal panel, not in an editor. */ -export interface ITerminalGroupService { +export interface ITerminalGroupService extends ITerminalInstanceHost { readonly _serviceBrand: undefined; readonly groups: readonly ITerminalGroup[]; readonly activeGroup: ITerminalGroup | undefined; readonly activeGroupIndex: number; - readonly instances: readonly ITerminalInstance[]; - readonly activeInstance: ITerminalInstance | undefined; readonly activeInstanceIndex: number; // TODO: Review which methods can be made private + // TODO: Create ITerminalGroupHost and ITerminalInstanceHost interfaces that hold the events, + // create helper functions to setup event forwarding + readonly onDidChangeActiveGroup: Event; readonly onDidDisposeGroup: Event; /** Fires when a group is created, disposed of, or shown (in the case of a background group). */ readonly onDidChangeGroups: Event; - readonly onDidDisposeInstance: Event; - readonly onDidChangeActiveInstance: Event; - readonly onDidChangeInstances: Event; - readonly onPanelOrientationChanged: Event; createGroup(slcOrInstance?: IShellLaunchConfig | ITerminalInstance): ITerminalGroup; @@ -286,6 +276,19 @@ export interface ITerminalGroupService { setContainer(container: HTMLElement): void; } +/** + * An interface that indicates the implementer hosts terminal instances, exposing a common set of + * properties and events. + */ +export interface ITerminalInstanceHost { + readonly instances: readonly ITerminalInstance[]; + readonly activeInstance: ITerminalInstance | undefined; + + readonly onDidDisposeInstance: Event; + readonly onDidChangeActiveInstance: Event; + readonly onDidChangeInstances: Event; +} + export interface IRemoteTerminalService extends IOffProcessTerminalService { createProcess(shellLaunchConfig: IShellLaunchConfig, configuration: ICompleteTerminalConfiguration, activeWorkspaceRootUri: URI | undefined, cols: number, rows: number, shouldPersist: boolean, configHelper: ITerminalConfigHelper): Promise; } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts index f4936844605..a86c2407adc 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts @@ -153,7 +153,7 @@ export function registerTerminalActions() { const commandService = accessor.get(ICommandService); const folders = workspaceContextService.getWorkspace().folders; if (event instanceof MouseEvent && (event.altKey || event.ctrlKey)) { - const activeInstance = terminalService.getActiveInstance(); + const activeInstance = terminalService.activeInstance; if (activeInstance) { const cwd = await getCwdForSplit(terminalService.configHelper, activeInstance); terminalService.splitInstance(activeInstance, profile, cwd); @@ -549,7 +549,7 @@ export function registerTerminalActions() { }); } run(accessor: ServicesAccessor) { - accessor.get(ITerminalService).getActiveInstance()?.scrollDownLine(); + accessor.get(ITerminalService).activeInstance?.scrollDownLine(); } }); registerAction2(class extends Action2 { @@ -569,7 +569,7 @@ export function registerTerminalActions() { }); } run(accessor: ServicesAccessor) { - accessor.get(ITerminalService).getActiveInstance()?.scrollDownPage(); + accessor.get(ITerminalService).activeInstance?.scrollDownPage(); } }); registerAction2(class extends Action2 { @@ -589,7 +589,7 @@ export function registerTerminalActions() { }); } run(accessor: ServicesAccessor) { - accessor.get(ITerminalService).getActiveInstance()?.scrollToBottom(); + accessor.get(ITerminalService).activeInstance?.scrollToBottom(); } }); registerAction2(class extends Action2 { @@ -609,7 +609,7 @@ export function registerTerminalActions() { }); } run(accessor: ServicesAccessor) { - accessor.get(ITerminalService).getActiveInstance()?.scrollUpLine(); + accessor.get(ITerminalService).activeInstance?.scrollUpLine(); } }); registerAction2(class extends Action2 { @@ -629,7 +629,7 @@ export function registerTerminalActions() { }); } run(accessor: ServicesAccessor) { - accessor.get(ITerminalService).getActiveInstance()?.scrollUpPage(); + accessor.get(ITerminalService).activeInstance?.scrollUpPage(); } }); registerAction2(class extends Action2 { @@ -649,7 +649,7 @@ export function registerTerminalActions() { }); } run(accessor: ServicesAccessor) { - accessor.get(ITerminalService).getActiveInstance()?.scrollToTop(); + accessor.get(ITerminalService).activeInstance?.scrollToTop(); } }); registerAction2(class extends Action2 { @@ -668,7 +668,7 @@ export function registerTerminalActions() { }); } run(accessor: ServicesAccessor) { - accessor.get(ITerminalService).getActiveInstance()?.navigationMode?.exitNavigationMode(); + accessor.get(ITerminalService).activeInstance?.navigationMode?.exitNavigationMode(); } }); registerAction2(class extends Action2 { @@ -690,7 +690,7 @@ export function registerTerminalActions() { }); } run(accessor: ServicesAccessor) { - accessor.get(ITerminalService).getActiveInstance()?.navigationMode?.focusPreviousLine(); + accessor.get(ITerminalService).activeInstance?.navigationMode?.focusPreviousLine(); } }); registerAction2(class extends Action2 { @@ -712,7 +712,7 @@ export function registerTerminalActions() { }); } run(accessor: ServicesAccessor) { - accessor.get(ITerminalService).getActiveInstance()?.navigationMode?.focusNextLine(); + accessor.get(ITerminalService).activeInstance?.navigationMode?.focusNextLine(); } }); registerAction2(class extends Action2 { @@ -731,7 +731,7 @@ export function registerTerminalActions() { }); } run(accessor: ServicesAccessor) { - const terminalInstance = accessor.get(ITerminalService).getActiveInstance(); + const terminalInstance = accessor.get(ITerminalService).activeInstance; if (terminalInstance && terminalInstance.hasSelection()) { terminalInstance.clearSelection(); } @@ -748,7 +748,7 @@ export function registerTerminalActions() { }); } async run(accessor: ServicesAccessor) { - return accessor.get(ITerminalService).getActiveInstance()?.changeIcon(); + return accessor.get(ITerminalService).activeInstance?.changeIcon(); } }); registerAction2(class extends Action2 { @@ -776,7 +776,7 @@ export function registerTerminalActions() { }); } async run(accessor: ServicesAccessor) { - return accessor.get(ITerminalService).getActiveInstance()?.changeColor(); + return accessor.get(ITerminalService).activeInstance?.changeColor(); } }); registerAction2(class extends Action2 { @@ -804,7 +804,7 @@ export function registerTerminalActions() { }); } async run(accessor: ServicesAccessor) { - return accessor.get(ITerminalService).getActiveInstance()?.rename(); + return accessor.get(ITerminalService).activeInstance?.rename(); } }); registerAction2(class extends Action2 { @@ -901,7 +901,7 @@ export function registerTerminalActions() { } async run(accessor: ServicesAccessor) { const terminalService = accessor.get(ITerminalService); - await terminalService.getActiveInstance()?.detachFromProcess(); + await terminalService.activeInstance?.detachFromProcess(); } }); registerAction2(class extends Action2 { @@ -1097,7 +1097,7 @@ export function registerTerminalActions() { }); } run(accessor: ServicesAccessor) { - accessor.get(ITerminalService).getActiveInstance()?.toggleEscapeSequenceLogging(); + accessor.get(ITerminalService).activeInstance?.toggleEscapeSequenceLogging(); } }); registerAction2(class extends Action2 { @@ -1201,7 +1201,7 @@ export function registerTerminalActions() { notificationService.warn(localize('workbench.action.terminal.renameWithArg.noName', "No name argument provided")); return; } - accessor.get(ITerminalService).getActiveInstance()?.setTitle(args.name, TitleEventSource.Api); + accessor.get(ITerminalService).activeInstance?.setTitle(args.name, TitleEventSource.Api); } }); registerAction2(class extends Action2 { @@ -1339,7 +1339,7 @@ export function registerTerminalActions() { }); } run(accessor: ServicesAccessor) { - const query = accessor.get(ITerminalService).getActiveInstance()?.selection; + const query = accessor.get(ITerminalService).activeInstance?.selection; FindInFilesCommand(accessor, { query } as IFindInFilesArgs); } }); @@ -1354,7 +1354,7 @@ export function registerTerminalActions() { }); } run(accessor: ServicesAccessor) { - accessor.get(ITerminalService).getActiveInstance()?.relaunch(); + accessor.get(ITerminalService).activeInstance?.relaunch(); } }); registerAction2(class extends Action2 { @@ -1368,7 +1368,7 @@ export function registerTerminalActions() { }); } run(accessor: ServicesAccessor) { - accessor.get(ITerminalService).getActiveInstance()?.showEnvironmentInfoHover(); + accessor.get(ITerminalService).activeInstance?.showEnvironmentInfoHover(); } }); registerAction2(class extends Action2 { @@ -1542,7 +1542,7 @@ export function registerTerminalActions() { }); } run(accessor: ServicesAccessor) { - accessor.get(ITerminalService).getActiveInstance()?.selectAll(); + accessor.get(ITerminalService).activeInstance?.selectAll(); } }); registerAction2(class extends Action2 { @@ -1567,7 +1567,7 @@ export function registerTerminalActions() { const commandService = accessor.get(ICommandService); const folders = workspaceContextService.getWorkspace().folders; if (event instanceof MouseEvent && (event.altKey || event.ctrlKey)) { - const activeInstance = terminalService.getActiveInstance(); + const activeInstance = terminalService.activeInstance; if (activeInstance) { const cwd = await getCwdForSplit(terminalService.configHelper, activeInstance); terminalService.splitInstance(activeInstance, { cwd }); @@ -1616,7 +1616,7 @@ export function registerTerminalActions() { const terminalService = accessor.get(ITerminalService); await terminalService.doWithActiveInstance(async t => { t.dispose(true); - if (terminalService.terminalInstances.length > 0) { + if (terminalService.instances.length > 0) { await terminalService.showPanel(true); } }); @@ -1651,7 +1651,7 @@ export function registerTerminalActions() { for (const instance of selectedInstances) { terminalService.safeDisposeTerminal(instance); } - if (terminalService.terminalInstances.length > 0) { + if (terminalService.instances.length > 0) { terminalService.focusTabs(); focusNext(accessor); } @@ -1744,7 +1744,7 @@ export function registerTerminalActions() { }); } async run(accessor: ServicesAccessor) { - await accessor.get(ITerminalService).getActiveInstance()?.copySelection(); + await accessor.get(ITerminalService).activeInstance?.copySelection(); } }); } @@ -1768,7 +1768,7 @@ export function registerTerminalActions() { }); } async run(accessor: ServicesAccessor) { - await accessor.get(ITerminalService).getActiveInstance()?.paste(); + await accessor.get(ITerminalService).activeInstance?.paste(); } }); } @@ -1790,7 +1790,7 @@ export function registerTerminalActions() { }); } async run(accessor: ServicesAccessor) { - await accessor.get(ITerminalService).getActiveInstance()?.pasteSelection(); + await accessor.get(ITerminalService).activeInstance?.pasteSelection(); } }); } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalFindWidget.ts b/src/vs/workbench/contrib/terminal/browser/terminalFindWidget.ts index 85eeb1546a9..b2f8eb9a4d6 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalFindWidget.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalFindWidget.ts @@ -29,7 +29,7 @@ export class TerminalFindWidget extends SimpleFindWidget { } find(previous: boolean) { - const instance = this._terminalService.getActiveInstance(); + const instance = this._terminalService.activeInstance; if (instance) { if (previous) { instance.findPrevious(this.inputValue, { regex: this._getRegexValue(), wholeWord: this._getWholeWordValue(), caseSensitive: this._getCaseSensitiveValue() }); @@ -41,7 +41,7 @@ export class TerminalFindWidget extends SimpleFindWidget { override hide() { super.hide(); - const instance = this._terminalService.getActiveInstance(); + const instance = this._terminalService.activeInstance; if (instance) { instance.focus(); } @@ -49,7 +49,7 @@ export class TerminalFindWidget extends SimpleFindWidget { protected _onInputChanged() { // Ignore input changes for now - const instance = this._terminalService.getActiveInstance(); + const instance = this._terminalService.activeInstance; if (instance) { return instance.findPrevious(this.inputValue, { regex: this._getRegexValue(), wholeWord: this._getWholeWordValue(), caseSensitive: this._getCaseSensitiveValue(), incremental: true }); } @@ -57,7 +57,7 @@ export class TerminalFindWidget extends SimpleFindWidget { } protected _onFocusTrackerFocus() { - const instance = this._terminalService.getActiveInstance(); + const instance = this._terminalService.activeInstance; if (instance) { instance.notifyFindWidgetFocusChanged(true); } @@ -65,7 +65,7 @@ export class TerminalFindWidget extends SimpleFindWidget { } protected _onFocusTrackerBlur() { - const instance = this._terminalService.getActiveInstance(); + const instance = this._terminalService.activeInstance; if (instance) { instance.notifyFindWidgetFocusChanged(false); } @@ -81,7 +81,7 @@ export class TerminalFindWidget extends SimpleFindWidget { } findFirst() { - const instance = this._terminalService.getActiveInstance(); + const instance = this._terminalService.activeInstance; if (instance) { if (instance.hasSelection()) { instance.clearSelection(); diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index 1c06ac2799d..81668bc1a7b 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -84,16 +84,14 @@ export class TerminalService implements ITerminalService { private get _terminalInstances(): ITerminalInstance[] { return this._terminalGroups.reduce((p, c) => p.concat(c.terminalInstances), []); } - get terminalInstances(): ITerminalInstance[] { - return this._terminalInstances; - } + get instances(): ITerminalInstance[] { return this._terminalInstances; } private readonly _onActiveGroupChanged = new Emitter(); get onActiveGroupChanged(): Event { return this._onActiveGroupChanged.event; } private readonly _onInstanceCreated = new Emitter(); get onInstanceCreated(): Event { return this._onInstanceCreated.event; } - private readonly _onInstanceDisposed = new Emitter(); - get onInstanceDisposed(): Event { return this._onInstanceDisposed.event; } + private readonly _onDidDisposeInstance = new Emitter(); + get onDidDisposeInstance(): Event { return this._onDidDisposeInstance.event; } private readonly _onInstanceProcessIdReady = new Emitter(); get onInstanceProcessIdReady(): Event { return this._onInstanceProcessIdReady.event; } private readonly _onInstanceLinksReady = new Emitter(); @@ -104,16 +102,16 @@ export class TerminalService implements ITerminalService { get onInstanceDimensionsChanged(): Event { return this._onInstanceDimensionsChanged.event; } private readonly _onInstanceMaximumDimensionsChanged = new Emitter(); get onInstanceMaximumDimensionsChanged(): Event { return this._onInstanceMaximumDimensionsChanged.event; } - private readonly _onInstancesChanged = new Emitter(); - get onInstancesChanged(): Event { return this._onInstancesChanged.event; } + private readonly _onDidChangeInstances = new Emitter(); + get onDidChangeInstances(): Event { return this._onDidChangeInstances.event; } private readonly _onInstanceTitleChanged = new Emitter(); get onInstanceTitleChanged(): Event { return this._onInstanceTitleChanged.event; } private readonly _onInstanceIconChanged = new Emitter(); get onInstanceIconChanged(): Event { return this._onInstanceIconChanged.event; } private readonly _onInstanceColorChanged = new Emitter(); get onInstanceColorChanged(): Event { return this._onInstanceColorChanged.event; } - private readonly _onActiveInstanceChanged = new Emitter(); - get onActiveInstanceChanged(): Event { return this._onActiveInstanceChanged.event; } + private readonly _onDidChangeActiveInstance = new Emitter(); + get onDidChangeActiveInstance(): Event { return this._onDidChangeActiveInstance.event; } private readonly _onInstancePrimaryStatusChanged = new Emitter(); get onInstancePrimaryStatusChanged(): Event { return this._onInstancePrimaryStatusChanged.event; } private readonly _onGroupDisposed = new Emitter(); @@ -197,12 +195,11 @@ export class TerminalService implements ITerminalService { } ); - // the below avoids having to poll routinely. // we update detected profiles when an instance is created so that, // for example, we detect if you've installed a pwsh this.onInstanceCreated(() => this._refreshAvailableProfiles()); - this.onInstancesChanged(() => this._terminalCountContextKey.set(this._terminalInstances.length)); + this.onDidChangeInstances(() => this._terminalCountContextKey.set(this._terminalInstances.length)); this.onGroupsChanged(() => this._terminalGroupCountContextKey.set(this._terminalGroups.length)); this.onInstanceLinksReady(instance => this._setInstanceLinkProviders(instance)); @@ -214,8 +211,8 @@ export class TerminalService implements ITerminalService { this.hidePanel(); } }); - this._terminalGroupService.onDidDisposeInstance(this._onInstanceDisposed.fire, this._onInstanceDisposed); - this._terminalGroupService.onDidChangeInstances(this._onInstancesChanged.fire, this._onInstancesChanged); + this._terminalGroupService.onDidDisposeInstance(this._onDidDisposeInstance.fire, this._onDidDisposeInstance); + this._terminalGroupService.onDidChangeInstances(this._onDidChangeInstances.fire, this._onDidChangeInstances); this._handleInstanceContextKeys(); this._processSupportContextKey = KEYBINDING_CONTEXT_TERMINAL_PROCESS_SUPPORTED.bindTo(this._contextKeyService); @@ -333,7 +330,7 @@ export class TerminalService implements ITerminalService { this.splitInstance(terminalInstance, { attachPersistentProcess: terminalLayout.terminal! }); } }); - const activeInstance = this.terminalInstances.find(t => { + const activeInstance = this.instances.find(t => { return t.shellLaunchConfig.attachPersistentProcess?.id === groupLayout.activePersistentProcessId; }); if (activeInstance) { @@ -351,8 +348,8 @@ export class TerminalService implements ITerminalService { private _attachProcessLayoutListeners(): void { this.onActiveGroupChanged(() => this._saveState()); - this.onActiveInstanceChanged(() => this._saveState()); - this.onInstancesChanged(() => this._saveState()); + this.onDidChangeActiveInstance(() => this._saveState()); + this.onDidChangeInstances(() => this._saveState()); // The state must be updated when the terminal is relaunched, otherwise the persistent // terminal ID will be stale and the process will be leaked. this.onInstanceProcessIdReady(() => this._saveState()); @@ -363,14 +360,13 @@ export class TerminalService implements ITerminalService { private _handleInstanceContextKeys(): void { const terminalIsOpenContext = KEYBINDING_CONTEXT_TERMINAL_IS_OPEN.bindTo(this._contextKeyService); const updateTerminalContextKeys = () => { - terminalIsOpenContext.set(this.terminalInstances.length > 0); + terminalIsOpenContext.set(this.instances.length > 0); }; - this.onInstancesChanged(() => updateTerminalContextKeys()); + this.onDidChangeInstances(() => updateTerminalContextKeys()); } getActiveOrCreateInstance(): ITerminalInstance { - const activeInstance = this.getActiveInstance(); - return activeInstance ? activeInstance : this.createTerminal(); + return this.activeInstance || this.createTerminal(); } async setEditable(instance: ITerminalInstance, data?: IEditableData | null): Promise { @@ -428,7 +424,7 @@ export class TerminalService implements ITerminalService { } private _onBeforeShutdown(reason: ShutdownReason): boolean | Promise { - if (this.terminalInstances.length === 0) { + if (this.instances.length === 0) { // No terminal instances, don't veto return false; } @@ -456,12 +452,12 @@ export class TerminalService implements ITerminalService { // Don't touch processes if the shutdown was a result of reload as they will be reattached const shouldPersistTerminals = this._configHelper.config.enablePersistentSessions && e.reason === ShutdownReason.RELOAD; if (shouldPersistTerminals) { - this.terminalInstances.forEach(instance => instance.detachFromProcess()); + this.instances.forEach(instance => instance.detachFromProcess()); return; } // Force dispose of all terminal instances - this.terminalInstances.forEach(instance => instance.dispose(true)); + this.instances.forEach(instance => instance.dispose(true)); this._localTerminalService?.setTerminalLayoutInfo(undefined); } @@ -507,13 +503,13 @@ export class TerminalService implements ITerminalService { this._onActiveGroupChanged.fire(); } - getActiveInstance(): ITerminalInstance | undefined { + get activeInstance(): ITerminalInstance | undefined { // TODO: Get the active instance from the latest activated group or editor return this._terminalGroupService.activeInstance; } doWithActiveInstance(callback: (terminal: ITerminalInstance) => T): T | void { - const instance = this.getActiveInstance(); + const instance = this.activeInstance; if (instance) { return callback(instance); } @@ -530,14 +526,14 @@ export class TerminalService implements ITerminalService { return this._backgroundedTerminalInstances[bgIndex]; } try { - return this.terminalInstances[this._getIndexFromId(terminalId)]; + return this.instances[this._getIndexFromId(terminalId)]; } catch { return undefined; } } getInstanceFromIndex(terminalIndex: number): ITerminalInstance { - return this.terminalInstances[terminalIndex]; + return this.instances[terminalIndex]; } setActiveInstance(terminalInstance: ITerminalInstance): void { @@ -554,7 +550,7 @@ export class TerminalService implements ITerminalService { } isAttachedToTerminal(remoteTerm: IRemoteTerminalAttachTarget): boolean { - return this.terminalInstances.some(term => term.processId === remoteTerm.pid); + return this.instances.some(term => term.processId === remoteTerm.pid); } async initializeTerminals(): Promise { @@ -636,7 +632,7 @@ export class TerminalService implements ITerminalService { this.setActiveInstance(instances[0]); // Fire events - this._onInstancesChanged.fire(); + this._onDidChangeInstances.fire(); if (!wasActiveGroup) { this._onActiveGroupChanged.fire(); } @@ -709,7 +705,7 @@ export class TerminalService implements ITerminalService { } // Fire events - this._onInstancesChanged.fire(); + this._onDidChangeInstances.fire(); // this._onGroupsChanged.fire(); this._onActiveGroupChanged.fire(); } @@ -729,7 +725,7 @@ export class TerminalService implements ITerminalService { } })); instance.addDisposable(instance.onMaximumDimensionsChanged(() => this._onInstanceMaximumDimensionsChanged.fire(instance))); - instance.addDisposable(instance.onFocus(this._onActiveInstanceChanged.fire, this._onActiveInstanceChanged)); + instance.addDisposable(instance.onFocus(this._onDidChangeActiveInstance.fire, this._onDidChangeActiveInstance)); instance.addDisposable(instance.onRequestAddInstanceToGroup(e => { const instanceId = TerminalInstance.getInstanceIdFromUri(e.uri); if (instanceId === undefined) { @@ -761,7 +757,7 @@ export class TerminalService implements ITerminalService { registerLinkProvider(linkProvider: ITerminalExternalLinkProvider): IDisposable { const disposables: IDisposable[] = []; this._linkProviders.add(linkProvider); - for (const instance of this.terminalInstances) { + for (const instance of this.instances) { if (instance.areLinksReady) { disposables.push(instance.registerLinkProvider(linkProvider)); } @@ -820,7 +816,7 @@ export class TerminalService implements ITerminalService { // Do the focus call asynchronously as going through the // command palette will force editor focus await timeout(0); - const instance = this.getActiveInstance(); + const instance = this.activeInstance; if (instance) { await instance.focusWhenReady(true); } @@ -842,7 +838,7 @@ export class TerminalService implements ITerminalService { private _getIndexFromId(terminalId: number): number { let terminalIndex = -1; - this.terminalInstances.forEach((terminalInstance, i) => { + this.instances.forEach((terminalInstance, i) => { if (terminalInstance.instanceId === terminalId) { terminalIndex = i; } @@ -855,10 +851,10 @@ export class TerminalService implements ITerminalService { protected async _showTerminalCloseConfirmation(singleTerminal?: boolean): Promise { let message: string; - if (this.terminalInstances.length === 1 || singleTerminal) { + if (this.instances.length === 1 || singleTerminal) { message = nls.localize('terminalService.terminalCloseConfirmationSingular', "There is an active terminal session, do you want to kill it?"); } else { - message = nls.localize('terminalService.terminalCloseConfirmationPlural', "There are {0} active terminal sessions, do you want to kill them?", this.terminalInstances.length); + message = nls.localize('terminalService.terminalCloseConfirmationPlural', "There are {0} active terminal sessions, do you want to kill them?", this.instances.length); } const res = await this._dialogService.confirm({ message, @@ -945,7 +941,7 @@ export class TerminalService implements ITerminalService { return; } if (type === 'createInstance') { - const activeInstance = this.getActiveInstance(); + const activeInstance = this.activeInstance; let instance; if ('id' in value.profile) { @@ -1001,7 +997,7 @@ export class TerminalService implements ITerminalService { try { await profileProvider.createContributedTerminalProfile(isSplitTerminal); this._terminalGroupService.setActiveInstanceByIndex(this._terminalInstances.length - 1); - await this.getActiveInstance()?.focusWhenReady(); + await this.activeInstance?.focusWhenReady(); } catch (e) { this._notificationService.error(e.message); } @@ -1102,7 +1098,7 @@ export class TerminalService implements ITerminalService { instance = this.createInstance(shellLaunchConfig); this._terminalEditorService.createEditor(instance); this._initInstanceListeners(instance); - this._onInstancesChanged.fire(); + this._onDidChangeInstances.fire(); } else { const group = this._terminalGroupService.createGroup(shellLaunchConfig); // const terminalGroup = this._instantiationService.createInstance(TerminalGroup, this._terminalContainer, shellLaunchConfig); @@ -1114,11 +1110,11 @@ export class TerminalService implements ITerminalService { // terminalGroup.addDisposable(terminalGroup.onDisposed(this._onGroupDisposed.fire, this._onGroupDisposed)); // terminalGroup.addDisposable(terminalGroup.onInstancesChanged(this._onInstancesChanged.fire, this._onInstancesChanged)); this._initInstanceListeners(instance); - this._onInstancesChanged.fire(); + this._onDidChangeInstances.fire(); // this._onGroupsChanged.fire(); } - if (this.terminalInstances.length === 1) { + if (this.instances.length === 1) { // It's the first instance so it should be made active automatically, this must fire // after onInstancesChanged so consumers can react to the instance being added first this._terminalGroupService.setActiveInstanceByIndex(0); @@ -1132,11 +1128,11 @@ export class TerminalService implements ITerminalService { this._terminalGroupService.createGroup(instance); // Make active automatically if it's the first instance - if (this.terminalInstances.length === 1) { + if (this.instances.length === 1) { this._terminalGroupService.setActiveInstanceByIndex(0); } - this._onInstancesChanged.fire(); + this._onDidChangeInstances.fire(); this._onGroupsChanged.fire(); } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalTabbedView.ts b/src/vs/workbench/contrib/terminal/browser/terminalTabbedView.ts index a96011fcb44..b9bf33c1eb0 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalTabbedView.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalTabbedView.ts @@ -129,7 +129,7 @@ export class TerminalTabbedView extends Disposable { } } }); - this._register(this._terminalService.onInstancesChanged(() => this._refreshShowTabs())); + this._register(this._terminalService.onDidChangeInstances(() => this._refreshShowTabs())); this._register(this._terminalGroupService.onDidChangeGroups(() => this._refreshShowTabs())); this._register(this._themeService.onDidColorThemeChange(theme => this._updateTheme(theme))); this._updateTheme(); @@ -159,7 +159,7 @@ export class TerminalTabbedView extends Disposable { return true; } - if (hide === 'singleTerminal' && this._terminalService.terminalInstances.length > 1) { + if (hide === 'singleTerminal' && this._terminalService.instances.length > 1) { return true; } @@ -209,7 +209,7 @@ export class TerminalTabbedView extends Disposable { if (ctx) { const style = window.getComputedStyle(this._tabListElement); ctx.font = `${style.fontStyle} ${style.fontSize} ${style.fontFamily}`; - const maxInstanceWidth = this._terminalService.terminalInstances.reduce((p, c) => { + const maxInstanceWidth = this._terminalService.instances.reduce((p, c) => { return Math.max(p, ctx.measureText(c.title + (c.shellLaunchConfig.description || '')).width + this._getAdditionalWidth(c)); }, 0); idealWidth = Math.ceil(Math.max(maxInstanceWidth, TerminalTabsListSizes.WideViewMinimumWidth)); @@ -343,21 +343,21 @@ export class TerminalTabbedView extends Disposable { event.stopPropagation(); })); this._register(dom.addDisposableListener(terminalContainer, 'mousedown', async (event: MouseEvent) => { - if (this._terminalService.terminalInstances.length === 0) { + if (this._terminalService.instances.length === 0) { return; } if (event.which === 2 && isLinux) { // Drop selection and focus terminal on Linux to enable middle button paste when click // occurs on the selection itself. - const terminal = this._terminalService.getActiveInstance(); + const terminal = this._terminalService.activeInstance; if (terminal) { terminal.focus(); } } else if (event.which === 3) { const rightClickBehavior = this._terminalService.configHelper.config.rightClickBehavior; if (rightClickBehavior === 'copyPaste' || rightClickBehavior === 'paste') { - const terminal = this._terminalService.getActiveInstance(); + const terminal = this._terminalService.activeInstance; if (!terminal) { return; } @@ -491,7 +491,7 @@ export class TerminalTabbedView extends Disposable { focusFindWidget() { this._findWidgetVisible.set(true); - const activeInstance = this._terminalService.getActiveInstance(); + const activeInstance = this._terminalService.activeInstance; if (activeInstance && activeInstance.hasSelection() && activeInstance.selection!.indexOf('\n') === -1) { this._findWidget!.reveal(activeInstance.selection); } else { @@ -506,7 +506,7 @@ export class TerminalTabbedView extends Disposable { } showFindWidget() { - const activeInstance = this._terminalService.getActiveInstance(); + const activeInstance = this._terminalService.activeInstance; if (activeInstance && activeInstance.hasSelection() && activeInstance.selection!.indexOf('\n') === -1) { this._findWidget!.show(activeInstance.selection); } else { @@ -537,6 +537,6 @@ export class TerminalTabbedView extends Disposable { } private _focus() { - this._terminalService.getActiveInstance()?.focusWhenReady(); + this._terminalService.activeInstance?.focusWhenReady(); } } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalTabsList.ts b/src/vs/workbench/contrib/terminal/browser/terminalTabsList.ts index 579a9cda51c..b264c1cce75 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalTabsList.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalTabsList.ts @@ -100,16 +100,16 @@ export class TerminalTabList extends WorkbenchList { configurationService, keybindingService, ); - this._terminalService.onInstancesChanged(() => this.refresh()); + this._terminalService.onDidChangeInstances(() => this.refresh()); terminalGroupService.onDidChangeGroups(() => this.refresh()); this._terminalService.onInstanceTitleChanged(() => this.refresh()); this._terminalService.onInstanceIconChanged(() => this.refresh()); this._terminalService.onInstancePrimaryStatusChanged(() => this.refresh()); this._terminalService.onDidChangeConnectionState(() => this.refresh()); this._themeService.onDidColorThemeChange(() => this.refresh()); - this._terminalService.onActiveInstanceChanged(e => { + this._terminalService.onDidChangeActiveInstance(e => { if (e && e.target !== TerminalLocation.Editor) { - const i = this._terminalService.terminalInstances.indexOf(e); + const i = this._terminalService.instances.indexOf(e); this.setSelection([i]); this.reveal(i); } @@ -176,7 +176,7 @@ export class TerminalTabList extends WorkbenchList { } refresh(): void { - this.splice(0, this.length, this._terminalService.terminalInstances); + this.splice(0, this.length, this._terminalService.instances.slice()); } private _updateContextKey() { diff --git a/src/vs/workbench/contrib/terminal/browser/terminalView.ts b/src/vs/workbench/contrib/terminal/browser/terminalView.ts index e22983da455..bffc1e882ef 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalView.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalView.ts @@ -283,11 +283,11 @@ export class TerminalViewPane extends ViewPane { } private _focus() { - this._terminalService.getActiveInstance()?.focusWhenReady(); + this._terminalService.activeInstance?.focusWhenReady(); } override shouldShowWelcome(): boolean { - this._isWelcomeShowing = !this._terminalService.isProcessSupportRegistered && this._terminalService.terminalInstances.length === 0; + this._isWelcomeShowing = !this._terminalService.isProcessSupportRegistered && this._terminalService.instances.length === 0; return this._isWelcomeShowing; } } @@ -321,9 +321,9 @@ class SwitchTerminalActionViewItem extends SelectActionViewItem { @IContextViewService contextViewService: IContextViewService ) { super(null, action, getTerminalSelectOpenItems(_terminalService), _terminalGroupService.activeGroupIndex, contextViewService, { ariaLabel: nls.localize('terminals', 'Open Terminals.'), optionsAsChildren: true }); - this._register(_terminalService.onInstancesChanged(() => this._updateItems(), this)); + this._register(_terminalService.onDidChangeInstances(() => this._updateItems(), this)); this._register(_terminalService.onActiveGroupChanged(() => this._updateItems(), this)); - this._register(_terminalService.onActiveInstanceChanged(() => this._updateItems(), this)); + this._register(_terminalService.onDidChangeActiveInstance(() => this._updateItems(), this)); this._register(_terminalService.onInstanceTitleChanged(() => this._updateItems(), this)); this._register(_terminalGroupService.onDidChangeGroups(() => this._updateItems(), this)); // TODO: dispose group shouldn't be needed @@ -380,8 +380,8 @@ class SingleTerminalTabActionViewItem extends MenuEntryActionViewItem { super(new MenuItemAction( { id: action.id, - title: getSingleTabLabel(_terminalService.getActiveInstance()), - tooltip: getSingleTabTooltip(_terminalService.getActiveInstance()) + title: getSingleTabLabel(_terminalService.activeInstance), + tooltip: getSingleTabTooltip(_terminalService.activeInstance) }, { id: TerminalCommandId.Split, @@ -394,15 +394,15 @@ class SingleTerminalTabActionViewItem extends MenuEntryActionViewItem { ), keybindingService, notificationService); this._register(this._terminalService.onInstancePrimaryStatusChanged(() => this.updateLabel())); - this._register(this._terminalService.onActiveInstanceChanged(() => this.updateLabel())); + this._register(this._terminalService.onDidChangeActiveInstance(() => this.updateLabel())); this._register(this._terminalService.onInstanceTitleChanged(e => { - if (e === this._terminalService.getActiveInstance()) { + if (e === this._terminalService.activeInstance) { this._action.tooltip = getSingleTabTooltip(e); this.updateLabel(); } })); this._register(this._terminalService.onInstanceIconChanged(e => { - if (e === this._terminalService.getActiveInstance()) { + if (e === this._terminalService.activeInstance) { this.updateLabel(); } })); @@ -429,14 +429,14 @@ class SingleTerminalTabActionViewItem extends MenuEntryActionViewItem { // Middle click kills this._elementDisposables.push(dom.addDisposableListener(this.element!, dom.EventType.AUXCLICK, e => { if (e.button === 1) { - this._terminalService.getActiveInstance()?.dispose(); + this._terminalService.activeInstance?.dispose(); e.preventDefault(); } })); } if (this.label) { const label = this.label; - const instance = this._terminalService.getActiveInstance(); + const instance = this._terminalService.activeInstance; if (!instance) { dom.reset(label, ''); return; @@ -540,7 +540,7 @@ class TerminalThemeIconStyle extends Themable { private _registerListeners(): void { this._register(this._terminalService.onInstanceIconChanged(() => this.updateStyles())); this._register(this._terminalService.onInstanceColorChanged(() => this.updateStyles())); - this._register(this._terminalService.onInstancesChanged(() => this.updateStyles())); + this._register(this._terminalService.onDidChangeInstances(() => this.updateStyles())); this._register(this._terminalGroupService.onDidChangeGroups(() => this.updateStyles())); } @@ -552,7 +552,7 @@ class TerminalThemeIconStyle extends Themable { let css = ''; // Add icons - for (const instance of this._terminalService.terminalInstances) { + for (const instance of this._terminalService.instances) { const icon = instance.icon; if (!icon) { continue; @@ -571,7 +571,7 @@ class TerminalThemeIconStyle extends Themable { } // Add colors - for (const instance of this._terminalService.terminalInstances) { + for (const instance of this._terminalService.instances) { const colorClass = getColorClass(instance); if (!colorClass || !instance.color) { continue; diff --git a/src/vs/workbench/contrib/terminal/electron-sandbox/terminalNativeContribution.ts b/src/vs/workbench/contrib/terminal/electron-sandbox/terminalNativeContribution.ts index 651030fe136..ce9cd074027 100644 --- a/src/vs/workbench/contrib/terminal/electron-sandbox/terminalNativeContribution.ts +++ b/src/vs/workbench/contrib/terminal/electron-sandbox/terminalNativeContribution.ts @@ -37,7 +37,7 @@ export class TerminalNativeContribution extends Disposable implements IWorkbench } private _onOsResume(): void { - this._terminalService.terminalInstances.forEach(instance => instance.forceRedraw()); + this._terminalService.instances.forEach(instance => instance.forceRedraw()); } private async _onOpenFileRequest(request: INativeOpenFileRequest): Promise { @@ -49,7 +49,7 @@ export class TerminalNativeContribution extends Disposable implements IWorkbench await this._whenFileDeleted(waitMarkerFileUri); // Focus active terminal - this._terminalService.getActiveInstance()?.focus(); + this._terminalService.activeInstance?.focus(); } } diff --git a/src/vs/workbench/contrib/testing/browser/testingOutputTerminalService.ts b/src/vs/workbench/contrib/testing/browser/testingOutputTerminalService.ts index 3e2cbafbb0c..ad63dc72cdf 100644 --- a/src/vs/workbench/contrib/testing/browser/testingOutputTerminalService.ts +++ b/src/vs/workbench/contrib/testing/browser/testingOutputTerminalService.ts @@ -56,7 +56,7 @@ export class TestingOutputTerminalService implements ITestingOutputTerminalServi // If a result terminal is currently active and we start a new test run, // stream live results there automatically. resultService.onResultsChanged(evt => { - const active = this.terminalService.getActiveInstance(); + const active = this.terminalService.activeInstance; if (!('started' in evt) || !active) { return; } @@ -77,7 +77,7 @@ export class TestingOutputTerminalService implements ITestingOutputTerminalServi * @inheritdoc */ public async open(result: ITestResult | undefined): Promise { - const testOutputPtys = this.terminalService.terminalInstances + const testOutputPtys = this.terminalService.instances .map(t => { const output = this.outputTerminals.get(t); return output ? [t, output] as const : undefined;