From 4cac8a8d8a249c7cb0ed800b26701e70b966e182 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 18 Jun 2021 04:52:35 -0700 Subject: [PATCH 01/31] Create group service Part of #126243 --- .../terminal/browser/terminal.contribution.ts | 4 +++- .../workbench/contrib/terminal/browser/terminal.ts | 11 +++++++++++ .../contrib/terminal/browser/terminalGroupService.ts | 12 ++++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts b/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts index f034d9babd8..26c26d0145e 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts @@ -23,7 +23,7 @@ import { registerColors } from 'vs/workbench/contrib/terminal/common/terminalCol import { setupTerminalCommands } from 'vs/workbench/contrib/terminal/browser/terminalCommands'; import { TerminalService } from 'vs/workbench/contrib/terminal/browser/terminalService'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { IRemoteTerminalService, ITerminalEditorService, ITerminalInstanceService, ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal'; +import { IRemoteTerminalService, ITerminalEditorService, ITerminalGroupService, ITerminalInstanceService, ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { ViewPaneContainer } from 'vs/workbench/browser/parts/views/viewPaneContainer'; import { IQuickAccessRegistry, Extensions as QuickAccessExtensions } from 'vs/platform/quickinput/common/quickAccess'; @@ -43,10 +43,12 @@ import { TerminalInputSerializer, TerminalEditor } from 'vs/workbench/contrib/te import { TerminalEditorInput } from 'vs/workbench/contrib/terminal/browser/terminalEditorInput'; import { terminalStrings } from 'vs/workbench/contrib/terminal/common/terminalStrings'; import { TerminalEditorService } from 'vs/workbench/contrib/terminal/browser/terminalEditorService'; +import { TerminalGroupService } from 'vs/workbench/contrib/terminal/browser/terminalGroupService'; // Register services registerSingleton(ITerminalService, TerminalService, true); registerSingleton(ITerminalEditorService, TerminalEditorService, true); +registerSingleton(ITerminalGroupService, TerminalGroupService, true); registerSingleton(IRemoteTerminalService, RemoteTerminalService); registerSingleton(ITerminalInstanceService, TerminalInstanceService, true); diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index 024ae525949..d544c0cd179 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -22,6 +22,7 @@ import { TerminalEditorInput } from 'vs/workbench/contrib/terminal/browser/termi export const ITerminalService = createDecorator('terminalService'); export const ITerminalEditorService = createDecorator('terminalEditorService'); +export const ITerminalGroupService = createDecorator('terminalGroupService'); export const ITerminalInstanceService = createDecorator('terminalInstanceService'); export const IRemoteTerminalService = createDecorator('remoteTerminalService'); @@ -248,6 +249,16 @@ export interface ITerminalEditorService { detachInstance(instance: ITerminalInstance): void; } +/** + * 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 { + readonly _serviceBrand: undefined; + + readonly terminalInstances: ITerminalInstance[]; +} + 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/terminalGroupService.ts b/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts new file mode 100644 index 00000000000..4ff72bd2701 --- /dev/null +++ b/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts @@ -0,0 +1,12 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { ITerminalGroupService, ITerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminal'; + +export class TerminalGroupService implements ITerminalGroupService { + declare _serviceBrand: undefined; + + terminalInstances: ITerminalInstance[] = []; +} From 3d9fcc36c2027ccd84af4d86b041a494cd9c6de1 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 18 Jun 2021 05:07:15 -0700 Subject: [PATCH 02/31] Add createGroup to group service --- .../contrib/terminal/browser/terminal.ts | 5 ++- .../terminal/browser/terminalGroupService.ts | 44 +++++++++++++++++-- 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index d544c0cd179..9baf26ff44d 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -256,7 +256,10 @@ export interface ITerminalEditorService { export interface ITerminalGroupService { readonly _serviceBrand: undefined; - readonly terminalInstances: ITerminalInstance[]; + readonly instances: readonly ITerminalInstance[]; + readonly groups: readonly ITerminalGroup[]; + + createGroup(): ITerminalGroup; } export interface IRemoteTerminalService extends IOffProcessTerminalService { diff --git a/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts b/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts index 4ff72bd2701..b49b159dcf9 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts @@ -3,10 +3,48 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { ITerminalGroupService, ITerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminal'; +import { Orientation } from 'vs/base/browser/ui/sash/sash'; +import { Emitter, Event } from 'vs/base/common/event'; +import { Disposable } from 'vs/base/common/lifecycle'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { ITerminalGroup, ITerminalGroupService, ITerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminal'; +import { TerminalGroup } from 'vs/workbench/contrib/terminal/browser/terminalGroup'; -export class TerminalGroupService implements ITerminalGroupService { +export class TerminalGroupService extends Disposable implements ITerminalGroupService { declare _serviceBrand: undefined; - terminalInstances: ITerminalInstance[] = []; + instances: ITerminalInstance[] = []; + groups: ITerminalGroup[] = []; + + private _container: HTMLElement | undefined; + + private readonly _onDidDisposeGroup = new Emitter(); + get onDidDisposeGroup(): Event { return this._onDidDisposeGroup.event; } + + private readonly _onDidChangeInstances = new Emitter(); + get onDidChangeInstances(): Event { return this._onDidChangeInstances.event; } + + private readonly _onPanelOrientationChanged = new Emitter(); + get onPanelOrientationChanged(): Event { return this._onPanelOrientationChanged.event; } + + constructor( + @IInstantiationService private readonly _instantiationService: IInstantiationService + ) { + super(); + } + + setContainer(container: HTMLElement) { + this._container = container; + this.groups.forEach(group => group.attachToElement(container)); + } + + createGroup(): ITerminalGroup { + const group = this._instantiationService.createInstance(TerminalGroup, this._container, undefined); + // TODO: Move panel orientation change into this file so it's not fired many times + group.onPanelOrientationChanged((orientation) => this._onPanelOrientationChanged.fire(orientation)); + this.groups.push(group); + group.addDisposable(group.onDisposed(this._onDidDisposeGroup.fire, this._onDidDisposeGroup)); + group.addDisposable(group.onInstancesChanged(this._onDidChangeInstances.fire, this._onDidChangeInstances)); + return group; + } } From 0ca64bc1aa120994e0055b66adfe2147ac25bb60 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 18 Jun 2021 05:32:13 -0700 Subject: [PATCH 03/31] Move more into group service --- .../contrib/terminal/browser/terminal.ts | 22 +++- .../terminal/browser/terminalGroupService.ts | 36 ++++++- .../terminal/browser/terminalService.ts | 101 ++++++++---------- .../terminal/browser/terminalTabsList.ts | 5 +- 4 files changed, 103 insertions(+), 61 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index 9baf26ff44d..c8dea5d3b33 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -116,7 +116,7 @@ export interface ITerminalService { activeGroupIndex: number; configHelper: ITerminalConfigHelper; terminalInstances: ITerminalInstance[]; - terminalGroups: ITerminalGroup[]; + readonly terminalGroups: readonly ITerminalGroup[]; isProcessSupportRegistered: boolean; readonly connectionState: TerminalConnectionState; readonly availableProfiles: ITerminalProfile[]; @@ -176,7 +176,7 @@ export interface ITerminalService { /** * Moves a terminal instance's group to the target instance group's position. */ - moveGroup(source: ITerminalInstance, target: ITerminalInstance): void; + // moveGroup(source: ITerminalInstance, target: ITerminalInstance): void; moveInstance(source: ITerminalInstance, target: ITerminalInstance, side: 'before' | 'after'): void; moveToEditor(source: ITerminalInstance): void; moveToTerminalView(source?: ITerminalInstance): Promise; @@ -259,7 +259,23 @@ export interface ITerminalGroupService { readonly instances: readonly ITerminalInstance[]; readonly groups: readonly ITerminalGroup[]; - createGroup(): ITerminalGroup; + readonly onDidDisposeGroup: Event; + readonly onDidChangeGroups: Event; + readonly onDidChangeInstances: Event; + readonly onPanelOrientationChanged: Event; + + createGroup(slcOrInstance?: IShellLaunchConfig | ITerminalInstance): ITerminalGroup; + // removeGroup(group: ITerminalGroup): void; + + /** + * Moves a terminal instance's group to the target instance group's position. + * @param source The source instance to move. + * @param target The target instance to move the source instance to. + */ + moveGroup(source: ITerminalInstance, target: ITerminalInstance): void; + getGroupForInstance(instance: ITerminalInstance): ITerminalGroup | undefined; + + setContainer(container: HTMLElement): void; } export interface IRemoteTerminalService extends IOffProcessTerminalService { diff --git a/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts b/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts index b49b159dcf9..6bf41a9ddf8 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts @@ -7,6 +7,7 @@ import { Orientation } from 'vs/base/browser/ui/sash/sash'; import { Emitter, Event } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { IShellLaunchConfig } from 'vs/platform/terminal/common/terminal'; import { ITerminalGroup, ITerminalGroupService, ITerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminal'; import { TerminalGroup } from 'vs/workbench/contrib/terminal/browser/terminalGroup'; @@ -20,6 +21,8 @@ export class TerminalGroupService extends Disposable implements ITerminalGroupSe private readonly _onDidDisposeGroup = new Emitter(); get onDidDisposeGroup(): Event { return this._onDidDisposeGroup.event; } + private readonly _onDidChangeGroups = new Emitter(); + get onDidChangeGroups(): Event { return this._onDidChangeGroups.event; } private readonly _onDidChangeInstances = new Emitter(); get onDidChangeInstances(): Event { return this._onDidChangeInstances.event; } @@ -38,13 +41,42 @@ export class TerminalGroupService extends Disposable implements ITerminalGroupSe this.groups.forEach(group => group.attachToElement(container)); } - createGroup(): ITerminalGroup { - const group = this._instantiationService.createInstance(TerminalGroup, this._container, undefined); + createGroup(slcOrInstance?: IShellLaunchConfig | ITerminalInstance): ITerminalGroup { + const group = this._instantiationService.createInstance(TerminalGroup, this._container, slcOrInstance); // TODO: Move panel orientation change into this file so it's not fired many times group.onPanelOrientationChanged((orientation) => this._onPanelOrientationChanged.fire(orientation)); this.groups.push(group); group.addDisposable(group.onDisposed(this._onDidDisposeGroup.fire, this._onDidDisposeGroup)); group.addDisposable(group.onInstancesChanged(this._onDidChangeInstances.fire, this._onDidChangeInstances)); + if (group.terminalInstances.length > 0) { + this._onDidChangeInstances.fire(); + } + this._onDidChangeGroups.fire(); return group; } + + // removeGroup(group: ITerminalGroup): void { + // const index = this.groups.indexOf(group); + // if (index !== -1) { + // this.groups.splice(index, 1); + // this._onDidChangeGroups.fire(); + // } + // } + + moveGroup(source: ITerminalInstance, target: ITerminalInstance): void { + const sourceGroup = this.getGroupForInstance(source); + const targetGroup = this.getGroupForInstance(target); + if (!sourceGroup || !targetGroup) { + return; + } + const sourceGroupIndex = this.groups.indexOf(sourceGroup); + const targetGroupIndex = this.groups.indexOf(targetGroup); + this.groups.splice(sourceGroupIndex, 1); + this.groups.splice(targetGroupIndex, 0, sourceGroup); + this._onDidChangeInstances.fire(); + } + + getGroupForInstance(instance: ITerminalInstance): ITerminalGroup | undefined { + return this.groups.find(group => group.terminalInstances.indexOf(instance) !== -1); + } } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index 3c4a991d6b1..bafdfbe6c37 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -28,10 +28,9 @@ import { registerTerminalDefaultProfileConfiguration } from 'vs/platform/termina import { ThemeIcon } from 'vs/platform/theme/common/themeService'; import { VirtualWorkspaceContext } from 'vs/workbench/browser/contextkeys'; import { IEditableData, IViewDescriptorService, IViewsService, ViewContainerLocation } from 'vs/workbench/common/views'; -import { ICreateTerminalOptions, IRemoteTerminalService, ITerminalEditorService, ITerminalExternalLinkProvider, ITerminalGroup, ITerminalInstance, ITerminalProfileProvider, ITerminalService, TerminalConnectionState } from 'vs/workbench/contrib/terminal/browser/terminal'; +import { ICreateTerminalOptions, IRemoteTerminalService, ITerminalEditorService, ITerminalExternalLinkProvider, ITerminalGroup, ITerminalGroupService, ITerminalInstance, ITerminalProfileProvider, ITerminalService, TerminalConnectionState } from 'vs/workbench/contrib/terminal/browser/terminal'; import { TerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminalConfigHelper'; import { TerminalEditor } from 'vs/workbench/contrib/terminal/browser/terminalEditor'; -import { TerminalGroup } from 'vs/workbench/contrib/terminal/browser/terminalGroup'; import { configureTerminalProfileIcon } from 'vs/workbench/contrib/terminal/browser/terminalIcons'; import { TerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminalInstance'; import { TerminalViewPane } from 'vs/workbench/contrib/terminal/browser/terminalView'; @@ -48,13 +47,14 @@ import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteA export class TerminalService implements ITerminalService { declare _serviceBrand: undefined; + private get _terminalGroups(): readonly ITerminalGroup[] { return this._terminalGroupService.groups; } + private _isShuttingDown: boolean; private _terminalFocusContextKey: IContextKey; private _terminalCountContextKey: IContextKey; private _terminalGroupCountContextKey: IContextKey; private _terminalShellTypeContextKey: IContextKey; private _terminalAltBufferActiveContextKey: IContextKey; - private _terminalGroups: ITerminalGroup[] = []; private _backgroundedTerminalInstances: ITerminalInstance[] = []; private _findState: FindReplaceState; private _activeGroupIndex: number; @@ -68,7 +68,6 @@ export class TerminalService implements ITerminalService { private _profilesReadyBarrier: AutoOpenBarrier; private _availableProfiles: ITerminalProfile[] | undefined; private _configHelper: TerminalConfigHelper; - private _terminalContainer: HTMLElement | undefined; private _remoteTerminalsInitPromise: Promise | undefined; private _localTerminalsInitPromise: Promise | undefined; private _connectionState: TerminalConnectionState; @@ -76,7 +75,7 @@ export class TerminalService implements ITerminalService { private _editable: { instance: ITerminalInstance, data: IEditableData } | undefined; public get activeGroupIndex(): number { return this._activeGroupIndex; } - public get terminalGroups(): ITerminalGroup[] { return this._terminalGroups; } + public get terminalGroups(): readonly ITerminalGroup[] { return this._terminalGroups; } public get isProcessSupportRegistered(): boolean { return !!this._processSupportContextKey.get(); } get connectionState(): TerminalConnectionState { return this._connectionState; } get profilesReady(): Promise { return this._profilesReadyBarrier.wait().then(() => { }); } @@ -150,6 +149,7 @@ export class TerminalService implements ITerminalService { @ITelemetryService private readonly _telemetryService: ITelemetryService, @ITerminalContributionService private readonly _terminalContributionService: ITerminalContributionService, @ITerminalEditorService private readonly _terminalEditorService: ITerminalEditorService, + @ITerminalGroupService private readonly _terminalGroupService: ITerminalGroupService, @IEditorOverrideService editorOverrideService: IEditorOverrideService, @IExtensionService private readonly _extensionService: IExtensionService, @INotificationService private readonly _notificationService: INotificationService, @@ -514,7 +514,8 @@ export class TerminalService implements ITerminalService { const activeGroupIndex = activeGroup ? this._terminalGroups.indexOf(activeGroup) : -1; const wasActiveGroup = group === activeGroup; if (index !== -1) { - this._terminalGroups.splice(index, 1); + // TODO: Remove cast + (this._terminalGroups as ITerminalGroup[]).splice(index, 1); this._onGroupsChanged.fire(); } @@ -709,15 +710,16 @@ export class TerminalService implements ITerminalService { } oldGroup.removeInstance(instance); + this._terminalGroupService.createGroup(instance); - const newGroup = this._instantiationService.createInstance(TerminalGroup, this._terminalContainer, instance); - newGroup.onPanelOrientationChanged((orientation) => this._onPanelOrientationChanged.fire(orientation)); - this._terminalGroups.push(newGroup); + // const newGroup = this._instantiationService.createInstance(TerminalGroup, this._terminalContainer, instance); + // newGroup.onPanelOrientationChanged((orientation) => this._onPanelOrientationChanged.fire(orientation)); + // this._terminalGroups.push(newGroup); - newGroup.addDisposable(newGroup.onDisposed(this._onGroupDisposed.fire, this._onGroupDisposed)); - newGroup.addDisposable(newGroup.onInstancesChanged(this._onInstancesChanged.fire, this._onInstancesChanged)); - this._onInstancesChanged.fire(); - this._onGroupsChanged.fire(); + // newGroup.addDisposable(newGroup.onDisposed(this._onGroupDisposed.fire, this._onGroupDisposed)); + // newGroup.addDisposable(newGroup.onInstancesChanged(this._onInstancesChanged.fire, this._onInstancesChanged)); + // this._onInstancesChanged.fire(); + // this._onGroupsChanged.fire(); } joinInstances(instances: ITerminalInstance[]): void { @@ -735,12 +737,13 @@ export class TerminalService implements ITerminalService { // Create a new group if needed if (!candidateGroup) { - candidateGroup = this._instantiationService.createInstance(TerminalGroup, this._terminalContainer, undefined); - candidateGroup.onPanelOrientationChanged((orientation) => this._onPanelOrientationChanged.fire(orientation)); - this._terminalGroups.push(candidateGroup); - candidateGroup.addDisposable(candidateGroup.onDisposed(this._onGroupDisposed.fire, this._onGroupDisposed)); - candidateGroup.addDisposable(candidateGroup.onInstancesChanged(this._onInstancesChanged.fire, this._onInstancesChanged)); - this._onGroupsChanged.fire(); + candidateGroup = this._terminalGroupService.createGroup(); + // candidateGroup = this._instantiationService.createInstance(TerminalGroup, this._terminalContainer, undefined); + // candidateGroup.onPanelOrientationChanged((orientation) => this._onPanelOrientationChanged.fire(orientation)); + // this._terminalGroups.push(candidateGroup); + // candidateGroup.addDisposable(candidateGroup.onDisposed(this._onGroupDisposed.fire, this._onGroupDisposed)); + // candidateGroup.addDisposable(candidateGroup.onInstancesChanged(this._onInstancesChanged.fire, this._onInstancesChanged)); + // this._onGroupsChanged.fire(); } const wasActiveGroup = this.getActiveGroup() === candidateGroup; @@ -770,19 +773,6 @@ export class TerminalService implements ITerminalService { } } - moveGroup(source: ITerminalInstance, target: ITerminalInstance): void { - const sourceGroup = this.getGroupForInstance(source); - const targetGroup = this.getGroupForInstance(target); - if (!sourceGroup || !targetGroup) { - return; - } - const sourceGroupIndex = this._terminalGroups.indexOf(sourceGroup); - const targetGroupIndex = this._terminalGroups.indexOf(targetGroup); - this._terminalGroups.splice(sourceGroupIndex, 1); - this._terminalGroups.splice(targetGroupIndex, 0, sourceGroup); - this._onInstancesChanged.fire(); - } - moveInstance(source: ITerminalInstance, target: ITerminalInstance, side: 'before' | 'after'): void { const sourceGroup = this.getGroupForInstance(source); const targetGroup = this.getGroupForInstance(target); @@ -834,13 +824,13 @@ export class TerminalService implements ITerminalService { group = this.getGroupForInstance(target); } - // TODO: Share code with joinInstances - move into terminal group service if (!group) { - group = this._instantiationService.createInstance(TerminalGroup, this._terminalContainer, undefined); - group.onPanelOrientationChanged((orientation) => this._onPanelOrientationChanged.fire(orientation)); - this._terminalGroups.push(group); - group.addDisposable(group.onDisposed(this._onGroupDisposed.fire, this._onGroupDisposed)); - group.addDisposable(group.onInstancesChanged(this._onInstancesChanged.fire, this._onInstancesChanged)); + group = this._terminalGroupService.createGroup(); + // group = this._instantiationService.createInstance(TerminalGroup, this._terminalContainer, undefined); + // group.onPanelOrientationChanged((orientation) => this._onPanelOrientationChanged.fire(orientation)); + // this._terminalGroups.push(group); + // group.addDisposable(group.onDisposed(this._onGroupDisposed.fire, this._onGroupDisposed)); + // group.addDisposable(group.onInstancesChanged(this._onInstancesChanged.fire, this._onInstancesChanged)); } group.addInstance(source); @@ -856,7 +846,7 @@ export class TerminalService implements ITerminalService { // Fire events this._onInstancesChanged.fire(); - this._onGroupsChanged.fire(); + // this._onGroupsChanged.fire(); this._onActiveGroupChanged.fire(); } @@ -1245,17 +1235,18 @@ export class TerminalService implements ITerminalService { this._initInstanceListeners(instance); this._onInstancesChanged.fire(); } else { - const terminalGroup = this._instantiationService.createInstance(TerminalGroup, this._terminalContainer, shellLaunchConfig); - this._terminalGroups.push(terminalGroup); - terminalGroup.onPanelOrientationChanged((orientation) => this._onPanelOrientationChanged.fire(orientation)); + const group = this._terminalGroupService.createGroup(shellLaunchConfig); + // const terminalGroup = this._instantiationService.createInstance(TerminalGroup, this._terminalContainer, shellLaunchConfig); + // this._terminalGroups.push(terminalGroup); + // terminalGroup.onPanelOrientationChanged((orientation) => this._onPanelOrientationChanged.fire(orientation)); - instance = terminalGroup.terminalInstances[0]; + instance = group.terminalInstances[0]; - terminalGroup.addDisposable(terminalGroup.onDisposed(this._onGroupDisposed.fire, this._onGroupDisposed)); - terminalGroup.addDisposable(terminalGroup.onInstancesChanged(this._onInstancesChanged.fire, this._onInstancesChanged)); + // 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._onGroupsChanged.fire(); + // this._onGroupsChanged.fire(); } if (this.terminalInstances.length === 1) { @@ -1269,15 +1260,18 @@ export class TerminalService implements ITerminalService { protected _showBackgroundTerminal(instance: ITerminalInstance): void { this._backgroundedTerminalInstances.splice(this._backgroundedTerminalInstances.indexOf(instance), 1); instance.shellLaunchConfig.hideFromUser = false; - const terminalGroup = this._instantiationService.createInstance(TerminalGroup, this._terminalContainer, instance); - this._terminalGroups.push(terminalGroup); - terminalGroup.onPanelOrientationChanged((orientation) => this._onPanelOrientationChanged.fire(orientation)); - terminalGroup.addDisposable(terminalGroup.onDisposed(this._onGroupDisposed.fire, this._onGroupDisposed)); - terminalGroup.addDisposable(terminalGroup.onInstancesChanged(this._onInstancesChanged.fire, this._onInstancesChanged)); + this._terminalGroupService.createGroup(instance); + // const terminalGroup = this._instantiationService.createInstance(TerminalGroup, this._terminalContainer, instance); + // this._terminalGroups.push(terminalGroup); + // terminalGroup.onPanelOrientationChanged((orientation) => this._onPanelOrientationChanged.fire(orientation)); + // terminalGroup.addDisposable(terminalGroup.onDisposed(this._onGroupDisposed.fire, this._onGroupDisposed)); + // terminalGroup.addDisposable(terminalGroup.onInstancesChanged(this._onInstancesChanged.fire, this._onInstancesChanged)); + + // Make active automatically if it's the first instance if (this.terminalInstances.length === 1) { - // It's the first instance so it should be made active automatically this.setActiveInstanceByIndex(0); } + this._onInstancesChanged.fire(); this._onGroupsChanged.fire(); } @@ -1311,8 +1305,7 @@ export class TerminalService implements ITerminalService { async setContainers(panelContainer: HTMLElement, terminalContainer: HTMLElement): Promise { this._configHelper.panelContainer = panelContainer; - this._terminalContainer = terminalContainer; - this._terminalGroups.forEach(group => group.attachToElement(terminalContainer)); + this._terminalGroupService.setContainer(terminalContainer); } hidePanel(): void { diff --git a/src/vs/workbench/contrib/terminal/browser/terminalTabsList.ts b/src/vs/workbench/contrib/terminal/browser/terminalTabsList.ts index 06e4a966f7d..60abad67cd5 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalTabsList.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalTabsList.ts @@ -9,7 +9,7 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IThemeService, ThemeIcon } from 'vs/platform/theme/common/themeService'; -import { ITerminalInstance, ITerminalInstanceService, ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal'; +import { ITerminalGroupService, ITerminalInstance, ITerminalInstanceService, ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal'; import { localize } from 'vs/nls'; import * as DOM from 'vs/base/browser/dom'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -519,6 +519,7 @@ class TerminalTabsDragAndDrop implements IListDragAndDrop { constructor( @ITerminalService private _terminalService: ITerminalService, + @ITerminalGroupService private _terminalGroupService: ITerminalGroupService, @ITerminalInstanceService private _terminalInstanceService: ITerminalInstanceService ) { } @@ -609,7 +610,7 @@ class TerminalTabsDragAndDrop implements IListDragAndDrop { } for (const instance of sourceInstances) { - this._terminalService.moveGroup(instance, targetInstance); + this._terminalGroupService.moveGroup(instance, targetInstance); if (!focused) { this._terminalService.setActiveInstance(instance); focused = true; From 02d93e0af3cc45d8f528bb97af1ccbf55e8226d1 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 18 Jun 2021 05:53:28 -0700 Subject: [PATCH 04/31] Move more into group service --- .../contrib/terminal/browser/terminal.ts | 9 ++- .../terminal/browser/terminalActions.ts | 20 +++-- .../terminal/browser/terminalGroupService.ts | 80 +++++++++++++++++-- .../terminal/browser/terminalService.ts | 72 +++-------------- .../contrib/terminal/browser/terminalView.ts | 7 +- 5 files changed, 104 insertions(+), 84 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index c8dea5d3b33..de8972e4811 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -188,7 +188,7 @@ export interface ITerminalService { */ doWithActiveInstance(callback: (terminal: ITerminalInstance) => T): T | void; - getActiveGroup(): ITerminalGroup | null; + // TODO: Move these to ITerminalGroupService setActiveGroupToNext(): void; setActiveGroupToPrevious(): void; setActiveGroupByIndex(groupIndex: number): void; @@ -256,16 +256,21 @@ export interface ITerminalEditorService { export interface ITerminalGroupService { readonly _serviceBrand: undefined; + readonly activeGroup: ITerminalGroup | undefined; + readonly activeInstance: ITerminalInstance | undefined; readonly instances: readonly ITerminalInstance[]; readonly groups: readonly ITerminalGroup[]; + readonly onDidChangeActiveGroup: Event; readonly onDidDisposeGroup: Event; readonly onDidChangeGroups: Event; + readonly onDidChangeInstances: Event; + readonly onPanelOrientationChanged: Event; createGroup(slcOrInstance?: IShellLaunchConfig | ITerminalInstance): ITerminalGroup; - // removeGroup(group: ITerminalGroup): void; + removeGroup(group: ITerminalGroup): void; /** * Moves a terminal instance's group to the target instance group's position. diff --git a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts index 26b98cdaa77..7119c0a7779 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts @@ -30,7 +30,7 @@ import { ILocalTerminalService, ITerminalProfile, TerminalSettingId, TitleEventS import { IWorkspaceContextService, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { PICK_WORKSPACE_FOLDER_COMMAND_ID } from 'vs/workbench/browser/actions/workspaceCommands'; import { FindInFilesCommand, IFindInFilesArgs } from 'vs/workbench/contrib/search/browser/searchActions'; -import { Direction, IRemoteTerminalService, ITerminalInstance, ITerminalInstanceService, ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal'; +import { Direction, IRemoteTerminalService, ITerminalGroupService, ITerminalInstance, ITerminalInstanceService, ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal'; import { TerminalQuickAccessProvider } from 'vs/workbench/contrib/terminal/browser/terminalQuickAccess'; import { IRemoteTerminalAttachTarget, ITerminalConfigHelper, KEYBINDING_CONTEXT_TERMINAL_A11Y_TREE_FOCUS, KEYBINDING_CONTEXT_TERMINAL_ALT_BUFFER_ACTIVE, KEYBINDING_CONTEXT_TERMINAL_FIND_FOCUSED, KEYBINDING_CONTEXT_TERMINAL_FIND_NOT_VISIBLE, KEYBINDING_CONTEXT_TERMINAL_FIND_VISIBLE, KEYBINDING_CONTEXT_TERMINAL_FOCUS, KEYBINDING_CONTEXT_TERMINAL_IS_OPEN, KEYBINDING_CONTEXT_TERMINAL_PROCESS_SUPPORTED, KEYBINDING_CONTEXT_TERMINAL_TABS_FOCUS, KEYBINDING_CONTEXT_TERMINAL_TABS_SINGULAR_SELECTION, KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, TerminalCommandId, TerminalLocation, TERMINAL_ACTION_CATEGORY } from 'vs/workbench/contrib/terminal/common/terminal'; import { terminalStrings } from 'vs/workbench/contrib/terminal/common/terminalStrings'; @@ -276,9 +276,8 @@ export function registerTerminalActions() { }); } async run(accessor: ServicesAccessor) { - const terminalService = accessor.get(ITerminalService); - terminalService.getActiveGroup()?.focusPreviousPane(); - await terminalService.showPanel(true); + accessor.get(ITerminalGroupService).activeGroup?.focusPreviousPane(); + await accessor.get(ITerminalService).showPanel(true); } }); registerAction2(class extends Action2 { @@ -302,9 +301,8 @@ export function registerTerminalActions() { }); } async run(accessor: ServicesAccessor) { - const terminalService = accessor.get(ITerminalService); - terminalService.getActiveGroup()?.focusNextPane(); - await terminalService.showPanel(true); + accessor.get(ITerminalGroupService).activeGroup?.focusNextPane(); + await accessor.get(ITerminalService).showPanel(true); } }); registerAction2(class extends Action2 { @@ -324,7 +322,7 @@ export function registerTerminalActions() { }); } async run(accessor: ServicesAccessor) { - accessor.get(ITerminalService).getActiveGroup()?.resizePane(Direction.Left); + accessor.get(ITerminalGroupService).activeGroup?.resizePane(Direction.Left); } }); registerAction2(class extends Action2 { @@ -344,7 +342,7 @@ export function registerTerminalActions() { }); } async run(accessor: ServicesAccessor) { - accessor.get(ITerminalService).getActiveGroup()?.resizePane(Direction.Right); + accessor.get(ITerminalGroupService).activeGroup?.resizePane(Direction.Right); } }); registerAction2(class extends Action2 { @@ -363,7 +361,7 @@ export function registerTerminalActions() { }); } async run(accessor: ServicesAccessor) { - accessor.get(ITerminalService).getActiveGroup()?.resizePane(Direction.Up); + accessor.get(ITerminalGroupService).activeGroup?.resizePane(Direction.Up); } }); registerAction2(class extends Action2 { @@ -382,7 +380,7 @@ export function registerTerminalActions() { }); } async run(accessor: ServicesAccessor) { - accessor.get(ITerminalService).getActiveGroup()?.resizePane(Direction.Down); + accessor.get(ITerminalGroupService).activeGroup?.resizePane(Direction.Down); } }); registerAction2(class extends Action2 { diff --git a/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts b/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts index 6bf41a9ddf8..ff8666c2607 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts @@ -17,8 +17,12 @@ export class TerminalGroupService extends Disposable implements ITerminalGroupSe instances: ITerminalInstance[] = []; groups: ITerminalGroup[] = []; + private _activeGroupIndex: number = -1; + private _container: HTMLElement | undefined; + private readonly _onDidChangeActiveGroup = new Emitter(); + get onDidChangeActiveGroup(): Event { return this._onDidChangeActiveGroup.event; } private readonly _onDidDisposeGroup = new Emitter(); get onDidDisposeGroup(): Event { return this._onDidDisposeGroup.event; } private readonly _onDidChangeGroups = new Emitter(); @@ -36,6 +40,18 @@ export class TerminalGroupService extends Disposable implements ITerminalGroupSe super(); } + get activeGroup(): ITerminalGroup | undefined { + if (this._activeGroupIndex < 0 || this._activeGroupIndex >= this.groups.length) { + return undefined; + } + return this.groups[this._activeGroupIndex]; + } + + get activeInstance(): ITerminalInstance | undefined { + // TODO: Change ITermianlGroup.activeInstance to return undefined + return this.activeGroup?.activeInstance ?? undefined; + } + setContainer(container: HTMLElement) { this._container = container; this.groups.forEach(group => group.attachToElement(container)); @@ -55,13 +71,63 @@ export class TerminalGroupService extends Disposable implements ITerminalGroupSe return group; } - // removeGroup(group: ITerminalGroup): void { - // const index = this.groups.indexOf(group); - // if (index !== -1) { - // this.groups.splice(index, 1); - // this._onDidChangeGroups.fire(); - // } - // } + removeGroup(group: ITerminalGroup): void { + const wasActiveGroup = this._removeGroupAndAdjustFocus(group); + + this._onDidChangeInstances.fire(); + this._onDidChangeGroups.fire(); + if (wasActiveGroup) { + this._onDidChangeActiveGroup.fire(this.activeGroup); + } + } + + private _removeGroupAndAdjustFocus(group: ITerminalGroup): boolean { + // Get the index of the group and remove it from the list + const activeGroup = this.activeGroup; + const wasActiveGroup = group === activeGroup; + const index = this.groups.indexOf(group); + if (index !== -1) { + this.groups.splice(index, 1); + this._onDidChangeGroups.fire(); + } + // if (index !== -1) { + // // TODO: Remove cast + // (this._terminalGroups as ITerminalGroup[]).splice(index, 1); + // this._onGroupsChanged.fire(); + // } + + // Adjust focus if the group was active + if (wasActiveGroup && this.groups.length > 0) { + const newIndex = index < this.groups.length ? index : this.groups.length - 1; + this._setActiveGroupByIndex(newIndex); + this.activeInstance?.focus(true); + } else if (this._activeGroupIndex >= this.groups.length) { + const newIndex = this.groups.length - 1; + this._setActiveGroupByIndex(newIndex); + } + + // Hide the panel if there are no more instances, provided that VS Code is not shutting + // down. When shutting down the panel is locked in place so that it is restored upon next + // launch. + // TODO: Move this into terminal service - listen to onDidGroupsChange + // if (this.groups.length === 0 && !this._isShuttingDown) { + // this.hidePanel(); + // this._onActiveInstanceChanged.fire(undefined); + // } + + return wasActiveGroup; + } + + private _setActiveGroupByIndex(index: number): void { + if (index >= this.groups.length) { + return; + } + + this._activeGroupIndex = index; + + this.groups.forEach((g, i) => g.setVisible(i === this._activeGroupIndex)); + this._onDidChangeActiveGroup.fire(this.activeGroup); + } moveGroup(source: ITerminalInstance, target: ITerminalInstance): void { const sourceGroup = this.getGroupForInstance(source); diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index 64a7c26d53e..7f7c13611a6 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -207,7 +207,7 @@ export class TerminalService implements ITerminalService { // 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.onGroupDisposed(group => this._removeGroup(group)); + this.onGroupDisposed(group => this._terminalGroupService.removeGroup(group)); this.onInstancesChanged(() => this._terminalCountContextKey.set(this._terminalInstances.length)); this.onGroupsChanged(() => this._terminalGroupCountContextKey.set(this._terminalGroups.length)); this.onInstanceLinksReady(instance => this._setInstanceLinkProviders(instance)); @@ -477,7 +477,7 @@ export class TerminalService implements ITerminalService { return; } const state: ITerminalsLayoutInfoById = { - tabs: this.terminalGroups.map(g => g.getLayoutInfo(g === this.getActiveGroup())) + tabs: this.terminalGroups.map(g => g.getLayoutInfo(g === this._terminalGroupService.activeGroup)) }; this._primaryOffProcessTerminalService?.setTerminalLayoutInfo(state); } @@ -498,69 +498,19 @@ export class TerminalService implements ITerminalService { this._primaryOffProcessTerminalService?.updateIcon(instance.persistentProcessId, instance.icon, instance.color); } - private _removeGroup(group: ITerminalGroup): void { - const wasActiveGroup = this._removeGroupAndAdjustFocus(group); - - this._onInstancesChanged.fire(); - this._onGroupsChanged.fire(); - if (wasActiveGroup) { - this._onActiveGroupChanged.fire(); - } - } - - private _removeGroupAndAdjustFocus(group: ITerminalGroup): boolean { - // Get the index of the group and remove it from the list - const index = this._terminalGroups.indexOf(group); - const activeGroup = this.getActiveGroup(); - const activeGroupIndex = activeGroup ? this._terminalGroups.indexOf(activeGroup) : -1; - const wasActiveGroup = group === activeGroup; - if (index !== -1) { - // TODO: Remove cast - (this._terminalGroups as ITerminalGroup[]).splice(index, 1); - this._onGroupsChanged.fire(); - } - - // Adjust focus if the group was active - if (wasActiveGroup && this._terminalGroups.length > 0) { - const newIndex = index < this._terminalGroups.length ? index : this._terminalGroups.length - 1; - this.setActiveGroupByIndex(newIndex); - const activeInstance = this.getActiveInstance(); - if (activeInstance) { - activeInstance.focus(true); - } - } else if (activeGroupIndex >= this._terminalGroups.length) { - const newIndex = this._terminalGroups.length - 1; - this.setActiveGroupByIndex(newIndex); - } - - // Hide the panel if there are no more instances, provided that VS Code is not shutting - // down. When shutting down the panel is locked in place so that it is restored upon next - // launch. - if (this._terminalGroups.length === 0 && !this._isShuttingDown) { - this.hidePanel(); - this._onActiveInstanceChanged.fire(undefined); - } - - return wasActiveGroup; - } - refreshActiveGroup(): void { this._onActiveGroupChanged.fire(); } - public getActiveGroup(): ITerminalGroup | null { - if (this._activeGroupIndex < 0 || this._activeGroupIndex >= this._terminalGroups.length) { - return null; - } - return this._terminalGroups[this._activeGroupIndex]; - } - public getActiveInstance(): ITerminalInstance | null { - const group = this.getActiveGroup(); - if (!group) { - return null; - } - return group.activeInstance; + // TODO: Change return type to undefined + // TODO: Get the active instance from the latest activated group or editor + return this._terminalGroupService.activeInstance || null; + // const group = this.getActiveGroup(); + // if (!group) { + // return null; + // } + // return group.activeInstance; } doWithActiveInstance(callback: (terminal: ITerminalInstance) => T): T | void { @@ -747,7 +697,7 @@ export class TerminalService implements ITerminalService { // this._onGroupsChanged.fire(); } - const wasActiveGroup = this.getActiveGroup() === candidateGroup; + const wasActiveGroup = this._terminalGroupService.activeGroup === candidateGroup; // Unsplit all other instances and add them to the new group for (const instance of instances) { diff --git a/src/vs/workbench/contrib/terminal/browser/terminalView.ts b/src/vs/workbench/contrib/terminal/browser/terminalView.ts index f8f55275b8b..51207ddb6db 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalView.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalView.ts @@ -14,7 +14,7 @@ import { IThemeService, IColorTheme, registerThemingParticipant, ICssStyleCollec import { switchTerminalActionViewItemSeparator, switchTerminalShowTabsTitle } from 'vs/workbench/contrib/terminal/browser/terminalActions'; import { TERMINAL_BACKGROUND_COLOR, TERMINAL_BORDER_COLOR, TERMINAL_DRAG_AND_DROP_BACKGROUND } from 'vs/workbench/contrib/terminal/common/terminalColorRegistry'; import { INotificationService, IPromptChoice, Severity } from 'vs/platform/notification/common/notification'; -import { ITerminalInstance, ITerminalService, TerminalConnectionState } from 'vs/workbench/contrib/terminal/browser/terminal'; +import { ITerminalGroupService, ITerminalInstance, ITerminalService, TerminalConnectionState } from 'vs/workbench/contrib/terminal/browser/terminal'; import { ViewPane, IViewPaneOptions } from 'vs/workbench/browser/parts/views/viewPane'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; @@ -66,6 +66,7 @@ export class TerminalViewPane extends ViewPane { @IContextMenuService private readonly _contextMenuService: IContextMenuService, @IInstantiationService private readonly _instantiationService: IInstantiationService, @ITerminalService private readonly _terminalService: ITerminalService, + @ITerminalGroupService private readonly _terminalGroupService: ITerminalGroupService, @IThemeService themeService: IThemeService, @ITelemetryService telemetryService: ITelemetryService, @INotificationService private readonly _notificationService: INotificationService, @@ -143,14 +144,14 @@ export class TerminalViewPane extends ViewPane { } if (hadTerminals) { - this._terminalService.getActiveGroup()?.setVisible(visible); + this._terminalGroupService.activeGroup?.setVisible(visible); } else { // TODO@Tyriar - this call seems unnecessary this.layoutBody(this._bodyDimensions.height, this._bodyDimensions.width); } this._terminalService.showPanel(true); } else { - this._terminalService.getActiveGroup()?.setVisible(false); + this._terminalGroupService.activeGroup?.setVisible(false); } })); this.layoutBody(this._parentDomElement.offsetHeight, this._parentDomElement.offsetWidth); From dd4a0f6baffb4143967ded21686739893c09919c Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 18 Jun 2021 06:05:24 -0700 Subject: [PATCH 05/31] Move active ids into group service --- .../contrib/terminal/browser/terminal.ts | 24 +++-- .../terminal/browser/terminalActions.ts | 12 +-- .../terminal/browser/terminalCommands.ts | 7 +- .../terminal/browser/terminalGroupService.ts | 91 +++++++++++++++--- .../terminal/browser/terminalService.ts | 96 ++----------------- .../contrib/terminal/browser/terminalView.ts | 5 +- 6 files changed, 113 insertions(+), 122 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index de8972e4811..7e64cd03d93 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -113,7 +113,6 @@ export interface ICreateTerminalOptions { export interface ITerminalService { readonly _serviceBrand: undefined; - activeGroupIndex: number; configHelper: ITerminalConfigHelper; terminalInstances: ITerminalInstance[]; readonly terminalGroups: readonly ITerminalGroup[]; @@ -167,7 +166,6 @@ export interface ITerminalService { getGroupLabels(): string[]; getActiveInstance(): ITerminalInstance | null; setActiveInstance(terminalInstance: ITerminalInstance): void; - setActiveInstanceByIndex(terminalIndex: number): void; getActiveOrCreateInstance(): ITerminalInstance; splitInstance(instance: ITerminalInstance, shell?: IShellLaunchConfig, cwd?: string | URI): ITerminalInstance | null; splitInstance(instance: ITerminalInstance, profile: ITerminalProfile): ITerminalInstance | null; @@ -188,11 +186,6 @@ export interface ITerminalService { */ doWithActiveInstance(callback: (terminal: ITerminalInstance) => T): T | void; - // TODO: Move these to ITerminalGroupService - setActiveGroupToNext(): void; - setActiveGroupToPrevious(): void; - setActiveGroupByIndex(groupIndex: number): void; - /** * Fire the onActiveTabChanged event, this will trigger the terminal dropdown to be updated, * among other things. @@ -256,15 +249,20 @@ export interface ITerminalEditorService { export interface ITerminalGroupService { readonly _serviceBrand: undefined; - readonly activeGroup: ITerminalGroup | undefined; - readonly activeInstance: ITerminalInstance | undefined; - readonly instances: readonly ITerminalInstance[]; 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 readonly onDidChangeActiveGroup: Event; readonly onDidDisposeGroup: Event; readonly onDidChangeGroups: Event; + readonly onDidChangeActiveInstance: Event; readonly onDidChangeInstances: Event; readonly onPanelOrientationChanged: Event; @@ -278,8 +276,14 @@ export interface ITerminalGroupService { * @param target The target instance to move the source instance to. */ moveGroup(source: ITerminalInstance, target: ITerminalInstance): void; + + setActiveGroupByIndex(index: number): void; + setActiveGroupToNext(): void; + setActiveGroupToPrevious(): void; getGroupForInstance(instance: ITerminalInstance): ITerminalGroup | undefined; + setActiveInstanceByIndex(terminalIndex: number): void; + setContainer(container: HTMLElement): void; } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts index 7119c0a7779..f4936844605 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts @@ -441,9 +441,8 @@ export function registerTerminalActions() { }); } async run(accessor: ServicesAccessor) { - const terminalService = accessor.get(ITerminalService); - terminalService.setActiveGroupToNext(); - await terminalService.showPanel(true); + accessor.get(ITerminalGroupService).setActiveGroupToNext(); + await accessor.get(ITerminalService).showPanel(true); } }); registerAction2(class extends Action2 { @@ -465,9 +464,8 @@ export function registerTerminalActions() { }); } async run(accessor: ServicesAccessor) { - const terminalService = accessor.get(ITerminalService); - terminalService.setActiveGroupToPrevious(); - await terminalService.showPanel(true); + accessor.get(ITerminalGroupService).setActiveGroupToPrevious(); + await accessor.get(ITerminalService).showPanel(true); } }); registerAction2(class extends Action2 { @@ -1823,7 +1821,7 @@ export function registerTerminalActions() { } const indexMatches = terminalIndexRe.exec(item); if (indexMatches) { - terminalService.setActiveGroupByIndex(Number(indexMatches[1]) - 1); + accessor.get(ITerminalGroupService).setActiveGroupByIndex(Number(indexMatches[1]) - 1); return terminalService.showPanel(true); } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalCommands.ts b/src/vs/workbench/contrib/terminal/browser/terminalCommands.ts index 8f0f92efe05..359167fa331 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalCommands.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalCommands.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; -import { ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal'; +import { ITerminalGroupService, ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal'; export function setupTerminalCommands(): void { registerOpenTerminalAtIndexCommands(); @@ -21,9 +21,8 @@ function registerOpenTerminalAtIndexCommands(): void { when: undefined, primary: 0, handler: accessor => { - const terminalService = accessor.get(ITerminalService); - terminalService.setActiveInstanceByIndex(terminalIndex); - return terminalService.showPanel(true); + accessor.get(ITerminalGroupService).setActiveInstanceByIndex(terminalIndex); + return accessor.get(ITerminalService).showPanel(true); } }); } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts b/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts index ff8666c2607..e503a054291 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts @@ -14,10 +14,10 @@ import { TerminalGroup } from 'vs/workbench/contrib/terminal/browser/terminalGro export class TerminalGroupService extends Disposable implements ITerminalGroupService { declare _serviceBrand: undefined; - instances: ITerminalInstance[] = []; groups: ITerminalGroup[] = []; - - private _activeGroupIndex: number = -1; + activeGroupIndex: number = -1; + instances: ITerminalInstance[] = []; + activeInstanceIndex: number = -1; private _container: HTMLElement | undefined; @@ -28,6 +28,8 @@ export class TerminalGroupService extends Disposable implements ITerminalGroupSe private readonly _onDidChangeGroups = new Emitter(); get onDidChangeGroups(): Event { return this._onDidChangeGroups.event; } + private readonly _onDidChangeActiveInstance = new Emitter(); + get onDidChangeActiveInstance(): Event { return this._onDidChangeActiveInstance.event; } private readonly _onDidChangeInstances = new Emitter(); get onDidChangeInstances(): Event { return this._onDidChangeInstances.event; } @@ -41,10 +43,10 @@ export class TerminalGroupService extends Disposable implements ITerminalGroupSe } get activeGroup(): ITerminalGroup | undefined { - if (this._activeGroupIndex < 0 || this._activeGroupIndex >= this.groups.length) { + if (this.activeGroupIndex < 0 || this.activeGroupIndex >= this.groups.length) { return undefined; } - return this.groups[this._activeGroupIndex]; + return this.groups[this.activeGroupIndex]; } get activeInstance(): ITerminalInstance | undefined { @@ -99,11 +101,11 @@ export class TerminalGroupService extends Disposable implements ITerminalGroupSe // Adjust focus if the group was active if (wasActiveGroup && this.groups.length > 0) { const newIndex = index < this.groups.length ? index : this.groups.length - 1; - this._setActiveGroupByIndex(newIndex); + this.setActiveGroupByIndex(newIndex); this.activeInstance?.focus(true); - } else if (this._activeGroupIndex >= this.groups.length) { + } else if (this.activeGroupIndex >= this.groups.length) { const newIndex = this.groups.length - 1; - this._setActiveGroupByIndex(newIndex); + this.setActiveGroupByIndex(newIndex); } // Hide the panel if there are no more instances, provided that VS Code is not shutting @@ -118,17 +120,77 @@ export class TerminalGroupService extends Disposable implements ITerminalGroupSe return wasActiveGroup; } - private _setActiveGroupByIndex(index: number): void { + setActiveGroupByIndex(index: number): void { if (index >= this.groups.length) { return; } - this._activeGroupIndex = index; + this.activeGroupIndex = index; - this.groups.forEach((g, i) => g.setVisible(i === this._activeGroupIndex)); + this.groups.forEach((g, i) => g.setVisible(i === this.activeGroupIndex)); this._onDidChangeActiveGroup.fire(this.activeGroup); } + + private _getInstanceLocation(index: number): IInstanceLocation | undefined { + let currentGroupIndex = 0; + while (index >= 0 && currentGroupIndex < this.groups.length) { + const group = this.groups[currentGroupIndex]; + const count = group.terminalInstances.length; + if (index < count) { + return { + group, + groupIndex: currentGroupIndex, + instance: group.terminalInstances[index], + instanceIndex: index + }; + } + index -= count; + currentGroupIndex++; + } + return undefined; + } + + setActiveInstanceByIndex(index: number): void { + const instanceLocation = this._getInstanceLocation(index); + if (!instanceLocation || (this.activeInstanceIndex > 0 && this.activeInstanceIndex === index)) { + return; + } + + this.activeInstanceIndex = instanceLocation.instanceIndex; + this.activeGroupIndex = instanceLocation.groupIndex; + + instanceLocation.group.setActiveInstanceByIndex(this.activeInstanceIndex); + this.groups.forEach((g, i) => g.setVisible(i === instanceLocation.groupIndex)); + + if (this.activeGroupIndex !== instanceLocation.groupIndex) { + this._onDidChangeActiveGroup.fire(this.activeGroup); + } + this._onDidChangeActiveInstance.fire(instanceLocation.instance); + } + + setActiveGroupToNext(): void { + if (this.groups.length <= 1) { + return; + } + let newIndex = this.activeGroupIndex + 1; + if (newIndex >= this.groups.length) { + newIndex = 0; + } + this.setActiveGroupByIndex(newIndex); + } + + setActiveGroupToPrevious(): void { + if (this.groups.length <= 1) { + return; + } + let newIndex = this.activeGroupIndex - 1; + if (newIndex < 0) { + newIndex = this.groups.length - 1; + } + this.setActiveGroupByIndex(newIndex); + } + moveGroup(source: ITerminalInstance, target: ITerminalInstance): void { const sourceGroup = this.getGroupForInstance(source); const targetGroup = this.getGroupForInstance(target); @@ -146,3 +208,10 @@ export class TerminalGroupService extends Disposable implements ITerminalGroupSe return this.groups.find(group => group.terminalInstances.indexOf(instance) !== -1); } } + +interface IInstanceLocation { + group: ITerminalGroup, + groupIndex: number, + instance: ITerminalInstance, + instanceIndex: number +} diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index 7f7c13611a6..33a1e4de67d 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -57,8 +57,6 @@ export class TerminalService implements ITerminalService { private _terminalAltBufferActiveContextKey: IContextKey; private _backgroundedTerminalInstances: ITerminalInstance[] = []; private _findState: FindReplaceState; - private _activeGroupIndex: number; - private _activeInstanceIndex: number; private readonly _profileProviders: Map> = new Map(); private _linkProviders: Set = new Set(); private _linkProviderDisposables: Map = new Map(); @@ -74,7 +72,6 @@ export class TerminalService implements ITerminalService { private _editable: { instance: ITerminalInstance, data: IEditableData } | undefined; - public get activeGroupIndex(): number { return this._activeGroupIndex; } public get terminalGroups(): readonly ITerminalGroup[] { return this._terminalGroups; } public get isProcessSupportRegistered(): boolean { return !!this._processSupportContextKey.get(); } get connectionState(): TerminalConnectionState { return this._connectionState; } @@ -156,8 +153,6 @@ export class TerminalService implements ITerminalService { @optional(ILocalTerminalService) localTerminalService: ILocalTerminalService ) { this._localTerminalService = localTerminalService; - this._activeGroupIndex = 0; - this._activeInstanceIndex = 0; this._isShuttingDown = false; this._findState = new FindReplaceState(); this._terminalFocusContextKey = KEYBINDING_CONTEXT_TERMINAL_FOCUS.bindTo(this._contextKeyService); @@ -338,7 +333,7 @@ export class TerminalService implements ITerminalService { } }); if (layoutInfo.tabs.length) { - this.setActiveGroupByIndex(activeGroup ? this.terminalGroups.indexOf(activeGroup) : 0); + this._terminalGroupService.setActiveGroupByIndex(activeGroup ? this.terminalGroups.indexOf(activeGroup) : 0); } } return reconnectCounter; @@ -550,18 +545,8 @@ export class TerminalService implements ITerminalService { if (terminalInstance.shellLaunchConfig.hideFromUser) { this._showBackgroundTerminal(terminalInstance); } - this.setActiveInstanceByIndex(this._getIndexFromId(terminalInstance.instanceId)); - } - - setActiveGroupByIndex(index: number): void { - if (index >= this._terminalGroups.length) { - return; - } - - this._activeGroupIndex = index; - - this._terminalGroups.forEach((g, i) => g.setVisible(i === this._activeGroupIndex)); - this._onActiveGroupChanged.fire(); + // TODO: Handle editor terminals too + this._terminalGroupService.setActiveInstanceByIndex(this._getIndexFromId(terminalInstance.instanceId)); } isAttachedToTerminal(remoteTerm: IRemoteTerminalAttachTarget): boolean { @@ -579,65 +564,6 @@ export class TerminalService implements ITerminalService { } } - private _getInstanceLocation(index: number): IInstanceLocation | undefined { - let currentGroupIndex = 0; - while (index >= 0 && currentGroupIndex < this._terminalGroups.length) { - const group = this._terminalGroups[currentGroupIndex]; - const count = group.terminalInstances.length; - if (index < count) { - return { - group, - groupIndex: currentGroupIndex, - instance: group.terminalInstances[index], - instanceIndex: index - }; - } - index -= count; - currentGroupIndex++; - } - return undefined; - } - - setActiveInstanceByIndex(index: number): void { - const instanceLocation = this._getInstanceLocation(index); - if (!instanceLocation || (this._activeInstanceIndex > 0 && this._activeInstanceIndex === index)) { - return; - } - - this._activeInstanceIndex = instanceLocation.instanceIndex; - this._activeGroupIndex = instanceLocation.groupIndex; - - instanceLocation.group.setActiveInstanceByIndex(this._activeInstanceIndex); - this._terminalGroups.forEach((g, i) => g.setVisible(i === instanceLocation.groupIndex)); - - if (this._activeGroupIndex !== instanceLocation.groupIndex) { - this._onActiveGroupChanged.fire(); - } - this._onActiveInstanceChanged.fire(instanceLocation.instance); - } - - setActiveGroupToNext(): void { - if (this._terminalGroups.length <= 1) { - return; - } - let newIndex = this._activeGroupIndex + 1; - if (newIndex >= this._terminalGroups.length) { - newIndex = 0; - } - this.setActiveGroupByIndex(newIndex); - } - - setActiveGroupToPrevious(): void { - if (this._terminalGroups.length <= 1) { - return; - } - let newIndex = this._activeGroupIndex - 1; - if (newIndex < 0) { - newIndex = this._terminalGroups.length - 1; - } - this.setActiveGroupByIndex(newIndex); - } - splitInstance(instanceToSplit: ITerminalInstance, shellLaunchConfig?: IShellLaunchConfig): ITerminalInstance | null; splitInstance(instanceToSplit: ITerminalInstance, profile: ITerminalProfile, cwd?: string | URI): ITerminalInstance | null splitInstance(instanceToSplit: ITerminalInstance, shellLaunchConfigOrProfile: IShellLaunchConfig | ITerminalProfile = {}, cwd?: string | URI): ITerminalInstance | null { @@ -650,7 +576,8 @@ export class TerminalService implements ITerminalService { this._initInstanceListeners(instance); - this._terminalGroups.forEach((g, i) => g.setVisible(i === this._activeGroupIndex)); + // TODO: Move into group service? + this._terminalGroups.forEach((g, i) => g.setVisible(i === this._terminalGroupService.activeGroupIndex)); return instance; } @@ -1087,7 +1014,7 @@ export class TerminalService implements ITerminalService { } try { await profileProvider.createContributedTerminalProfile(isSplitTerminal); - this.setActiveInstanceByIndex(this._terminalInstances.length - 1); + this._terminalGroupService.setActiveInstanceByIndex(this._terminalInstances.length - 1); await this.getActiveInstance()?.focusWhenReady(); } catch (e) { this._notificationService.error(e.message); @@ -1208,7 +1135,7 @@ export class TerminalService implements ITerminalService { if (this.terminalInstances.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.setActiveInstanceByIndex(0); + this._terminalGroupService.setActiveInstanceByIndex(0); } return instance; } @@ -1225,7 +1152,7 @@ export class TerminalService implements ITerminalService { // Make active automatically if it's the first instance if (this.terminalInstances.length === 1) { - this.setActiveInstanceByIndex(0); + this._terminalGroupService.setActiveInstanceByIndex(0); } this._onInstancesChanged.fire(); @@ -1280,10 +1207,3 @@ export class TerminalService implements ITerminalService { interface IProfileQuickPickItem extends IQuickPickItem { profile: ITerminalProfile | (ITerminalProfileContribution & { extensionIdentifier: string }); } - -interface IInstanceLocation { - group: ITerminalGroup, - groupIndex: number, - instance: ITerminalInstance, - instanceIndex: number -} diff --git a/src/vs/workbench/contrib/terminal/browser/terminalView.ts b/src/vs/workbench/contrib/terminal/browser/terminalView.ts index 51207ddb6db..7b97007546a 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalView.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalView.ts @@ -316,10 +316,11 @@ class SwitchTerminalActionViewItem extends SelectActionViewItem { constructor( action: IAction, @ITerminalService private readonly _terminalService: ITerminalService, + @ITerminalGroupService private readonly _terminalGroupService: ITerminalGroupService, @IThemeService private readonly _themeService: IThemeService, @IContextViewService contextViewService: IContextViewService ) { - super(null, action, getTerminalSelectOpenItems(_terminalService), _terminalService.activeGroupIndex, contextViewService, { ariaLabel: nls.localize('terminals', 'Open Terminals.'), optionsAsChildren: true }); + 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.onGroupsChanged(() => this._updateItems(), this)); this._register(_terminalService.onActiveGroupChanged(() => this._updateItems(), this)); @@ -341,7 +342,7 @@ class SwitchTerminalActionViewItem extends SelectActionViewItem { private _updateItems(): void { const options = getTerminalSelectOpenItems(this._terminalService); - this.setOptions(options, this._terminalService.activeGroupIndex); + this.setOptions(options, this._terminalGroupService.activeGroupIndex); } } From b286e524efdaf0f93d48068de67febeb8af0c6e0 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 18 Jun 2021 06:07:52 -0700 Subject: [PATCH 06/31] Return undefined instead of null --- src/vs/workbench/contrib/terminal/browser/terminal.ts | 2 +- .../workbench/contrib/terminal/browser/terminalFindWidget.ts | 4 ++-- src/vs/workbench/contrib/terminal/browser/terminalService.ts | 5 ++--- src/vs/workbench/contrib/terminal/browser/terminalView.ts | 4 ++-- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index 7e64cd03d93..2b14075e236 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -164,7 +164,7 @@ export interface ITerminalService { getInstanceFromId(terminalId: number): ITerminalInstance | undefined; getInstanceFromIndex(terminalIndex: number): ITerminalInstance; getGroupLabels(): string[]; - getActiveInstance(): ITerminalInstance | null; + getActiveInstance(): ITerminalInstance | undefined; setActiveInstance(terminalInstance: ITerminalInstance): void; getActiveOrCreateInstance(): ITerminalInstance; splitInstance(instance: ITerminalInstance, shell?: IShellLaunchConfig, cwd?: string | URI): ITerminalInstance | null; diff --git a/src/vs/workbench/contrib/terminal/browser/terminalFindWidget.ts b/src/vs/workbench/contrib/terminal/browser/terminalFindWidget.ts index 4d9ac4ed1f1..85eeb1546a9 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalFindWidget.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalFindWidget.ts @@ -30,7 +30,7 @@ export class TerminalFindWidget extends SimpleFindWidget { find(previous: boolean) { const instance = this._terminalService.getActiveInstance(); - if (instance !== null) { + if (instance) { if (previous) { instance.findPrevious(this.inputValue, { regex: this._getRegexValue(), wholeWord: this._getWholeWordValue(), caseSensitive: this._getCaseSensitiveValue() }); } else { @@ -50,7 +50,7 @@ export class TerminalFindWidget extends SimpleFindWidget { protected _onInputChanged() { // Ignore input changes for now const instance = this._terminalService.getActiveInstance(); - if (instance !== null) { + if (instance) { return instance.findPrevious(this.inputValue, { regex: this._getRegexValue(), wholeWord: this._getWholeWordValue(), caseSensitive: this._getCaseSensitiveValue(), incremental: true }); } return false; diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index 33a1e4de67d..6cbbb122710 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -497,10 +497,9 @@ export class TerminalService implements ITerminalService { this._onActiveGroupChanged.fire(); } - public getActiveInstance(): ITerminalInstance | null { - // TODO: Change return type to undefined + getActiveInstance(): ITerminalInstance | undefined { // TODO: Get the active instance from the latest activated group or editor - return this._terminalGroupService.activeInstance || null; + return this._terminalGroupService.activeInstance; // const group = this.getActiveGroup(); // if (!group) { // return null; diff --git a/src/vs/workbench/contrib/terminal/browser/terminalView.ts b/src/vs/workbench/contrib/terminal/browser/terminalView.ts index 7b97007546a..cdcde6f7037 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalView.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalView.ts @@ -494,7 +494,7 @@ class SingleTerminalTabActionViewItem extends MenuEntryActionViewItem { } } -function getSingleTabLabel(instance: ITerminalInstance | null, icon?: ThemeIcon) { +function getSingleTabLabel(instance: ITerminalInstance | undefined, icon?: ThemeIcon) { // Don't even show the icon if there is no title as the icon would shift around when the title // is added if (!instance || !instance.title) { @@ -510,7 +510,7 @@ function getSingleTabLabel(instance: ITerminalInstance | null, icon?: ThemeIcon) return `${label} $(${primaryStatus.icon.id})`; } -function getSingleTabTooltip(instance: ITerminalInstance | null): string { +function getSingleTabTooltip(instance: ITerminalInstance | undefined): string { if (!instance) { return ''; } From b09d03248bb498da642b1215a57e31be16d28bf3 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 18 Jun 2021 06:09:22 -0700 Subject: [PATCH 07/31] Remove more null and public --- src/vs/workbench/contrib/terminal/browser/terminal.ts | 2 +- .../contrib/terminal/browser/terminalGroup.ts | 4 ++-- .../contrib/terminal/browser/terminalGroupService.ts | 3 +-- .../contrib/terminal/browser/terminalService.ts | 10 +++++----- 4 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index 2b14075e236..0bbbc07cb92 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -64,7 +64,7 @@ export const enum Direction { } export interface ITerminalGroup { - activeInstance: ITerminalInstance | null; + activeInstance: ITerminalInstance | undefined; terminalInstances: ITerminalInstance[]; title: string; diff --git a/src/vs/workbench/contrib/terminal/browser/terminalGroup.ts b/src/vs/workbench/contrib/terminal/browser/terminalGroup.ts index b7b915f93c9..062abe58d57 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalGroup.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalGroup.ts @@ -301,9 +301,9 @@ export class TerminalGroup extends Disposable implements ITerminalGroup { this._onInstancesChanged.fire(); } - get activeInstance(): ITerminalInstance | null { + get activeInstance(): ITerminalInstance | undefined { if (this._terminalInstances.length === 0) { - return null; + return undefined; } return this._terminalInstances[this._activeInstanceIndex]; } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts b/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts index e503a054291..258db3bb188 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts @@ -50,8 +50,7 @@ export class TerminalGroupService extends Disposable implements ITerminalGroupSe } get activeInstance(): ITerminalInstance | undefined { - // TODO: Change ITermianlGroup.activeInstance to return undefined - return this.activeGroup?.activeInstance ?? undefined; + return this.activeGroup?.activeInstance; } setContainer(container: HTMLElement) { diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index 6cbbb122710..7345ff644f5 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -72,8 +72,8 @@ export class TerminalService implements ITerminalService { private _editable: { instance: ITerminalInstance, data: IEditableData } | undefined; - public get terminalGroups(): readonly ITerminalGroup[] { return this._terminalGroups; } - public get isProcessSupportRegistered(): boolean { return !!this._processSupportContextKey.get(); } + get terminalGroups(): readonly ITerminalGroup[] { return this._terminalGroups; } + get isProcessSupportRegistered(): boolean { return !!this._processSupportContextKey.get(); } get connectionState(): TerminalConnectionState { return this._connectionState; } get profilesReady(): Promise { return this._profilesReadyBarrier.wait().then(() => { }); } get availableProfiles(): ITerminalProfile[] { @@ -115,9 +115,9 @@ export class TerminalService implements ITerminalService { private readonly _onActiveInstanceChanged = new Emitter(); get onActiveInstanceChanged(): Event { return this._onActiveInstanceChanged.event; } private readonly _onInstancePrimaryStatusChanged = new Emitter(); - public get onInstancePrimaryStatusChanged(): Event { return this._onInstancePrimaryStatusChanged.event; } + get onInstancePrimaryStatusChanged(): Event { return this._onInstancePrimaryStatusChanged.event; } private readonly _onGroupDisposed = new Emitter(); - public get onGroupDisposed(): Event { return this._onGroupDisposed.event; } + get onGroupDisposed(): Event { return this._onGroupDisposed.event; } private readonly _onGroupsChanged = new Emitter(); get onGroupsChanged(): Event { return this._onGroupsChanged.event; } private readonly _onDidRegisterProcessSupport = new Emitter(); @@ -456,7 +456,7 @@ export class TerminalService implements ITerminalService { this._localTerminalService?.setTerminalLayoutInfo(undefined); } - public getGroupLabels(): string[] { + getGroupLabels(): string[] { return this._terminalGroups.filter(group => group.terminalInstances.length > 0).map((group, index) => { return `${index + 1}: ${group.title ? group.title : ''}`; }); From c1a076dd2617bf686d4bb2cf86afcaf696baa1ec Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 18 Jun 2021 06:13:32 -0700 Subject: [PATCH 08/31] Remove some code --- .../terminal/browser/terminalGroupService.ts | 16 ++------ .../terminal/browser/terminalService.ts | 39 +++++-------------- 2 files changed, 12 insertions(+), 43 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts b/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts index 258db3bb188..f0c3a2ecd0d 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts @@ -91,11 +91,6 @@ export class TerminalGroupService extends Disposable implements ITerminalGroupSe this.groups.splice(index, 1); this._onDidChangeGroups.fire(); } - // if (index !== -1) { - // // TODO: Remove cast - // (this._terminalGroups as ITerminalGroup[]).splice(index, 1); - // this._onGroupsChanged.fire(); - // } // Adjust focus if the group was active if (wasActiveGroup && this.groups.length > 0) { @@ -107,14 +102,9 @@ export class TerminalGroupService extends Disposable implements ITerminalGroupSe this.setActiveGroupByIndex(newIndex); } - // Hide the panel if there are no more instances, provided that VS Code is not shutting - // down. When shutting down the panel is locked in place so that it is restored upon next - // launch. - // TODO: Move this into terminal service - listen to onDidGroupsChange - // if (this.groups.length === 0 && !this._isShuttingDown) { - // this.hidePanel(); - // this._onActiveInstanceChanged.fire(undefined); - // } + if (this.groups.length === 0) { + this._onDidChangeActiveInstance.fire(undefined); + } return wasActiveGroup; } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index 7345ff644f5..83ad2d7724f 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -207,6 +207,15 @@ export class TerminalService implements ITerminalService { this.onGroupsChanged(() => this._terminalGroupCountContextKey.set(this._terminalGroups.length)); this.onInstanceLinksReady(instance => this._setInstanceLinkProviders(instance)); + // Hide the panel if there are no more instances, provided that VS Code is not shutting + // down. When shutting down the panel is locked in place so that it is restored upon next + // launch. + this._terminalGroupService.onDidChangeActiveInstance(instance => { + if (!instance && !this._isShuttingDown) { + this.hidePanel(); + } + }); + this._handleInstanceContextKeys(); this._processSupportContextKey = KEYBINDING_CONTEXT_TERMINAL_PROCESS_SUPPORTED.bindTo(this._contextKeyService); this._processSupportContextKey.set(!isWeb || this._remoteAgentService.getConnection() !== null); @@ -500,11 +509,6 @@ export class TerminalService implements ITerminalService { getActiveInstance(): ITerminalInstance | undefined { // TODO: Get the active instance from the latest activated group or editor return this._terminalGroupService.activeInstance; - // const group = this.getActiveGroup(); - // if (!group) { - // return null; - // } - // return group.activeInstance; } doWithActiveInstance(callback: (terminal: ITerminalInstance) => T): T | void { @@ -588,15 +592,6 @@ export class TerminalService implements ITerminalService { oldGroup.removeInstance(instance); this._terminalGroupService.createGroup(instance); - - // const newGroup = this._instantiationService.createInstance(TerminalGroup, this._terminalContainer, instance); - // newGroup.onPanelOrientationChanged((orientation) => this._onPanelOrientationChanged.fire(orientation)); - // this._terminalGroups.push(newGroup); - - // newGroup.addDisposable(newGroup.onDisposed(this._onGroupDisposed.fire, this._onGroupDisposed)); - // newGroup.addDisposable(newGroup.onInstancesChanged(this._onInstancesChanged.fire, this._onInstancesChanged)); - // this._onInstancesChanged.fire(); - // this._onGroupsChanged.fire(); } joinInstances(instances: ITerminalInstance[]): void { @@ -615,12 +610,6 @@ export class TerminalService implements ITerminalService { // Create a new group if needed if (!candidateGroup) { candidateGroup = this._terminalGroupService.createGroup(); - // candidateGroup = this._instantiationService.createInstance(TerminalGroup, this._terminalContainer, undefined); - // candidateGroup.onPanelOrientationChanged((orientation) => this._onPanelOrientationChanged.fire(orientation)); - // this._terminalGroups.push(candidateGroup); - // candidateGroup.addDisposable(candidateGroup.onDisposed(this._onGroupDisposed.fire, this._onGroupDisposed)); - // candidateGroup.addDisposable(candidateGroup.onInstancesChanged(this._onInstancesChanged.fire, this._onInstancesChanged)); - // this._onGroupsChanged.fire(); } const wasActiveGroup = this._terminalGroupService.activeGroup === candidateGroup; @@ -703,11 +692,6 @@ export class TerminalService implements ITerminalService { if (!group) { group = this._terminalGroupService.createGroup(); - // group = this._instantiationService.createInstance(TerminalGroup, this._terminalContainer, undefined); - // group.onPanelOrientationChanged((orientation) => this._onPanelOrientationChanged.fire(orientation)); - // this._terminalGroups.push(group); - // group.addDisposable(group.onDisposed(this._onGroupDisposed.fire, this._onGroupDisposed)); - // group.addDisposable(group.onInstancesChanged(this._onInstancesChanged.fire, this._onInstancesChanged)); } group.addInstance(source); @@ -1143,11 +1127,6 @@ export class TerminalService implements ITerminalService { this._backgroundedTerminalInstances.splice(this._backgroundedTerminalInstances.indexOf(instance), 1); instance.shellLaunchConfig.hideFromUser = false; this._terminalGroupService.createGroup(instance); - // const terminalGroup = this._instantiationService.createInstance(TerminalGroup, this._terminalContainer, instance); - // this._terminalGroups.push(terminalGroup); - // terminalGroup.onPanelOrientationChanged((orientation) => this._onPanelOrientationChanged.fire(orientation)); - // terminalGroup.addDisposable(terminalGroup.onDisposed(this._onGroupDisposed.fire, this._onGroupDisposed)); - // terminalGroup.addDisposable(terminalGroup.onInstancesChanged(this._onInstancesChanged.fire, this._onInstancesChanged)); // Make active automatically if it's the first instance if (this.terminalInstances.length === 1) { From 6c2714f0e6e1e179f4ffd7f591b7eb1d253d964d Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 18 Jun 2021 06:33:35 -0700 Subject: [PATCH 09/31] Update tabs list on dispose of single terminals --- .../contrib/terminal/browser/terminal.ts | 7 +++---- .../contrib/terminal/browser/terminalGroup.ts | 15 ++++++++++----- .../terminal/browser/terminalGroupService.ts | 5 +++++ .../contrib/terminal/browser/terminalService.ts | 4 ++-- .../terminal/browser/terminalTabbedView.ts | 5 +++-- .../contrib/terminal/browser/terminalTabsList.ts | 3 ++- .../contrib/terminal/browser/terminalView.ts | 10 ++++++---- 7 files changed, 31 insertions(+), 18 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index 0bbbc07cb92..4377121734d 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -68,6 +68,7 @@ export interface ITerminalGroup { terminalInstances: ITerminalInstance[]; title: string; + readonly onDidDisposeInstance: Event; readonly onDisposed: Event; readonly onInstancesChanged: Event; readonly onPanelOrientationChanged: Event; @@ -124,10 +125,6 @@ export interface ITerminalService { initializeTerminals(): Promise; onActiveGroupChanged: Event; onGroupDisposed: Event; - /** - * An event that fires when a terminal group is created, disposed of, or shown (in the case of a background group) - */ - onGroupsChanged: Event; onInstanceCreated: Event; onInstanceDisposed: Event; onInstanceProcessIdReady: Event; @@ -260,8 +257,10 @@ export interface ITerminalGroupService { 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; diff --git a/src/vs/workbench/contrib/terminal/browser/terminalGroup.ts b/src/vs/workbench/contrib/terminal/browser/terminalGroup.ts index 062abe58d57..63ec90439d2 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalGroup.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalGroup.ts @@ -242,12 +242,14 @@ export class TerminalGroup extends Disposable implements ITerminalGroup { private _initialRelativeSizes: number[] | undefined; + private readonly _onDidDisposeInstance: Emitter = this._register(new Emitter()); + readonly onDidDisposeInstance = this._onDidDisposeInstance.event; private readonly _onDisposed: Emitter = this._register(new Emitter()); - public readonly onDisposed: Event = this._onDisposed.event; + readonly onDisposed = this._onDisposed.event; private readonly _onInstancesChanged: Emitter = this._register(new Emitter()); - readonly onInstancesChanged: Event = this._onInstancesChanged.event; + readonly onInstancesChanged = this._onInstancesChanged.event; private readonly _onPanelOrientationChanged = new Emitter(); - get onPanelOrientationChanged(): Event { return this._onPanelOrientationChanged.event; } + readonly onPanelOrientationChanged = this._onPanelOrientationChanged.event; constructor( private _container: HTMLElement | undefined, @@ -326,12 +328,15 @@ export class TerminalGroup extends Disposable implements ITerminalGroup { private _initInstanceListeners(instance: ITerminalInstance) { this._instanceDisposables.set(instance.instanceId, [ - instance.onDisposed(instance => this._onInstanceDisposed(instance)), + instance.onDisposed(instance => { + this._onDidDisposeInstance.fire(instance); + this._handleOnDidDisposeInstance(instance); + }), instance.onFocused(instance => this._setActiveInstance(instance)) ]); } - private _onInstanceDisposed(instance: ITerminalInstance) { + private _handleOnDidDisposeInstance(instance: ITerminalInstance) { this._removeInstance(instance); } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts b/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts index f0c3a2ecd0d..aa564c29113 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts @@ -28,6 +28,8 @@ export class TerminalGroupService extends Disposable implements ITerminalGroupSe private readonly _onDidChangeGroups = new Emitter(); get onDidChangeGroups(): Event { return this._onDidChangeGroups.event; } + private readonly _onDidDisposeInstance = new Emitter(); + get onDidDisposeInstance(): Event { return this._onDidDisposeInstance.event; } private readonly _onDidChangeActiveInstance = new Emitter(); get onDidChangeActiveInstance(): Event { return this._onDidChangeActiveInstance.event; } private readonly _onDidChangeInstances = new Emitter(); @@ -40,6 +42,8 @@ export class TerminalGroupService extends Disposable implements ITerminalGroupSe @IInstantiationService private readonly _instantiationService: IInstantiationService ) { super(); + + this.onDidDisposeGroup(group => this.removeGroup(group)); } get activeGroup(): ITerminalGroup | undefined { @@ -65,6 +69,7 @@ export class TerminalGroupService extends Disposable implements ITerminalGroupSe this.groups.push(group); group.addDisposable(group.onDisposed(this._onDidDisposeGroup.fire, this._onDidDisposeGroup)); group.addDisposable(group.onInstancesChanged(this._onDidChangeInstances.fire, this._onDidChangeInstances)); + group.addDisposable(group.onDidDisposeInstance(this._onDidDisposeInstance.fire, this._onDidDisposeInstance)); if (group.terminalInstances.length > 0) { this._onDidChangeInstances.fire(); } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index 83ad2d7724f..c98f6789c62 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -202,7 +202,6 @@ export class TerminalService implements ITerminalService { // 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.onGroupDisposed(group => this._terminalGroupService.removeGroup(group)); this.onInstancesChanged(() => this._terminalCountContextKey.set(this._terminalInstances.length)); this.onGroupsChanged(() => this._terminalGroupCountContextKey.set(this._terminalGroups.length)); this.onInstanceLinksReady(instance => this._setInstanceLinkProviders(instance)); @@ -215,6 +214,7 @@ export class TerminalService implements ITerminalService { this.hidePanel(); } }); + this._terminalGroupService.onDidDisposeInstance(this._onInstanceDisposed.fire, this._onInstanceDisposed); this._handleInstanceContextKeys(); this._processSupportContextKey = KEYBINDING_CONTEXT_TERMINAL_PROCESS_SUPPORTED.bindTo(this._contextKeyService); @@ -712,7 +712,7 @@ export class TerminalService implements ITerminalService { } protected _initInstanceListeners(instance: ITerminalInstance): void { - instance.addDisposable(instance.onDisposed(this._onInstanceDisposed.fire, this._onInstanceDisposed)); + // instance.addDisposable(instance.onDisposed(this._onInstanceDisposed.fire, this._onInstanceDisposed)); instance.addDisposable(instance.onTitleChanged(this._onInstanceTitleChanged.fire, this._onInstanceTitleChanged)); instance.addDisposable(instance.onIconChanged(this._onInstanceIconChanged.fire, this._onInstanceIconChanged)); instance.addDisposable(instance.onIconChanged(this._onInstanceColorChanged.fire, this._onInstanceColorChanged)); diff --git a/src/vs/workbench/contrib/terminal/browser/terminalTabbedView.ts b/src/vs/workbench/contrib/terminal/browser/terminalTabbedView.ts index 69a0e7f6d62..a96011fcb44 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalTabbedView.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalTabbedView.ts @@ -7,7 +7,7 @@ import { LayoutPriority, Orientation, Sizing, SplitView } from 'vs/base/browser/ import { Disposable, dispose, IDisposable } from 'vs/base/common/lifecycle'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { ITerminalInstance, ITerminalService, TerminalConnectionState } from 'vs/workbench/contrib/terminal/browser/terminal'; +import { ITerminalGroupService, ITerminalInstance, ITerminalService, TerminalConnectionState } from 'vs/workbench/contrib/terminal/browser/terminal'; import { TerminalFindWidget } from 'vs/workbench/contrib/terminal/browser/terminalFindWidget'; import { TerminalTabsListSizes, TerminalTabList } from 'vs/workbench/contrib/terminal/browser/terminalTabsList'; import { IThemeService, IColorTheme } from 'vs/platform/theme/common/themeService'; @@ -71,6 +71,7 @@ export class TerminalTabbedView extends Disposable { constructor( parentElement: HTMLElement, @ITerminalService private readonly _terminalService: ITerminalService, + @ITerminalGroupService private readonly _terminalGroupService: ITerminalGroupService, @IInstantiationService private readonly _instantiationService: IInstantiationService, @INotificationService private readonly _notificationService: INotificationService, @IContextMenuService private readonly _contextMenuService: IContextMenuService, @@ -129,7 +130,7 @@ export class TerminalTabbedView extends Disposable { } }); this._register(this._terminalService.onInstancesChanged(() => this._refreshShowTabs())); - this._register(this._terminalService.onGroupsChanged(() => this._refreshShowTabs())); + this._register(this._terminalGroupService.onDidChangeGroups(() => this._refreshShowTabs())); this._register(this._themeService.onDidColorThemeChange(theme => this._updateTheme(theme))); this._updateTheme(); diff --git a/src/vs/workbench/contrib/terminal/browser/terminalTabsList.ts b/src/vs/workbench/contrib/terminal/browser/terminalTabsList.ts index 96fad169355..579a9cda51c 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalTabsList.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalTabsList.ts @@ -69,6 +69,7 @@ export class TerminalTabList extends WorkbenchList { @IConfigurationService configurationService: IConfigurationService, @IKeybindingService keybindingService: IKeybindingService, @ITerminalService private _terminalService: ITerminalService, + @ITerminalGroupService terminalGroupService: ITerminalGroupService, @ITerminalInstanceService _terminalInstanceService: ITerminalInstanceService, @IInstantiationService instantiationService: IInstantiationService, @IDecorationsService _decorationsService: IDecorationsService, @@ -100,7 +101,7 @@ export class TerminalTabList extends WorkbenchList { keybindingService, ); this._terminalService.onInstancesChanged(() => this.refresh()); - this._terminalService.onGroupsChanged(() => this.refresh()); + terminalGroupService.onDidChangeGroups(() => this.refresh()); this._terminalService.onInstanceTitleChanged(() => this.refresh()); this._terminalService.onInstanceIconChanged(() => this.refresh()); this._terminalService.onInstancePrimaryStatusChanged(() => this.refresh()); diff --git a/src/vs/workbench/contrib/terminal/browser/terminalView.ts b/src/vs/workbench/contrib/terminal/browser/terminalView.ts index cdcde6f7037..e22983da455 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalView.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalView.ts @@ -322,11 +322,12 @@ class SwitchTerminalActionViewItem extends SelectActionViewItem { ) { 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.onGroupsChanged(() => this._updateItems(), this)); this._register(_terminalService.onActiveGroupChanged(() => this._updateItems(), this)); this._register(_terminalService.onActiveInstanceChanged(() => this._updateItems(), this)); this._register(_terminalService.onInstanceTitleChanged(() => this._updateItems(), this)); - this._register(_terminalService.onGroupDisposed(() => this._updateItems(), this)); + this._register(_terminalGroupService.onDidChangeGroups(() => this._updateItems(), this)); + // TODO: dispose group shouldn't be needed + // this._register(_terminalGroupService.onDidDisposeGroup(() => this._updateItems(), this)); this._register(_terminalService.onDidChangeConnectionState(() => this._updateItems(), this)); this._register(_terminalService.onDidChangeAvailableProfiles(() => this._updateItems(), this)); this._register(attachSelectBoxStyler(this.selectBox, this._themeService)); @@ -525,7 +526,8 @@ class TerminalThemeIconStyle extends Themable { constructor( container: HTMLElement, @IThemeService private readonly _themeService: IThemeService, - @ITerminalService private readonly _terminalService: ITerminalService + @ITerminalService private readonly _terminalService: ITerminalService, + @ITerminalGroupService private readonly _terminalGroupService: ITerminalGroupService ) { super(_themeService); this._registerListeners(); @@ -539,7 +541,7 @@ class TerminalThemeIconStyle extends Themable { 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.onGroupsChanged(() => this.updateStyles())); + this._register(this._terminalGroupService.onDidChangeGroups(() => this.updateStyles())); } override updateStyles(): void { From 3f5f2e946e45fee9a036f07310cc8296ed9858df Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 18 Jun 2021 06:40:32 -0700 Subject: [PATCH 10/31] Bubble instances changed event --- .../contrib/terminal/browser/terminalGroupService.ts | 4 ++-- src/vs/workbench/contrib/terminal/browser/terminalService.ts | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts b/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts index aa564c29113..16ab6335505 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts @@ -67,9 +67,9 @@ export class TerminalGroupService extends Disposable implements ITerminalGroupSe // TODO: Move panel orientation change into this file so it's not fired many times group.onPanelOrientationChanged((orientation) => this._onPanelOrientationChanged.fire(orientation)); this.groups.push(group); - group.addDisposable(group.onDisposed(this._onDidDisposeGroup.fire, this._onDidDisposeGroup)); - group.addDisposable(group.onInstancesChanged(this._onDidChangeInstances.fire, this._onDidChangeInstances)); group.addDisposable(group.onDidDisposeInstance(this._onDidDisposeInstance.fire, this._onDidDisposeInstance)); + group.addDisposable(group.onInstancesChanged(this._onDidChangeInstances.fire, this._onDidChangeInstances)); + group.addDisposable(group.onDisposed(this._onDidDisposeGroup.fire, this._onDidDisposeGroup)); if (group.terminalInstances.length > 0) { this._onDidChangeInstances.fire(); } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index c98f6789c62..1c06ac2799d 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -215,6 +215,7 @@ export class TerminalService implements ITerminalService { } }); this._terminalGroupService.onDidDisposeInstance(this._onInstanceDisposed.fire, this._onInstanceDisposed); + this._terminalGroupService.onDidChangeInstances(this._onInstancesChanged.fire, this._onInstancesChanged); this._handleInstanceContextKeys(); this._processSupportContextKey = KEYBINDING_CONTEXT_TERMINAL_PROCESS_SUPPORTED.bindTo(this._contextKeyService); @@ -584,6 +585,7 @@ export class TerminalService implements ITerminalService { return instance; } + // TODO: Move to group service unsplitInstance(instance: ITerminalInstance): void { const oldGroup = this.getGroupForInstance(instance); if (!oldGroup || oldGroup.terminalInstances.length < 2) { @@ -594,6 +596,7 @@ export class TerminalService implements ITerminalService { this._terminalGroupService.createGroup(instance); } + // TODO: Move to group service joinInstances(instances: ITerminalInstance[]): void { // Find the group of the first instance that is the only instance in the group, if one exists let candidateInstance: ITerminalInstance | undefined = undefined; From 1c55ecdcc96f69d2af56ac35cbc2f69d63248b90 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 18 Jun 2021 06:58:00 -0700 Subject: [PATCH 11/31] Introduce term instance host interface --- .../api/browser/mainThreadTerminalService.ts | 18 ++-- .../contrib/remote/browser/urlFinder.ts | 4 +- .../tasks/browser/terminalTaskSystem.ts | 4 +- .../contrib/terminal/browser/terminal.ts | 35 ++++---- .../terminal/browser/terminalActions.ts | 54 ++++++------ .../terminal/browser/terminalFindWidget.ts | 12 +-- .../terminal/browser/terminalService.ts | 82 +++++++++---------- .../terminal/browser/terminalTabbedView.ts | 18 ++-- .../terminal/browser/terminalTabsList.ts | 8 +- .../contrib/terminal/browser/terminalView.ts | 28 +++---- .../terminalNativeContribution.ts | 4 +- .../browser/testingOutputTerminalService.ts | 4 +- 12 files changed, 135 insertions(+), 136 deletions(-) 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; From 96f2421adcd5c8b82a5f517623b6e9f8a12f43fe Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 18 Jun 2021 07:02:43 -0700 Subject: [PATCH 12/31] Forward host events helper --- .../terminal/browser/terminalEditorService.ts | 1 + .../contrib/terminal/browser/terminalService.ts | 12 +++++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalEditorService.ts b/src/vs/workbench/contrib/terminal/browser/terminalEditorService.ts index f43c571f761..5bccaac7d11 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalEditorService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalEditorService.ts @@ -9,6 +9,7 @@ import { TerminalEditorInput } from 'vs/workbench/contrib/terminal/browser/termi import { TerminalLocation } from 'vs/workbench/contrib/terminal/common/terminal'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; +// TODO: Implement ITerminalInstanceHost export class TerminalEditorService extends Disposable implements ITerminalEditorService { declare _serviceBrand: undefined; diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index 81668bc1a7b..3d2e78dd644 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -28,7 +28,7 @@ import { registerTerminalDefaultProfileConfiguration } from 'vs/platform/termina import { ThemeIcon } from 'vs/platform/theme/common/themeService'; import { VirtualWorkspaceContext } from 'vs/workbench/browser/contextkeys'; import { IEditableData, IViewDescriptorService, IViewsService, ViewContainerLocation } from 'vs/workbench/common/views'; -import { ICreateTerminalOptions, IRemoteTerminalService, ITerminalEditorService, ITerminalExternalLinkProvider, ITerminalGroup, ITerminalGroupService, ITerminalInstance, ITerminalProfileProvider, ITerminalService, TerminalConnectionState } from 'vs/workbench/contrib/terminal/browser/terminal'; +import { ICreateTerminalOptions, IRemoteTerminalService, ITerminalEditorService, ITerminalExternalLinkProvider, ITerminalGroup, ITerminalGroupService, ITerminalInstance, ITerminalInstanceHost, ITerminalProfileProvider, ITerminalService, TerminalConnectionState } from 'vs/workbench/contrib/terminal/browser/terminal'; import { TerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminalConfigHelper'; import { TerminalEditor } from 'vs/workbench/contrib/terminal/browser/terminalEditor'; import { configureTerminalProfileIcon } from 'vs/workbench/contrib/terminal/browser/terminalIcons'; @@ -195,6 +195,8 @@ export class TerminalService implements ITerminalService { } ); + this._forwardInstanceHostEvents(this._terminalGroupService); + // 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 @@ -211,8 +213,6 @@ export class TerminalService implements ITerminalService { this.hidePanel(); } }); - 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); @@ -260,6 +260,12 @@ export class TerminalService implements ITerminalService { this._refreshAvailableProfiles(); } + private _forwardInstanceHostEvents(host: ITerminalInstanceHost) { + host.onDidDisposeInstance(this._onDidChangeActiveInstance.fire, this._onDidChangeActiveInstance); + host.onDidDisposeInstance(this._onDidDisposeInstance.fire, this._onDidDisposeInstance); + host.onDidChangeInstances(this._onDidChangeInstances.fire, this._onDidChangeInstances); + } + async safeDisposeTerminal(instance: ITerminalInstance): Promise { if (this.configHelper.config.confirmOnExit) { const notConfirmed = await this._showTerminalCloseConfirmation(true); From 436e3ffca87109004d9f1246f0bd55a2a186417d Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 18 Jun 2021 07:45:28 -0700 Subject: [PATCH 13/31] Track active instance in editor service --- .../contrib/terminal/browser/terminal.ts | 4 +- .../terminal/browser/terminalEditorService.ts | 55 +++++++++++++++++-- .../terminal/browser/terminalService.ts | 23 ++++++-- 3 files changed, 70 insertions(+), 12 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index 1d98964fbc7..918eeec561b 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -221,10 +221,10 @@ export interface ITerminalService extends ITerminalInstanceHost { * This service is responsible for integrating with the editor service and managing terminal * editors. */ -export interface ITerminalEditorService { +export interface ITerminalEditorService extends ITerminalInstanceHost { readonly _serviceBrand: undefined; - readonly terminalEditorInstances: ITerminalInstance[]; + readonly instances: ITerminalInstance[]; createEditor(instance: ITerminalInstance): Promise; createEditorInput(instance: ITerminalInstance): TerminalEditorInput; diff --git a/src/vs/workbench/contrib/terminal/browser/terminalEditorService.ts b/src/vs/workbench/contrib/terminal/browser/terminalEditorService.ts index 5bccaac7d11..55aeda9901e 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalEditorService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalEditorService.ts @@ -3,7 +3,8 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Disposable } from 'vs/base/common/lifecycle'; +import { Emitter, Event } from 'vs/base/common/event'; +import { Disposable, dispose, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { ITerminalEditorService, ITerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminal'; import { TerminalEditorInput } from 'vs/workbench/contrib/terminal/browser/terminalEditorInput'; import { TerminalLocation } from 'vs/workbench/contrib/terminal/common/terminal'; @@ -13,16 +14,48 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic export class TerminalEditorService extends Disposable implements ITerminalEditorService { declare _serviceBrand: undefined; - terminalEditorInstances: ITerminalInstance[] = []; + instances: ITerminalInstance[] = []; + private _activeInstanceIndex: number = -1; private _editorInputs: Map = new Map(); + private _instanceDisposables: Map = new Map(); + + private readonly _onDidDisposeInstance = new Emitter(); + get onDidDisposeInstance(): Event { return this._onDidDisposeInstance.event; } + private readonly _onDidChangeActiveInstance = new Emitter(); + get onDidChangeActiveInstance(): Event { return this._onDidChangeActiveInstance.event; } + private readonly _onDidChangeInstances = new Emitter(); + get onDidChangeInstances(): Event { return this._onDidChangeInstances.event; } constructor( @IEditorService private readonly _editorService: IEditorService ) { super(); - // TODO: Multiplex instance events + this._register(toDisposable(() => { + for (const d of this._instanceDisposables.values()) { + dispose(d); + } + })); + this._register(this._editorService.onDidActiveEditorChange(() => { + const oldActiveIndex = this._activeInstanceIndex; + const activeEditor = this._editorService.activeEditor; + if (activeEditor instanceof TerminalEditorInput) { + this._activeInstanceIndex = this.instances.findIndex(e => activeEditor.terminalInstance === e); + } else { + this._activeInstanceIndex = -1; + } + if (oldActiveIndex !== this._activeInstanceIndex) { + this._onDidChangeActiveInstance.fire(this.activeInstance); + } + })); + } + + get activeInstance(): ITerminalInstance | undefined { + if (this.instances.length === 0 || this._activeInstanceIndex === -1) { + return undefined; + } + return this.instances[this._activeInstanceIndex]; } async createEditor(instance: ITerminalInstance): Promise { @@ -31,13 +64,17 @@ export class TerminalEditorService extends Disposable implements ITerminalEditor pinned: true, forceReload: true }); - this.terminalEditorInstances.push(instance); + this.instances.push(instance); } createEditorInput(instance: ITerminalInstance): TerminalEditorInput { const input = new TerminalEditorInput(instance); instance.target = TerminalLocation.Editor; this._editorInputs.set(instance.instanceId, input); + this._instanceDisposables.set(instance.instanceId, [ + instance.onDisposed(this._onDidDisposeInstance.fire, this._onDidDisposeInstance) + ]); + this._onDidChangeInstances.fire(); return input; } @@ -58,10 +95,16 @@ export class TerminalEditorService extends Disposable implements ITerminalEditor const editorInput = this._editorInputs.get(instance.instanceId); editorInput?.detachInstance(); this._editorInputs.delete(instance.instanceId); - const instanceIndex = this.terminalEditorInstances.findIndex(e => e === instance); + const instanceIndex = this.instances.findIndex(e => e === instance); if (instanceIndex !== -1) { - this.terminalEditorInstances.splice(instanceIndex, 1); + this.instances.splice(instanceIndex, 1); } editorInput?.dispose(); + const disposables = this._instanceDisposables.get(instance.instanceId); + this._instanceDisposables.delete(instance.instanceId); + if (disposables) { + dispose(disposables); + } + this._onDidChangeInstances.fire(); } } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index 3d2e78dd644..f77db06fc53 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -48,6 +48,7 @@ export class TerminalService implements ITerminalService { declare _serviceBrand: undefined; private get _terminalGroups(): readonly ITerminalGroup[] { return this._terminalGroupService.groups; } + private _hostActiveTerminals: Map = new Map(); private _isShuttingDown: boolean; private _terminalFocusContextKey: IContextKey; @@ -183,7 +184,7 @@ export class TerminalService implements ITerminalService { } else { instance = this.createInstance({}); } - this._terminalEditorService.terminalEditorInstances.push(instance); + this._terminalEditorService.instances.push(instance); return { editor: this._terminalEditorService.createEditorInput(instance), options: { @@ -196,6 +197,7 @@ export class TerminalService implements ITerminalService { ); this._forwardInstanceHostEvents(this._terminalGroupService); + this._forwardInstanceHostEvents(this._terminalEditorService); // the below avoids having to poll routinely. // we update detected profiles when an instance is created so that, @@ -261,9 +263,22 @@ export class TerminalService implements ITerminalService { } private _forwardInstanceHostEvents(host: ITerminalInstanceHost) { - host.onDidDisposeInstance(this._onDidChangeActiveInstance.fire, this._onDidChangeActiveInstance); - host.onDidDisposeInstance(this._onDidDisposeInstance.fire, this._onDidDisposeInstance); host.onDidChangeInstances(this._onDidChangeInstances.fire, this._onDidChangeInstances); + host.onDidDisposeInstance(this._onDidDisposeInstance.fire, this._onDidDisposeInstance); + // Track the latest active terminal for each host so that when one becomes undefined (eg. + // the last terminal editor is closed) + this._hostActiveTerminals.set(host, undefined); + host.onDidChangeActiveInstance(instance => { + this._hostActiveTerminals.set(host, instance); + if (instance === undefined) { + for (const active of this._hostActiveTerminals.values()) { + if (active) { + instance = active; + } + } + } + this._onDidChangeActiveInstance.fire(instance); + }); } async safeDisposeTerminal(instance: ITerminalInstance): Promise { @@ -745,7 +760,7 @@ export class TerminalService implements ITerminalService { } // Terminal editors - sourceInstance = this._terminalEditorService.terminalEditorInstances.find(instance => instance.resource.path === e.uri.path); + sourceInstance = this._terminalEditorService.instances.find(instance => instance.resource.path === e.uri.path); if (sourceInstance) { this.moveToTerminalView(sourceInstance, instance, e.side); } From 83086e6821dd382e95c37133c0f5e19c79f1cfe6 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 18 Jun 2021 07:55:05 -0700 Subject: [PATCH 14/31] Track last active instance in term service --- .../workbench/contrib/terminal/browser/terminalService.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index f77db06fc53..3f2246a1328 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -47,6 +47,8 @@ import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteA export class TerminalService implements ITerminalService { declare _serviceBrand: undefined; + private _activeInstance: ITerminalInstance | undefined; + get activeInstance(): ITerminalInstance | undefined { return this._activeInstance; } private get _terminalGroups(): readonly ITerminalGroup[] { return this._terminalGroupService.groups; } private _hostActiveTerminals: Map = new Map(); @@ -277,6 +279,7 @@ export class TerminalService implements ITerminalService { } } } + this._activeInstance = instance; this._onDidChangeActiveInstance.fire(instance); }); } @@ -524,11 +527,6 @@ export class TerminalService implements ITerminalService { this._onActiveGroupChanged.fire(); } - 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.activeInstance; if (instance) { From 74243095bf29704eb1599db6ae84c780167c9859 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 18 Jun 2021 08:09:08 -0700 Subject: [PATCH 15/31] Make set active instance a setter --- .../api/browser/mainThreadTerminalService.ts | 2 +- .../browser/externalTerminal.contribution.ts | 2 +- .../quickaccess/browser/viewQuickAccess.ts | 2 +- .../tasks/browser/terminalTaskSystem.ts | 12 ++--- .../contrib/terminal/browser/terminal.ts | 3 +- .../terminal/browser/terminalActions.ts | 16 +++--- .../terminal/browser/terminalEditorService.ts | 22 ++++---- .../terminal/browser/terminalGroupService.ts | 20 +++++++ .../terminal/browser/terminalQuickAccess.ts | 2 +- .../terminal/browser/terminalService.ts | 53 ++++++++++--------- .../terminal/browser/terminalTabsList.ts | 10 ++-- .../electron-sandbox/terminalRemote.ts | 2 +- .../browser/testingOutputTerminalService.ts | 4 +- 13 files changed, 89 insertions(+), 61 deletions(-) diff --git a/src/vs/workbench/api/browser/mainThreadTerminalService.ts b/src/vs/workbench/api/browser/mainThreadTerminalService.ts index f437285b00d..a1206838e28 100644 --- a/src/vs/workbench/api/browser/mainThreadTerminalService.ts +++ b/src/vs/workbench/api/browser/mainThreadTerminalService.ts @@ -159,7 +159,7 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape public $show(id: TerminalIdentifier, preserveFocus: boolean): void { const terminalInstance = this._getTerminalInstance(id); if (terminalInstance) { - this._terminalService.setActiveInstance(terminalInstance); + this._terminalService.activeInstance = terminalInstance; this._terminalService.showPanel(!preserveFocus); } } diff --git a/src/vs/workbench/contrib/externalTerminal/browser/externalTerminal.contribution.ts b/src/vs/workbench/contrib/externalTerminal/browser/externalTerminal.contribution.ts index e2d7b40f433..4cfa593f991 100644 --- a/src/vs/workbench/contrib/externalTerminal/browser/externalTerminal.contribution.ts +++ b/src/vs/workbench/contrib/externalTerminal/browser/externalTerminal.contribution.ts @@ -66,7 +66,7 @@ CommandsRegistry.registerCommand({ opened[cwd.path] = true; const instance = integratedTerminalService.createTerminal({ config: { cwd } }); if (instance && (resources.length === 1 || !resource || cwd.path === resource.path || cwd.path === dirname(resource.path))) { - integratedTerminalService.setActiveInstance(instance); + integratedTerminalService.activeInstance = instance; integratedTerminalService.showPanel(true); } }); diff --git a/src/vs/workbench/contrib/quickaccess/browser/viewQuickAccess.ts b/src/vs/workbench/contrib/quickaccess/browser/viewQuickAccess.ts index f29bdac9e6a..eeac76679bb 100644 --- a/src/vs/workbench/contrib/quickaccess/browser/viewQuickAccess.ts +++ b/src/vs/workbench/contrib/quickaccess/browser/viewQuickAccess.ts @@ -156,7 +156,7 @@ export class ViewQuickAccessProvider extends PickerQuickAccessProvider { await this.terminalService.showPanel(true); - this.terminalService.setActiveInstance(terminal); + this.terminalService.activeInstance = terminal; } }); }); diff --git a/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts b/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts index 31e420ae126..61483e881d7 100644 --- a/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts +++ b/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts @@ -324,7 +324,7 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { if (isTerminalInPanel && this.isTaskVisible(task)) { if (this.previousPanelId) { if (this.previousTerminalInstance) { - this.terminalService.setActiveInstance(this.previousTerminalInstance); + this.terminalService.activeInstance = this.previousTerminalInstance; } this.panelService.openPanel(this.previousPanelId); } else { @@ -339,7 +339,7 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { this.previousTerminalInstance = this.terminalService.activeInstance ?? undefined; } } - this.terminalService.setActiveInstance(terminalData.terminal); + this.terminalService.activeInstance = terminalData.terminal; if (CustomTask.is(task) || ContributedTask.is(task)) { this.terminalService.showPanel(task.command.presentation!.focus); } @@ -770,7 +770,7 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { if (revealProblems === RevealProblemKind.OnProblem) { this.viewsService.openView(Constants.MARKERS_VIEW_ID, true); } else if (reveal === RevealKind.Silent) { - this.terminalService.setActiveInstance(terminal!); + this.terminalService.activeInstance = terminal; this.terminalService.showPanel(false); } } @@ -839,7 +839,7 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { if ((reveal === RevealKind.Silent) && ((exitCode !== 0) || (watchingProblemMatcher.numberOfMatches > 0) && watchingProblemMatcher.maxMarkerSeverity && (watchingProblemMatcher.maxMarkerSeverity >= MarkerSeverity.Error))) { try { - this.terminalService.setActiveInstance(terminal!); + this.terminalService.activeInstance = terminal; this.terminalService.showPanel(false); } catch (e) { // If the terminal has already been disposed, then setting the active instance will fail. #99828 @@ -924,7 +924,7 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { } else if (terminal && (reveal === RevealKind.Silent) && ((exitCode !== 0) || (startStopProblemMatcher.numberOfMatches > 0) && startStopProblemMatcher.maxMarkerSeverity && (startStopProblemMatcher.maxMarkerSeverity >= MarkerSeverity.Error))) { try { - this.terminalService.setActiveInstance(terminal); + this.terminalService.activeInstance = terminal; this.terminalService.showPanel(false); } catch (e) { // If the terminal has already been disposed, then setting the active instance will fail. #99828 @@ -957,7 +957,7 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { if (showProblemPanel) { this.viewsService.openView(Constants.MARKERS_VIEW_ID); } else if (task.command.presentation && (task.command.presentation.reveal === RevealKind.Always)) { - this.terminalService.setActiveInstance(terminal); + this.terminalService.activeInstance = terminal; this.terminalService.showPanel(task.command.presentation.focus); } this.activeTasks[task.getMapKey()] = { terminal, task, promise }; diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index 918eeec561b..610938f7587 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -155,7 +155,6 @@ export interface ITerminalService extends ITerminalInstanceHost { getInstanceFromId(terminalId: number): ITerminalInstance | undefined; getInstanceFromIndex(terminalIndex: number): ITerminalInstance; getGroupLabels(): string[]; - setActiveInstance(terminalInstance: ITerminalInstance): void; getActiveOrCreateInstance(): ITerminalInstance; splitInstance(instance: ITerminalInstance, shell?: IShellLaunchConfig, cwd?: string | URI): ITerminalInstance | null; splitInstance(instance: ITerminalInstance, profile: ITerminalProfile): ITerminalInstance | null; @@ -281,8 +280,8 @@ export interface ITerminalGroupService extends ITerminalInstanceHost { * properties and events. */ export interface ITerminalInstanceHost { + activeInstance: ITerminalInstance | undefined; readonly instances: readonly ITerminalInstance[]; - readonly activeInstance: ITerminalInstance | undefined; readonly onDidDisposeInstance: Event; readonly onDidChangeActiveInstance: Event; diff --git a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts index a86c2407adc..88fd8144c95 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts @@ -118,7 +118,7 @@ export function registerTerminalActions() { if (!instance) { return; } - terminalService.setActiveInstance(instance); + terminalService.activeInstance = instance; } await terminalService.showPanel(true); } @@ -184,7 +184,7 @@ export function registerTerminalActions() { } if (instance) { - terminalService.setActiveInstance(instance); + terminalService.activeInstance = instance; } } await terminalService.showPanel(true); @@ -399,7 +399,7 @@ export function registerTerminalActions() { if (!instance) { return; } - terminalService.setActiveInstance(instance); + terminalService.activeInstance = instance; return terminalService.showPanel(true); } }); @@ -945,7 +945,7 @@ export function registerTerminalActions() { const instance = terminalService.createTerminal({ config: { attachPersistentProcess: selected.term } }); - terminalService.setActiveInstance(instance); + terminalService.activeInstance = instance; terminalService.showPanel(true); } } @@ -1163,7 +1163,7 @@ export function registerTerminalActions() { if (!instance) { return; } - terminalService.setActiveInstance(instance); + terminalService.activeInstance = instance; } return terminalService.showPanel(true); } @@ -1436,7 +1436,7 @@ export function registerTerminalActions() { const instances = getSelectedInstances(accessor); if (instances) { for (const t of instances) { - terminalService.setActiveInstance(t); + terminalService.activeInstance = t; terminalService.doWithActiveInstance(async instance => { const cwd = await getCwdForSplit(terminalService.configHelper, instance); terminalService.splitInstance(instance, { cwd }); @@ -1596,7 +1596,7 @@ export function registerTerminalActions() { } ); } - terminalService.setActiveInstance(instance); + terminalService.activeInstance = instance; } await terminalService.showPanel(true); } @@ -1836,7 +1836,7 @@ export function registerTerminalActions() { { config: profile }); - terminalService.setActiveInstance(instance); + terminalService.activeInstance = instance; } else { console.warn(`No profile with name "${profileSelection}"`); } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalEditorService.ts b/src/vs/workbench/contrib/terminal/browser/terminalEditorService.ts index 55aeda9901e..1f854c55ed2 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalEditorService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalEditorService.ts @@ -38,16 +38,8 @@ export class TerminalEditorService extends Disposable implements ITerminalEditor } })); this._register(this._editorService.onDidActiveEditorChange(() => { - const oldActiveIndex = this._activeInstanceIndex; const activeEditor = this._editorService.activeEditor; - if (activeEditor instanceof TerminalEditorInput) { - this._activeInstanceIndex = this.instances.findIndex(e => activeEditor.terminalInstance === e); - } else { - this._activeInstanceIndex = -1; - } - if (oldActiveIndex !== this._activeInstanceIndex) { - this._onDidChangeActiveInstance.fire(this.activeInstance); - } + this.activeInstance = activeEditor instanceof TerminalEditorInput ? activeEditor?.terminalInstance : undefined; })); } @@ -58,6 +50,18 @@ export class TerminalEditorService extends Disposable implements ITerminalEditor return this.instances[this._activeInstanceIndex]; } + set activeInstance(value: ITerminalInstance | undefined) { + const oldActiveIndex = this._activeInstanceIndex; + if (value === undefined) { + this._activeInstanceIndex = -1; + } else { + this._activeInstanceIndex = this.instances.findIndex(e => e === value); + } + if (oldActiveIndex !== this._activeInstanceIndex) { + this._onDidChangeActiveInstance.fire(this.activeInstance); + } + } + async createEditor(instance: ITerminalInstance): Promise { const input = this.createEditorInput(instance); await this._editorService.openEditor(input, { diff --git a/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts b/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts index 16ab6335505..194541f5529 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts @@ -57,6 +57,26 @@ export class TerminalGroupService extends Disposable implements ITerminalGroupSe return this.activeGroup?.activeInstance; } + set activeInstance(value: ITerminalInstance | undefined) { + if (value === undefined) { + return; + } + this.setActiveInstanceByIndex(this._getIndexFromId(value.instanceId)); + } + + private _getIndexFromId(terminalId: number): number { + let terminalIndex = -1; + this.instances.forEach((terminalInstance, i) => { + if (terminalInstance.instanceId === terminalId) { + terminalIndex = i; + } + }); + if (terminalIndex === -1) { + throw new Error(`Terminal with ID ${terminalId} does not exist (has it already been disposed?)`); + } + return terminalIndex; + } + setContainer(container: HTMLElement) { this._container = container; this.groups.forEach(group => group.attachToElement(container)); diff --git a/src/vs/workbench/contrib/terminal/browser/terminalQuickAccess.ts b/src/vs/workbench/contrib/terminal/browser/terminalQuickAccess.ts index 4842e563fc0..8aa4cc96d2e 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalQuickAccess.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalQuickAccess.ts @@ -75,7 +75,7 @@ export class TerminalQuickAccessProvider extends PickerQuickAccessProvider { - this._terminalService.setActiveInstance(terminal); + this._terminalService.activeInstance = terminal; this._terminalService.showPanel(!event.inBackground); } }); diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index 3f2246a1328..d7c5c636d9e 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -47,8 +47,6 @@ import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteA export class TerminalService implements ITerminalService { declare _serviceBrand: undefined; - private _activeInstance: ITerminalInstance | undefined; - get activeInstance(): ITerminalInstance | undefined { return this._activeInstance; } private get _terminalGroups(): readonly ITerminalGroup[] { return this._terminalGroupService.groups; } private _hostActiveTerminals: Map = new Map(); @@ -84,10 +82,28 @@ export class TerminalService implements ITerminalService { return this._availableProfiles || []; } get configHelper(): ITerminalConfigHelper { return this._configHelper; } - private get _terminalInstances(): ITerminalInstance[] { + get instances(): ITerminalInstance[] { + // TODO: Also return editors here return this._terminalGroups.reduce((p, c) => p.concat(c.terminalInstances), []); } - get instances(): ITerminalInstance[] { return this._terminalInstances; } + + private _activeInstance: ITerminalInstance | undefined; + get activeInstance(): ITerminalInstance | undefined { return this._activeInstance; } + set activeInstance(value: ITerminalInstance | undefined) { + if (value === undefined) { + throw new Error('Cannot set active instance to undefined'); + } + // If this was a hideFromUser terminal created by the API this was triggered by show, + // in which case we need to create the terminal group + if (value.shellLaunchConfig.hideFromUser) { + this._showBackgroundTerminal(value); + } + if (value.target === TerminalLocation.Editor) { + this._terminalEditorService.activeInstance = value; + } else { + this._terminalGroupService.activeInstance = value; + } + } private readonly _onActiveGroupChanged = new Emitter(); get onActiveGroupChanged(): Event { return this._onActiveGroupChanged.event; } @@ -205,7 +221,7 @@ export class TerminalService implements ITerminalService { // 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.onDidChangeInstances(() => this._terminalCountContextKey.set(this._terminalInstances.length)); + this.onDidChangeInstances(() => this._terminalCountContextKey.set(this.instances.length)); this.onGroupsChanged(() => this._terminalGroupCountContextKey.set(this._terminalGroups.length)); this.onInstanceLinksReady(instance => this._setInstanceLinkProviders(instance)); @@ -358,7 +374,7 @@ export class TerminalService implements ITerminalService { return t.shellLaunchConfig.attachPersistentProcess?.id === groupLayout.activePersistentProcessId; }); if (activeInstance) { - this.setActiveInstance(activeInstance); + this.activeInstance = activeInstance; } group?.resizePanes(groupLayout.terminals.map(terminal => terminal.relativeSize)); } @@ -555,19 +571,6 @@ export class TerminalService implements ITerminalService { return this.instances[terminalIndex]; } - setActiveInstance(terminalInstance: ITerminalInstance): void { - if (this.configHelper.config.creationTarget === TerminalLocation.Editor) { - return; - } - // If this was a hideFromUser terminal created by the API this was triggered by show, - // in which case we need to create the terminal group - if (terminalInstance.shellLaunchConfig.hideFromUser) { - this._showBackgroundTerminal(terminalInstance); - } - // TODO: Handle editor terminals too - this._terminalGroupService.setActiveInstanceByIndex(this._getIndexFromId(terminalInstance.instanceId)); - } - isAttachedToTerminal(remoteTerm: IRemoteTerminalAttachTarget): boolean { return this.instances.some(term => term.processId === remoteTerm.pid); } @@ -648,7 +651,7 @@ export class TerminalService implements ITerminalService { } // Set the active terminal - this.setActiveInstance(instances[0]); + this.activeInstance = instances[0]; // Fire events this._onDidChangeInstances.fire(); @@ -658,6 +661,7 @@ export class TerminalService implements ITerminalService { } moveInstance(source: ITerminalInstance, target: ITerminalInstance, side: 'before' | 'after'): void { + // TODO: Move into group service const sourceGroup = this.getGroupForInstance(source); const targetGroup = this.getGroupForInstance(target); if (!sourceGroup || !targetGroup) { @@ -713,7 +717,7 @@ export class TerminalService implements ITerminalService { } group.addInstance(source); - this.setActiveInstance(source); + this.activeInstance = source; await this.showPanel(true); // TODO: Shouldn't this happen automatically? source.setVisible(true); @@ -843,7 +847,7 @@ export class TerminalService implements ITerminalService { } async focusTabs(): Promise { - if (this._terminalInstances.length === 0) { + if (this.instances.length === 0) { return; } await this.showPanel(true); @@ -855,6 +859,7 @@ export class TerminalService implements ITerminalService { this._configurationService.updateValue(TerminalSettingId.TabsEnabled, true); } + // TODO: Remove this, it should live in group/editor servioce private _getIndexFromId(terminalId: number): number { let terminalIndex = -1; this.instances.forEach((terminalInstance, i) => { @@ -977,7 +982,7 @@ export class TerminalService implements ITerminalService { if (instance && this.configHelper.config.creationTarget === TerminalLocation.TerminalView) { this.showPanel(true); - this.setActiveInstance(instance); + this.activeInstance = instance; return instance; } } else { // setDefault @@ -1015,7 +1020,7 @@ export class TerminalService implements ITerminalService { } try { await profileProvider.createContributedTerminalProfile(isSplitTerminal); - this._terminalGroupService.setActiveInstanceByIndex(this._terminalInstances.length - 1); + this._terminalGroupService.setActiveInstanceByIndex(this.instances.length - 1); await this.activeInstance?.focusWhenReady(); } catch (e) { this._notificationService.error(e.message); diff --git a/src/vs/workbench/contrib/terminal/browser/terminalTabsList.ts b/src/vs/workbench/contrib/terminal/browser/terminalTabsList.ts index b264c1cce75..c87963ca100 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalTabsList.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalTabsList.ts @@ -118,7 +118,7 @@ export class TerminalTabList extends WorkbenchList { this.onMouseDblClick(async () => { if (this.getFocus().length === 0) { const instance = this._terminalService.createTerminal(); - this._terminalService.setActiveInstance(instance); + this._terminalService.activeInstance = instance; await instance.focusWhenReady(); } }); @@ -163,7 +163,7 @@ export class TerminalTabList extends WorkbenchList { if (e.editorOptions.pinned) { return; } - this._terminalService.setActiveInstance(instance); + this._terminalService.activeInstance = instance; if (!e.editorOptions.preserveFocus) { await instance.focusWhenReady(); } @@ -569,7 +569,7 @@ class TerminalTabsDragAndDrop implements IListDragAndDrop { if (didChangeAutoFocusInstance) { this._autoFocusDisposable = disposableTimeout(() => { - this._terminalService.setActiveInstance(targetInstance); + this._terminalService.activeInstance = targetInstance; this._autoFocusInstance = undefined; }, 500); } @@ -613,7 +613,7 @@ class TerminalTabsDragAndDrop implements IListDragAndDrop { for (const instance of sourceInstances) { this._terminalGroupService.moveGroup(instance, targetInstance); if (!focused) { - this._terminalService.setActiveInstance(instance); + this._terminalService.activeInstance = instance; focused = true; } } @@ -638,7 +638,7 @@ class TerminalTabsDragAndDrop implements IListDragAndDrop { return; } - this._terminalService.setActiveInstance(instance); + this._terminalService.activeInstance = instance; const preparedPath = await this._terminalInstanceService.preparePathForTerminalAsync(path, instance.shellLaunchConfig.executable, instance.title, instance.shellType, instance.isRemote); instance.sendText(preparedPath, false); diff --git a/src/vs/workbench/contrib/terminal/electron-sandbox/terminalRemote.ts b/src/vs/workbench/contrib/terminal/electron-sandbox/terminalRemote.ts index 9743f3c138c..2739f6b7f30 100644 --- a/src/vs/workbench/contrib/terminal/electron-sandbox/terminalRemote.ts +++ b/src/vs/workbench/contrib/terminal/electron-sandbox/terminalRemote.ts @@ -35,7 +35,7 @@ export class CreateNewLocalTerminalAction extends Action { return Promise.resolve(undefined); } - this._terminalService.setActiveInstance(instance); + this._terminalService.activeInstance = instance; return this._terminalService.showPanel(true); } } diff --git a/src/vs/workbench/contrib/testing/browser/testingOutputTerminalService.ts b/src/vs/workbench/contrib/testing/browser/testingOutputTerminalService.ts index ad63dc72cdf..aacb2d01bbb 100644 --- a/src/vs/workbench/contrib/testing/browser/testingOutputTerminalService.ts +++ b/src/vs/workbench/contrib/testing/browser/testingOutputTerminalService.ts @@ -87,7 +87,7 @@ export class TestingOutputTerminalService implements ITestingOutputTerminalServi // If there's an existing terminal for the attempted reveal, show that instead. const existing = testOutputPtys.find(([, o]) => o.resultId === result?.id); if (existing) { - this.terminalService.setActiveInstance(existing[0]); + this.terminalService.activeInstance = existing[0]; this.terminalService.showPanel(); return; } @@ -113,7 +113,7 @@ export class TestingOutputTerminalService implements ITestingOutputTerminalServi private async showResultsInTerminal(terminal: ITerminalInstance, output: TestOutputProcess, result: ITestResult | undefined) { this.outputTerminals.set(terminal, output); output.resetFor(result?.id, getTitle(result)); - this.terminalService.setActiveInstance(terminal); + this.terminalService.activeInstance = terminal; this.terminalService.showPanel(); if (!result) { From 8676a3c6a7045d1350dcf88c6e08f26a4490bae4 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 18 Jun 2021 08:17:54 -0700 Subject: [PATCH 16/31] Fix group service instances --- .../contrib/terminal/browser/terminalGroupService.ts | 11 ++++------- .../contrib/terminal/browser/terminalService.ts | 3 +-- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts b/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts index 194541f5529..c6edabdb971 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts @@ -16,7 +16,9 @@ export class TerminalGroupService extends Disposable implements ITerminalGroupSe groups: ITerminalGroup[] = []; activeGroupIndex: number = -1; - instances: ITerminalInstance[] = []; + get instances(): ITerminalInstance[] { + return this.groups.reduce((p, c) => p.concat(c.terminalInstances), [] as ITerminalInstance[]); + } activeInstanceIndex: number = -1; private _container: HTMLElement | undefined; @@ -65,12 +67,7 @@ export class TerminalGroupService extends Disposable implements ITerminalGroupSe } private _getIndexFromId(terminalId: number): number { - let terminalIndex = -1; - this.instances.forEach((terminalInstance, i) => { - if (terminalInstance.instanceId === terminalId) { - terminalIndex = i; - } - }); + let terminalIndex = this.instances.findIndex(e => e.instanceId === terminalId); if (terminalIndex === -1) { throw new Error(`Terminal with ID ${terminalId} does not exist (has it already been disposed?)`); } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index d7c5c636d9e..5facbf36b4f 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -83,8 +83,7 @@ export class TerminalService implements ITerminalService { } get configHelper(): ITerminalConfigHelper { return this._configHelper; } get instances(): ITerminalInstance[] { - // TODO: Also return editors here - return this._terminalGroups.reduce((p, c) => p.concat(c.terminalInstances), []); + return this._terminalGroupService.instances.concat(this._terminalEditorService.instances); } private _activeInstance: ITerminalInstance | undefined; From 02c53c324511ccc8dc8d7d208d5e7829c0ce84a7 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 18 Jun 2021 08:28:16 -0700 Subject: [PATCH 17/31] Move instance change into editor service --- src/vs/workbench/contrib/terminal/browser/terminal.ts | 2 -- .../workbench/contrib/terminal/browser/terminalEditorService.ts | 2 +- src/vs/workbench/contrib/terminal/browser/terminalService.ts | 1 - 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index 610938f7587..7d94186a846 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -223,8 +223,6 @@ export interface ITerminalService extends ITerminalInstanceHost { export interface ITerminalEditorService extends ITerminalInstanceHost { readonly _serviceBrand: undefined; - readonly instances: ITerminalInstance[]; - createEditor(instance: ITerminalInstance): Promise; createEditorInput(instance: ITerminalInstance): TerminalEditorInput; detachActiveEditorInstance(): ITerminalInstance; diff --git a/src/vs/workbench/contrib/terminal/browser/terminalEditorService.ts b/src/vs/workbench/contrib/terminal/browser/terminalEditorService.ts index 1f854c55ed2..9424ee6ccad 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalEditorService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalEditorService.ts @@ -68,7 +68,6 @@ export class TerminalEditorService extends Disposable implements ITerminalEditor pinned: true, forceReload: true }); - this.instances.push(instance); } createEditorInput(instance: ITerminalInstance): TerminalEditorInput { @@ -78,6 +77,7 @@ export class TerminalEditorService extends Disposable implements ITerminalEditor this._instanceDisposables.set(instance.instanceId, [ instance.onDisposed(this._onDidDisposeInstance.fire, this._onDidDisposeInstance) ]); + this.instances.push(instance); this._onDidChangeInstances.fire(); return input; } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index 5facbf36b4f..eb77b76ac28 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -201,7 +201,6 @@ export class TerminalService implements ITerminalService { } else { instance = this.createInstance({}); } - this._terminalEditorService.instances.push(instance); return { editor: this._terminalEditorService.createEditorInput(instance), options: { From cce2b835ab0041d318907ebb148080ef322e57cc Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 18 Jun 2021 08:41:14 -0700 Subject: [PATCH 18/31] Move groups out of terminal service --- .../quickaccess/browser/viewQuickAccess.ts | 5 ++-- .../contrib/terminal/browser/terminal.ts | 6 ++--- .../terminal/browser/terminalGroupService.ts | 20 ++++++++++++++ .../terminal/browser/terminalQuickAccess.ts | 5 ++-- .../terminal/browser/terminalService.ts | 27 ++++++------------- .../terminal/browser/terminalTabbedView.ts | 4 +-- .../contrib/terminal/browser/terminalView.ts | 10 +++---- 7 files changed, 43 insertions(+), 34 deletions(-) diff --git a/src/vs/workbench/contrib/quickaccess/browser/viewQuickAccess.ts b/src/vs/workbench/contrib/quickaccess/browser/viewQuickAccess.ts index eeac76679bb..9a4c4e8eeca 100644 --- a/src/vs/workbench/contrib/quickaccess/browser/viewQuickAccess.ts +++ b/src/vs/workbench/contrib/quickaccess/browser/viewQuickAccess.ts @@ -9,7 +9,7 @@ import { IPickerQuickAccessItem, PickerQuickAccessProvider } from 'vs/platform/q import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { IViewDescriptorService, IViewsService, ViewContainer } from 'vs/workbench/common/views'; import { IOutputService } from 'vs/workbench/contrib/output/common/output'; -import { ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal'; +import { ITerminalGroupService, ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal'; import { IPanelService, IPanelIdentifier } from 'vs/workbench/services/panel/common/panelService'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { ViewletDescriptor } from 'vs/workbench/browser/viewlet'; @@ -37,6 +37,7 @@ export class ViewQuickAccessProvider extends PickerQuickAccessProvider { + this.terminalGroupService.groups.forEach((group, groupIndex) => { group.terminalInstances.forEach((terminal, terminalIndex) => { const label = localize('terminalTitle', "{0}: {1}", `${groupIndex + 1}.${terminalIndex + 1}`, terminal.title); viewEntries.push({ diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index 7d94186a846..3135806acbf 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -115,8 +115,6 @@ export interface ITerminalService extends ITerminalInstanceHost { readonly _serviceBrand: undefined; configHelper: ITerminalConfigHelper; - // TODO: Remove groups - access should be exclusive to group service - readonly terminalGroups: readonly ITerminalGroup[]; isProcessSupportRegistered: boolean; readonly connectionState: TerminalConnectionState; readonly availableProfiles: ITerminalProfile[]; @@ -154,7 +152,6 @@ export interface ITerminalService extends ITerminalInstanceHost { createInstance(shellLaunchConfig: IShellLaunchConfig): ITerminalInstance; getInstanceFromId(terminalId: number): ITerminalInstance | undefined; getInstanceFromIndex(terminalIndex: number): ITerminalInstance; - getGroupLabels(): string[]; getActiveOrCreateInstance(): ITerminalInstance; splitInstance(instance: ITerminalInstance, shell?: IShellLaunchConfig, cwd?: string | URI): ITerminalInstance | null; splitInstance(instance: ITerminalInstance, profile: ITerminalProfile): ITerminalInstance | null; @@ -237,7 +234,7 @@ export interface ITerminalGroupService extends ITerminalInstanceHost { readonly _serviceBrand: undefined; readonly groups: readonly ITerminalGroup[]; - readonly activeGroup: ITerminalGroup | undefined; + activeGroup: ITerminalGroup | undefined; readonly activeGroupIndex: number; readonly activeInstanceIndex: number; @@ -263,6 +260,7 @@ export interface ITerminalGroupService extends ITerminalInstanceHost { */ moveGroup(source: ITerminalInstance, target: ITerminalInstance): void; + getGroupLabels(): string[]; setActiveGroupByIndex(index: number): void; setActiveGroupToNext(): void; setActiveGroupToPrevious(): void; diff --git a/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts b/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts index c6edabdb971..5259f1aa8ff 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts @@ -6,10 +6,12 @@ import { Orientation } from 'vs/base/browser/ui/sash/sash'; import { Emitter, Event } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; +import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IShellLaunchConfig } from 'vs/platform/terminal/common/terminal'; import { ITerminalGroup, ITerminalGroupService, ITerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminal'; import { TerminalGroup } from 'vs/workbench/contrib/terminal/browser/terminalGroup'; +import { KEYBINDING_CONTEXT_TERMINAL_GROUP_COUNT } from 'vs/workbench/contrib/terminal/common/terminal'; export class TerminalGroupService extends Disposable implements ITerminalGroupService { declare _serviceBrand: undefined; @@ -21,6 +23,7 @@ export class TerminalGroupService extends Disposable implements ITerminalGroupSe } activeInstanceIndex: number = -1; + private _terminalGroupCountContextKey: IContextKey; private _container: HTMLElement | undefined; private readonly _onDidChangeActiveGroup = new Emitter(); @@ -41,11 +44,15 @@ export class TerminalGroupService extends Disposable implements ITerminalGroupSe get onPanelOrientationChanged(): Event { return this._onPanelOrientationChanged.event; } constructor( + @IContextKeyService private _contextKeyService: IContextKeyService, @IInstantiationService private readonly _instantiationService: IInstantiationService ) { super(); this.onDidDisposeGroup(group => this.removeGroup(group)); + + this._terminalGroupCountContextKey = KEYBINDING_CONTEXT_TERMINAL_GROUP_COUNT.bindTo(this._contextKeyService); + this.onDidChangeGroups(() => this._terminalGroupCountContextKey.set(this.groups.length)); } get activeGroup(): ITerminalGroup | undefined { @@ -54,6 +61,13 @@ export class TerminalGroupService extends Disposable implements ITerminalGroupSe } return this.groups[this.activeGroupIndex]; } + set activeGroup(value: ITerminalGroup | undefined) { + if (value === undefined) { + this.activeGroupIndex = -1; + return; + } + this.activeGroupIndex = this.groups.findIndex(e => e === value); + } get activeInstance(): ITerminalInstance | undefined { return this.activeGroup?.activeInstance; @@ -218,6 +232,12 @@ export class TerminalGroupService extends Disposable implements ITerminalGroupSe getGroupForInstance(instance: ITerminalInstance): ITerminalGroup | undefined { return this.groups.find(group => group.terminalInstances.indexOf(instance) !== -1); } + + getGroupLabels(): string[] { + return this.groups.filter(group => group.terminalInstances.length > 0).map((group, index) => { + return `${index + 1}: ${group.title ? group.title : ''}`; + }); + } } interface IInstanceLocation { diff --git a/src/vs/workbench/contrib/terminal/browser/terminalQuickAccess.ts b/src/vs/workbench/contrib/terminal/browser/terminalQuickAccess.ts index 8aa4cc96d2e..a33a457b028 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalQuickAccess.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalQuickAccess.ts @@ -7,7 +7,7 @@ import { localize } from 'vs/nls'; import { IQuickPickSeparator } from 'vs/platform/quickinput/common/quickInput'; import { IPickerQuickAccessItem, PickerQuickAccessProvider, TriggerAction } from 'vs/platform/quickinput/browser/pickerQuickAccess'; import { matchesFuzzy } from 'vs/base/common/filters'; -import { ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal'; +import { ITerminalGroupService, ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { TerminalCommandId } from 'vs/workbench/contrib/terminal/common/terminal'; import { IThemeService, ThemeIcon } from 'vs/platform/theme/common/themeService'; @@ -21,6 +21,7 @@ export class TerminalQuickAccessProvider extends PickerQuickAccessProvider { const terminalPicks: Array = []; - const terminalGroups = this._terminalService.terminalGroups; + const terminalGroups = this._terminalGroupService.groups; for (let groupIndex = 0; groupIndex < terminalGroups.length; groupIndex++) { const terminalGroup = terminalGroups[groupIndex]; for (let terminalIndex = 0; terminalIndex < terminalGroup.terminalInstances.length; terminalIndex++) { diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index eb77b76ac28..fd2dbc7a2d4 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -34,7 +34,7 @@ import { TerminalEditor } from 'vs/workbench/contrib/terminal/browser/terminalEd import { configureTerminalProfileIcon } from 'vs/workbench/contrib/terminal/browser/terminalIcons'; import { TerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminalInstance'; import { TerminalViewPane } from 'vs/workbench/contrib/terminal/browser/terminalView'; -import { IRemoteTerminalAttachTarget, IStartExtensionTerminalRequest, ITerminalConfigHelper, ITerminalProcessExtHostProxy, ITerminalProfileContribution, KEYBINDING_CONTEXT_TERMINAL_ALT_BUFFER_ACTIVE, KEYBINDING_CONTEXT_TERMINAL_COUNT, KEYBINDING_CONTEXT_TERMINAL_FOCUS, KEYBINDING_CONTEXT_TERMINAL_GROUP_COUNT, KEYBINDING_CONTEXT_TERMINAL_IS_OPEN, KEYBINDING_CONTEXT_TERMINAL_PROCESS_SUPPORTED, KEYBINDING_CONTEXT_TERMINAL_SHELL_TYPE, KEYBINDING_CONTEXT_TERMINAL_TABS_MOUSE, TerminalLocation, TERMINAL_VIEW_ID } from 'vs/workbench/contrib/terminal/common/terminal'; +import { IRemoteTerminalAttachTarget, IStartExtensionTerminalRequest, ITerminalConfigHelper, ITerminalProcessExtHostProxy, ITerminalProfileContribution, KEYBINDING_CONTEXT_TERMINAL_ALT_BUFFER_ACTIVE, KEYBINDING_CONTEXT_TERMINAL_COUNT, KEYBINDING_CONTEXT_TERMINAL_FOCUS, KEYBINDING_CONTEXT_TERMINAL_IS_OPEN, KEYBINDING_CONTEXT_TERMINAL_PROCESS_SUPPORTED, KEYBINDING_CONTEXT_TERMINAL_SHELL_TYPE, KEYBINDING_CONTEXT_TERMINAL_TABS_MOUSE, TerminalLocation, TERMINAL_VIEW_ID } from 'vs/workbench/contrib/terminal/common/terminal'; import { ITerminalContributionService } from 'vs/workbench/contrib/terminal/common/terminalExtensionPoints'; import { formatMessageForTerminal, terminalStrings } from 'vs/workbench/contrib/terminal/common/terminalStrings'; import { IEditorOverrideService, RegisteredEditorPriority } from 'vs/workbench/services/editor/common/editorOverrideService'; @@ -47,13 +47,11 @@ import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteA export class TerminalService implements ITerminalService { declare _serviceBrand: undefined; - private get _terminalGroups(): readonly ITerminalGroup[] { return this._terminalGroupService.groups; } private _hostActiveTerminals: Map = new Map(); private _isShuttingDown: boolean; private _terminalFocusContextKey: IContextKey; private _terminalCountContextKey: IContextKey; - private _terminalGroupCountContextKey: IContextKey; private _terminalShellTypeContextKey: IContextKey; private _terminalAltBufferActiveContextKey: IContextKey; private _backgroundedTerminalInstances: ITerminalInstance[] = []; @@ -73,7 +71,6 @@ export class TerminalService implements ITerminalService { private _editable: { instance: ITerminalInstance, data: IEditableData } | undefined; - get terminalGroups(): readonly ITerminalGroup[] { return this._terminalGroups; } get isProcessSupportRegistered(): boolean { return !!this._processSupportContextKey.get(); } get connectionState(): TerminalConnectionState { return this._connectionState; } get profilesReady(): Promise { return this._profilesReadyBarrier.wait().then(() => { }); } @@ -173,7 +170,6 @@ export class TerminalService implements ITerminalService { this._findState = new FindReplaceState(); this._terminalFocusContextKey = KEYBINDING_CONTEXT_TERMINAL_FOCUS.bindTo(this._contextKeyService); this._terminalCountContextKey = KEYBINDING_CONTEXT_TERMINAL_COUNT.bindTo(this._contextKeyService); - this._terminalGroupCountContextKey = KEYBINDING_CONTEXT_TERMINAL_GROUP_COUNT.bindTo(this._contextKeyService); this._terminalShellTypeContextKey = KEYBINDING_CONTEXT_TERMINAL_SHELL_TYPE.bindTo(this._contextKeyService); this._terminalAltBufferActiveContextKey = KEYBINDING_CONTEXT_TERMINAL_ALT_BUFFER_ACTIVE.bindTo(this._contextKeyService); this._configHelper = _instantiationService.createInstance(TerminalConfigHelper); @@ -220,7 +216,6 @@ export class TerminalService implements ITerminalService { // for example, we detect if you've installed a pwsh this.onInstanceCreated(() => this._refreshAvailableProfiles()); this.onDidChangeInstances(() => this._terminalCountContextKey.set(this.instances.length)); - this.onGroupsChanged(() => this._terminalGroupCountContextKey.set(this._terminalGroups.length)); this.onInstanceLinksReady(instance => this._setInstanceLinkProviders(instance)); // Hide the panel if there are no more instances, provided that VS Code is not shutting @@ -378,7 +373,7 @@ export class TerminalService implements ITerminalService { } }); if (layoutInfo.tabs.length) { - this._terminalGroupService.setActiveGroupByIndex(activeGroup ? this.terminalGroups.indexOf(activeGroup) : 0); + this._terminalGroupService.activeGroup = activeGroup; } } return reconnectCounter; @@ -500,12 +495,6 @@ export class TerminalService implements ITerminalService { this._localTerminalService?.setTerminalLayoutInfo(undefined); } - getGroupLabels(): string[] { - return this._terminalGroups.filter(group => group.terminalInstances.length > 0).map((group, index) => { - return `${index + 1}: ${group.title ? group.title : ''}`; - }); - } - getFindState(): FindReplaceState { return this._findState; } @@ -515,9 +504,8 @@ export class TerminalService implements ITerminalService { if (!this.configHelper.config.enablePersistentSessions) { return; } - const state: ITerminalsLayoutInfoById = { - tabs: this.terminalGroups.map(g => g.getLayoutInfo(g === this._terminalGroupService.activeGroup)) - }; + const tabs = this._terminalGroupService.groups.map(g => g.getLayoutInfo(g === this._terminalGroupService.activeGroup)); + const state: ITerminalsLayoutInfoById = { tabs }; this._primaryOffProcessTerminalService?.setTerminalLayoutInfo(state); } @@ -579,7 +567,7 @@ export class TerminalService implements ITerminalService { } else if (this._localTerminalsInitPromise) { await this._localTerminalsInitPromise; } - if (this.terminalGroups.length === 0 && this.isProcessSupportRegistered) { + if (this._terminalGroupService.groups.length === 0 && this.isProcessSupportRegistered) { this.createTerminal(); } } @@ -597,7 +585,7 @@ export class TerminalService implements ITerminalService { this._initInstanceListeners(instance); // TODO: Move into group service? - this._terminalGroups.forEach((g, i) => g.setVisible(i === this._terminalGroupService.activeGroupIndex)); + this._terminalGroupService.groups.forEach((g, i) => g.setVisible(i === this._terminalGroupService.activeGroupIndex)); return instance; } @@ -821,8 +809,9 @@ export class TerminalService implements ITerminalService { return group.terminalInstances.length > 1; } + // TODO: Move to group service getGroupForInstance(instance: ITerminalInstance): ITerminalGroup | undefined { - return this._terminalGroups.find(group => group.terminalInstances.indexOf(instance) !== -1); + return this._terminalGroupService.groups.find(group => group.terminalInstances.indexOf(instance) !== -1); } async showPanel(focus?: boolean): Promise { diff --git a/src/vs/workbench/contrib/terminal/browser/terminalTabbedView.ts b/src/vs/workbench/contrib/terminal/browser/terminalTabbedView.ts index b9bf33c1eb0..ae4514b8afb 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalTabbedView.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalTabbedView.ts @@ -163,7 +163,7 @@ export class TerminalTabbedView extends Disposable { return true; } - if (hide === 'singleGroup' && this._terminalService.terminalGroups.length > 1) { + if (hide === 'singleGroup' && this._terminalGroupService.groups.length > 1) { return true; } @@ -261,7 +261,7 @@ export class TerminalTabbedView extends Disposable { } this._splitView.addView({ element: terminalOuterContainer, - layout: width => this._terminalService.terminalGroups.forEach(tab => tab.layout(width, this._height || 0)), + layout: width => this._terminalGroupService.groups.forEach(tab => tab.layout(width, this._height || 0)), minimumSize: 120, maximumSize: Number.POSITIVE_INFINITY, onDidChange: () => Disposable.None, diff --git a/src/vs/workbench/contrib/terminal/browser/terminalView.ts b/src/vs/workbench/contrib/terminal/browser/terminalView.ts index bffc1e882ef..f8b79d7fff1 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalView.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalView.ts @@ -131,7 +131,7 @@ export class TerminalViewPane extends ViewPane { this._register(this.onDidChangeBodyVisibility(visible => { if (visible) { - const hadTerminals = !!this._terminalService.terminalGroups.length; + const hadTerminals = !!this._terminalGroupService.groups.length; if (this._terminalService.isProcessSupportRegistered) { if (this._terminalsInitialized) { if (!hadTerminals) { @@ -320,7 +320,7 @@ class SwitchTerminalActionViewItem extends SelectActionViewItem { @IThemeService private readonly _themeService: IThemeService, @IContextViewService contextViewService: IContextViewService ) { - super(null, action, getTerminalSelectOpenItems(_terminalService), _terminalGroupService.activeGroupIndex, contextViewService, { ariaLabel: nls.localize('terminals', 'Open Terminals.'), optionsAsChildren: true }); + super(null, action, getTerminalSelectOpenItems(_terminalService, _terminalGroupService), _terminalGroupService.activeGroupIndex, contextViewService, { ariaLabel: nls.localize('terminals', 'Open Terminals.'), optionsAsChildren: true }); this._register(_terminalService.onDidChangeInstances(() => this._updateItems(), this)); this._register(_terminalService.onActiveGroupChanged(() => this._updateItems(), this)); this._register(_terminalService.onDidChangeActiveInstance(() => this._updateItems(), this)); @@ -342,15 +342,15 @@ class SwitchTerminalActionViewItem extends SelectActionViewItem { } private _updateItems(): void { - const options = getTerminalSelectOpenItems(this._terminalService); + const options = getTerminalSelectOpenItems(this._terminalService, this._terminalGroupService); this.setOptions(options, this._terminalGroupService.activeGroupIndex); } } -function getTerminalSelectOpenItems(terminalService: ITerminalService): ISelectOptionItem[] { +function getTerminalSelectOpenItems(terminalService: ITerminalService, terminalGroupService: ITerminalGroupService): ISelectOptionItem[] { let items: ISelectOptionItem[]; if (terminalService.connectionState === TerminalConnectionState.Connected) { - items = terminalService.getGroupLabels().map(label => { + items = terminalGroupService.getGroupLabels().map(label => { return { text: label }; }); } else { From 00ec97174ccf474634360fce3240fc37f105a17e Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 18 Jun 2021 08:45:12 -0700 Subject: [PATCH 19/31] Move unsplit, join to group service --- .../contrib/terminal/browser/terminal.ts | 5 +- .../terminal/browser/terminalActions.ts | 8 +-- .../terminal/browser/terminalGroupService.ts | 55 ++++++++++++++++++ .../terminal/browser/terminalService.ts | 57 ------------------- .../terminal/browser/terminalTabsList.ts | 2 +- .../contrib/terminal/browser/terminalView.ts | 2 - 6 files changed, 62 insertions(+), 67 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index 3135806acbf..15048c3ca16 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -155,8 +155,6 @@ export interface ITerminalService extends ITerminalInstanceHost { getActiveOrCreateInstance(): ITerminalInstance; splitInstance(instance: ITerminalInstance, shell?: IShellLaunchConfig, cwd?: string | URI): ITerminalInstance | null; splitInstance(instance: ITerminalInstance, profile: ITerminalProfile): ITerminalInstance | null; - unsplitInstance(instance: ITerminalInstance): void; - joinInstances(instances: ITerminalInstance[]): void; /** * Moves a terminal instance's group to the target instance group's position. */ @@ -260,6 +258,9 @@ export interface ITerminalGroupService extends ITerminalInstanceHost { */ moveGroup(source: ITerminalInstance, target: ITerminalInstance): void; + unsplitInstance(instance: ITerminalInstance): void; + joinInstances(instances: ITerminalInstance[]): void; + getGroupLabels(): string[]; setActiveGroupByIndex(index: number): void; setActiveGroupToNext(): void; diff --git a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts index 88fd8144c95..02ed19d2cef 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts @@ -1457,8 +1457,7 @@ export function registerTerminalActions() { }); } async run(accessor: ServicesAccessor) { - const terminalService = accessor.get(ITerminalService); - await terminalService.doWithActiveInstance(async t => terminalService.unsplitInstance(t)); + await accessor.get(ITerminalService).doWithActiveInstance(async t => accessor.get(ITerminalGroupService).unsplitInstance(t)); } }); registerAction2(class extends Action2 { @@ -1479,7 +1478,7 @@ export function registerTerminalActions() { if (instances?.length === 1) { const group = terminalService.getGroupForInstance(instances[0]); if (group && group?.terminalInstances.length > 1) { - terminalService.unsplitInstance(instances[0]); + accessor.get(ITerminalGroupService).unsplitInstance(instances[0]); } } } @@ -1494,10 +1493,9 @@ export function registerTerminalActions() { }); } async run(accessor: ServicesAccessor) { - const terminalService = accessor.get(ITerminalService); const instances = getSelectedInstances(accessor); if (instances) { - terminalService.joinInstances(instances); + accessor.get(ITerminalGroupService).joinInstances(instances); } } }); diff --git a/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts b/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts index 5259f1aa8ff..267c5eabe12 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts @@ -229,6 +229,61 @@ export class TerminalGroupService extends Disposable implements ITerminalGroupSe this._onDidChangeInstances.fire(); } + unsplitInstance(instance: ITerminalInstance): void { + const oldGroup = this.getGroupForInstance(instance); + if (!oldGroup || oldGroup.terminalInstances.length < 2) { + return; + } + + oldGroup.removeInstance(instance); + this.createGroup(instance); + } + + joinInstances(instances: ITerminalInstance[]): void { + // Find the group of the first instance that is the only instance in the group, if one exists + let candidateInstance: ITerminalInstance | undefined = undefined; + let candidateGroup: ITerminalGroup | undefined = undefined; + for (const instance of instances) { + const group = this.getGroupForInstance(instance); + if (group?.terminalInstances.length === 1) { + candidateInstance = instance; + candidateGroup = group; + break; + } + } + + // Create a new group if needed + if (!candidateGroup) { + candidateGroup = this.createGroup(); + } + + const wasActiveGroup = this.activeGroup === candidateGroup; + + // Unsplit all other instances and add them to the new group + for (const instance of instances) { + if (instance === candidateInstance) { + continue; + } + + const oldGroup = this.getGroupForInstance(instance); + if (!oldGroup) { + // Something went wrong, don't join this one + continue; + } + oldGroup.removeInstance(instance); + candidateGroup.addInstance(instance); + } + + // Set the active terminal + this.activeInstance = instances[0]; + + // Fire events + this._onDidChangeInstances.fire(); + if (!wasActiveGroup) { + this._onDidChangeActiveGroup.fire(this.activeGroup); + } + } + getGroupForInstance(instance: ITerminalInstance): ITerminalGroup | undefined { return this.groups.find(group => group.terminalInstances.indexOf(instance) !== -1); } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index fd2dbc7a2d4..c11560e6ea3 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -589,63 +589,6 @@ export class TerminalService implements ITerminalService { return instance; } - // TODO: Move to group service - unsplitInstance(instance: ITerminalInstance): void { - const oldGroup = this.getGroupForInstance(instance); - if (!oldGroup || oldGroup.terminalInstances.length < 2) { - return; - } - - oldGroup.removeInstance(instance); - this._terminalGroupService.createGroup(instance); - } - - // TODO: Move to group service - joinInstances(instances: ITerminalInstance[]): void { - // Find the group of the first instance that is the only instance in the group, if one exists - let candidateInstance: ITerminalInstance | undefined = undefined; - let candidateGroup: ITerminalGroup | undefined = undefined; - for (const instance of instances) { - const group = this.getGroupForInstance(instance); - if (group?.terminalInstances.length === 1) { - candidateInstance = instance; - candidateGroup = group; - break; - } - } - - // Create a new group if needed - if (!candidateGroup) { - candidateGroup = this._terminalGroupService.createGroup(); - } - - const wasActiveGroup = this._terminalGroupService.activeGroup === candidateGroup; - - // Unsplit all other instances and add them to the new group - for (const instance of instances) { - if (instance === candidateInstance) { - continue; - } - - const oldGroup = this.getGroupForInstance(instance); - if (!oldGroup) { - // Something went wrong, don't join this one - continue; - } - oldGroup.removeInstance(instance); - candidateGroup.addInstance(instance); - } - - // Set the active terminal - this.activeInstance = instances[0]; - - // Fire events - this._onDidChangeInstances.fire(); - if (!wasActiveGroup) { - this._onActiveGroupChanged.fire(); - } - } - moveInstance(source: ITerminalInstance, target: ITerminalInstance, side: 'before' | 'after'): void { // TODO: Move into group service const sourceGroup = this.getGroupForInstance(source); diff --git a/src/vs/workbench/contrib/terminal/browser/terminalTabsList.ts b/src/vs/workbench/contrib/terminal/browser/terminalTabsList.ts index c87963ca100..af6a8064032 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalTabsList.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalTabsList.ts @@ -605,7 +605,7 @@ class TerminalTabsDragAndDrop implements IListDragAndDrop { if (!targetInstance) { for (const instance of sourceInstances) { - this._terminalService.unsplitInstance(instance); + this._terminalGroupService.unsplitInstance(instance); } return; } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalView.ts b/src/vs/workbench/contrib/terminal/browser/terminalView.ts index f8b79d7fff1..8fd7c0f33d7 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalView.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalView.ts @@ -326,8 +326,6 @@ class SwitchTerminalActionViewItem extends SelectActionViewItem { 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 - // this._register(_terminalGroupService.onDidDisposeGroup(() => this._updateItems(), this)); this._register(_terminalService.onDidChangeConnectionState(() => this._updateItems(), this)); this._register(_terminalService.onDidChangeAvailableProfiles(() => this._updateItems(), this)); this._register(attachSelectBoxStyler(this.selectBox, this._themeService)); From 6a4d8d350ef0d9ba62969dc5f45ec11b018350ab Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 18 Jun 2021 08:48:08 -0700 Subject: [PATCH 20/31] moveinstance to group service --- .../contrib/terminal/browser/terminal.ts | 6 +---- .../terminal/browser/terminalGroupService.ts | 20 ++++++++++++++++ .../terminal/browser/terminalService.ts | 23 ++----------------- 3 files changed, 23 insertions(+), 26 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index 15048c3ca16..d808eaa51e2 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -155,11 +155,6 @@ export interface ITerminalService extends ITerminalInstanceHost { getActiveOrCreateInstance(): ITerminalInstance; splitInstance(instance: ITerminalInstance, shell?: IShellLaunchConfig, cwd?: string | URI): ITerminalInstance | null; splitInstance(instance: ITerminalInstance, profile: ITerminalProfile): ITerminalInstance | null; - /** - * Moves a terminal instance's group to the target instance group's position. - */ - // moveGroup(source: ITerminalInstance, target: ITerminalInstance): void; - moveInstance(source: ITerminalInstance, target: ITerminalInstance, side: 'before' | 'after'): void; moveToEditor(source: ITerminalInstance): void; moveToTerminalView(source?: ITerminalInstance): Promise; @@ -258,6 +253,7 @@ export interface ITerminalGroupService extends ITerminalInstanceHost { */ moveGroup(source: ITerminalInstance, target: ITerminalInstance): void; + moveInstance(source: ITerminalInstance, target: ITerminalInstance, side: 'before' | 'after'): void; unsplitInstance(instance: ITerminalInstance): void; joinInstances(instances: ITerminalInstance[]): void; diff --git a/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts b/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts index 267c5eabe12..22ccefce6ed 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts @@ -229,6 +229,26 @@ export class TerminalGroupService extends Disposable implements ITerminalGroupSe this._onDidChangeInstances.fire(); } + moveInstance(source: ITerminalInstance, target: ITerminalInstance, side: 'before' | 'after'): void { + // TODO: Move into group service + const sourceGroup = this.getGroupForInstance(source); + const targetGroup = this.getGroupForInstance(target); + if (!sourceGroup || !targetGroup) { + return; + } + + // Move from the source group to the target group + if (sourceGroup !== targetGroup) { + // Move groups + sourceGroup.removeInstance(source); + targetGroup.addInstance(source); + } + + // Rearrange within the target group + const index = targetGroup.terminalInstances.indexOf(target) + (side === 'after' ? 1 : 0); + targetGroup.moveInstance(source, index); + } + unsplitInstance(instance: ITerminalInstance): void { const oldGroup = this.getGroupForInstance(instance); if (!oldGroup || oldGroup.terminalInstances.length < 2) { diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index c11560e6ea3..af03ae7915d 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -589,26 +589,6 @@ export class TerminalService implements ITerminalService { return instance; } - moveInstance(source: ITerminalInstance, target: ITerminalInstance, side: 'before' | 'after'): void { - // TODO: Move into group service - const sourceGroup = this.getGroupForInstance(source); - const targetGroup = this.getGroupForInstance(target); - if (!sourceGroup || !targetGroup) { - return; - } - - // Move from the source group to the target group - if (sourceGroup !== targetGroup) { - // Move groups - sourceGroup.removeInstance(source); - targetGroup.addInstance(source); - } - - // Rearrange within the target group - const index = targetGroup.terminalInstances.indexOf(target) + (side === 'after' ? 1 : 0); - targetGroup.moveInstance(source, index); - } - moveToEditor(source: ITerminalInstance): void { if (source.target === TerminalLocation.Editor) { return; @@ -687,7 +667,8 @@ export class TerminalService implements ITerminalService { // View terminals let sourceInstance = this.getInstanceFromId(instanceId); if (sourceInstance) { - this.moveInstance(sourceInstance, instance, e.side); + this._terminalGroupService.moveInstance(sourceInstance, instance, e.side); + return; } // Terminal editors From d7b7ddf8ee5177abd8c9bf2762821f25f234a0ae Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 18 Jun 2021 08:52:42 -0700 Subject: [PATCH 21/31] Make some group service members private --- .../contrib/terminal/browser/terminal.ts | 7 ------- .../terminal/browser/terminalGroupService.ts | 20 +++++++++---------- .../terminal/browser/terminalService.ts | 8 -------- 3 files changed, 10 insertions(+), 25 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index d808eaa51e2..88d3be80719 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -231,11 +231,6 @@ export interface ITerminalGroupService extends ITerminalInstanceHost { readonly activeGroupIndex: number; 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). */ @@ -244,7 +239,6 @@ export interface ITerminalGroupService extends ITerminalInstanceHost { readonly onPanelOrientationChanged: Event; createGroup(slcOrInstance?: IShellLaunchConfig | ITerminalInstance): ITerminalGroup; - removeGroup(group: ITerminalGroup): void; /** * Moves a terminal instance's group to the target instance group's position. @@ -261,7 +255,6 @@ export interface ITerminalGroupService extends ITerminalInstanceHost { setActiveGroupByIndex(index: number): void; setActiveGroupToNext(): void; setActiveGroupToPrevious(): void; - getGroupForInstance(instance: ITerminalInstance): ITerminalGroup | undefined; setActiveInstanceByIndex(terminalIndex: number): void; diff --git a/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts b/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts index 22ccefce6ed..0e7cae46f5c 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts @@ -49,7 +49,7 @@ export class TerminalGroupService extends Disposable implements ITerminalGroupSe ) { super(); - this.onDidDisposeGroup(group => this.removeGroup(group)); + this.onDidDisposeGroup(group => this._removeGroup(group)); this._terminalGroupCountContextKey = KEYBINDING_CONTEXT_TERMINAL_GROUP_COUNT.bindTo(this._contextKeyService); this.onDidChangeGroups(() => this._terminalGroupCountContextKey.set(this.groups.length)); @@ -108,7 +108,7 @@ export class TerminalGroupService extends Disposable implements ITerminalGroupSe return group; } - removeGroup(group: ITerminalGroup): void { + private _removeGroup(group: ITerminalGroup): void { const wasActiveGroup = this._removeGroupAndAdjustFocus(group); this._onDidChangeInstances.fire(); @@ -217,8 +217,8 @@ export class TerminalGroupService extends Disposable implements ITerminalGroupSe } moveGroup(source: ITerminalInstance, target: ITerminalInstance): void { - const sourceGroup = this.getGroupForInstance(source); - const targetGroup = this.getGroupForInstance(target); + const sourceGroup = this._getGroupForInstance(source); + const targetGroup = this._getGroupForInstance(target); if (!sourceGroup || !targetGroup) { return; } @@ -231,8 +231,8 @@ export class TerminalGroupService extends Disposable implements ITerminalGroupSe moveInstance(source: ITerminalInstance, target: ITerminalInstance, side: 'before' | 'after'): void { // TODO: Move into group service - const sourceGroup = this.getGroupForInstance(source); - const targetGroup = this.getGroupForInstance(target); + const sourceGroup = this._getGroupForInstance(source); + const targetGroup = this._getGroupForInstance(target); if (!sourceGroup || !targetGroup) { return; } @@ -250,7 +250,7 @@ export class TerminalGroupService extends Disposable implements ITerminalGroupSe } unsplitInstance(instance: ITerminalInstance): void { - const oldGroup = this.getGroupForInstance(instance); + const oldGroup = this._getGroupForInstance(instance); if (!oldGroup || oldGroup.terminalInstances.length < 2) { return; } @@ -264,7 +264,7 @@ export class TerminalGroupService extends Disposable implements ITerminalGroupSe let candidateInstance: ITerminalInstance | undefined = undefined; let candidateGroup: ITerminalGroup | undefined = undefined; for (const instance of instances) { - const group = this.getGroupForInstance(instance); + const group = this._getGroupForInstance(instance); if (group?.terminalInstances.length === 1) { candidateInstance = instance; candidateGroup = group; @@ -285,7 +285,7 @@ export class TerminalGroupService extends Disposable implements ITerminalGroupSe continue; } - const oldGroup = this.getGroupForInstance(instance); + const oldGroup = this._getGroupForInstance(instance); if (!oldGroup) { // Something went wrong, don't join this one continue; @@ -304,7 +304,7 @@ export class TerminalGroupService extends Disposable implements ITerminalGroupSe } } - getGroupForInstance(instance: ITerminalInstance): ITerminalGroup | undefined { + private _getGroupForInstance(instance: ITerminalInstance): ITerminalGroup | undefined { return this.groups.find(group => group.terminalInstances.indexOf(instance) !== -1); } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index af03ae7915d..980d8efebc6 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -1036,17 +1036,9 @@ export class TerminalService implements ITerminalService { this._onDidChangeInstances.fire(); } else { const group = this._terminalGroupService.createGroup(shellLaunchConfig); - // const terminalGroup = this._instantiationService.createInstance(TerminalGroup, this._terminalContainer, shellLaunchConfig); - // this._terminalGroups.push(terminalGroup); - // terminalGroup.onPanelOrientationChanged((orientation) => this._onPanelOrientationChanged.fire(orientation)); - instance = group.terminalInstances[0]; - - // terminalGroup.addDisposable(terminalGroup.onDisposed(this._onGroupDisposed.fire, this._onGroupDisposed)); - // terminalGroup.addDisposable(terminalGroup.onInstancesChanged(this._onInstancesChanged.fire, this._onInstancesChanged)); this._initInstanceListeners(instance); this._onDidChangeInstances.fire(); - // this._onGroupsChanged.fire(); } if (this.instances.length === 1) { From 9fbb1ca0986cca623caa70e4d369faa7d4e61130 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 18 Jun 2021 10:16:06 -0700 Subject: [PATCH 22/31] Reconnect orientation change --- .../workbench/contrib/terminal/browser/terminalEditorService.ts | 1 - .../workbench/contrib/terminal/browser/terminalGroupService.ts | 1 - src/vs/workbench/contrib/terminal/browser/terminalService.ts | 1 + 3 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalEditorService.ts b/src/vs/workbench/contrib/terminal/browser/terminalEditorService.ts index 9424ee6ccad..072767dc33b 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalEditorService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalEditorService.ts @@ -10,7 +10,6 @@ import { TerminalEditorInput } from 'vs/workbench/contrib/terminal/browser/termi import { TerminalLocation } from 'vs/workbench/contrib/terminal/common/terminal'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; -// TODO: Implement ITerminalInstanceHost export class TerminalEditorService extends Disposable implements ITerminalEditorService { declare _serviceBrand: undefined; diff --git a/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts b/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts index 0e7cae46f5c..c967f949050 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts @@ -230,7 +230,6 @@ export class TerminalGroupService extends Disposable implements ITerminalGroupSe } moveInstance(source: ITerminalInstance, target: ITerminalInstance, side: 'before' | 'after'): void { - // TODO: Move into group service const sourceGroup = this._getGroupForInstance(source); const targetGroup = this._getGroupForInstance(target); if (!sourceGroup || !targetGroup) { diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index e36b6ef83cd..db6a2d24f44 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -210,6 +210,7 @@ export class TerminalService implements ITerminalService { this._forwardInstanceHostEvents(this._terminalGroupService); this._forwardInstanceHostEvents(this._terminalEditorService); + this._terminalGroupService.onPanelOrientationChanged(this._onPanelOrientationChanged.fire, this.onPanelOrientationChanged); // the below avoids having to poll routinely. // we update detected profiles when an instance is created so that, From 8edab436bd8015ba132681faffc85eb425453ec1 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 18 Jun 2021 10:21:30 -0700 Subject: [PATCH 23/31] Move getGroupForInstance into group service --- .../contrib/terminal/browser/terminal.ts | 3 +-- .../terminal/browser/terminalActions.ts | 6 +++--- .../terminal/browser/terminalGroupService.ts | 16 ++++++++-------- .../terminal/browser/terminalService.ts | 19 ++++++------------- .../terminal/browser/terminalTabbedView.ts | 2 +- .../terminal/browser/terminalTabsList.ts | 9 ++++++--- 6 files changed, 25 insertions(+), 30 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index 88d3be80719..ee94bdab634 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -194,8 +194,6 @@ export interface ITerminalService extends ITerminalInstanceHost { showProfileQuickPick(type: 'setDefault' | 'createInstance', cwd?: string | URI): Promise; - getGroupForInstance(instance: ITerminalInstance): ITerminalGroup | undefined; - setContainers(panelContainer: HTMLElement, terminalContainer: HTMLElement): void; requestStartExtensionTerminal(proxy: ITerminalProcessExtHostProxy, cols: number, rows: number): Promise; @@ -239,6 +237,7 @@ export interface ITerminalGroupService extends ITerminalInstanceHost { readonly onPanelOrientationChanged: Event; createGroup(slcOrInstance?: IShellLaunchConfig | ITerminalInstance): ITerminalGroup; + getGroupForInstance(instance: ITerminalInstance): ITerminalGroup | undefined; /** * Moves a terminal instance's group to the target instance group's position. diff --git a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts index 02ed19d2cef..0350f6b59b0 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts @@ -1471,14 +1471,14 @@ export function registerTerminalActions() { }); } async run(accessor: ServicesAccessor) { - const terminalService = accessor.get(ITerminalService); + const terminalGroupService = accessor.get(ITerminalGroupService); const instances = getSelectedInstances(accessor); // should not even need this check given the context key // but TS complains if (instances?.length === 1) { - const group = terminalService.getGroupForInstance(instances[0]); + const group = terminalGroupService.getGroupForInstance(instances[0]); if (group && group?.terminalInstances.length > 1) { - accessor.get(ITerminalGroupService).unsplitInstance(instances[0]); + terminalGroupService.unsplitInstance(instances[0]); } } } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts b/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts index c967f949050..9d55affa863 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts @@ -217,8 +217,8 @@ export class TerminalGroupService extends Disposable implements ITerminalGroupSe } moveGroup(source: ITerminalInstance, target: ITerminalInstance): void { - const sourceGroup = this._getGroupForInstance(source); - const targetGroup = this._getGroupForInstance(target); + const sourceGroup = this.getGroupForInstance(source); + const targetGroup = this.getGroupForInstance(target); if (!sourceGroup || !targetGroup) { return; } @@ -230,8 +230,8 @@ export class TerminalGroupService extends Disposable implements ITerminalGroupSe } moveInstance(source: ITerminalInstance, target: ITerminalInstance, side: 'before' | 'after'): void { - const sourceGroup = this._getGroupForInstance(source); - const targetGroup = this._getGroupForInstance(target); + const sourceGroup = this.getGroupForInstance(source); + const targetGroup = this.getGroupForInstance(target); if (!sourceGroup || !targetGroup) { return; } @@ -249,7 +249,7 @@ export class TerminalGroupService extends Disposable implements ITerminalGroupSe } unsplitInstance(instance: ITerminalInstance): void { - const oldGroup = this._getGroupForInstance(instance); + const oldGroup = this.getGroupForInstance(instance); if (!oldGroup || oldGroup.terminalInstances.length < 2) { return; } @@ -263,7 +263,7 @@ export class TerminalGroupService extends Disposable implements ITerminalGroupSe let candidateInstance: ITerminalInstance | undefined = undefined; let candidateGroup: ITerminalGroup | undefined = undefined; for (const instance of instances) { - const group = this._getGroupForInstance(instance); + const group = this.getGroupForInstance(instance); if (group?.terminalInstances.length === 1) { candidateInstance = instance; candidateGroup = group; @@ -284,7 +284,7 @@ export class TerminalGroupService extends Disposable implements ITerminalGroupSe continue; } - const oldGroup = this._getGroupForInstance(instance); + const oldGroup = this.getGroupForInstance(instance); if (!oldGroup) { // Something went wrong, don't join this one continue; @@ -303,7 +303,7 @@ export class TerminalGroupService extends Disposable implements ITerminalGroupSe } } - private _getGroupForInstance(instance: ITerminalInstance): ITerminalGroup | undefined { + getGroupForInstance(instance: ITerminalInstance): ITerminalGroup | undefined { return this.groups.find(group => group.terminalInstances.indexOf(instance) !== -1); } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index db6a2d24f44..4f8b7ad7d21 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -190,7 +190,7 @@ export class TerminalService implements ITerminalService { const instanceId = TerminalInstance.getInstanceIdFromUri(resource); let instance = instanceId === undefined ? undefined : this.getInstanceFromId(instanceId); if (instance) { - const sourceGroup = this.getGroupForInstance(instance); + const sourceGroup = this._terminalGroupService.getGroupForInstance(instance); if (sourceGroup) { sourceGroup.removeInstance(instance); } @@ -355,7 +355,7 @@ export class TerminalService implements ITerminalService { // create group and terminal const config = { attachPersistentProcess: terminalLayout.terminal! } as IShellLaunchConfig; terminalInstance = this.createTerminal(config); - group = this.getGroupForInstance(terminalInstance); + group = this._terminalGroupService.getGroupForInstance(terminalInstance); if (groupLayout.isActive) { activeGroup = group; } @@ -576,7 +576,7 @@ export class TerminalService implements ITerminalService { splitInstance(instanceToSplit: ITerminalInstance, shellLaunchConfig?: IShellLaunchConfig): ITerminalInstance | null; splitInstance(instanceToSplit: ITerminalInstance, profile: ITerminalProfile, cwd?: string | URI): ITerminalInstance | null splitInstance(instanceToSplit: ITerminalInstance, shellLaunchConfigOrProfile: IShellLaunchConfig | ITerminalProfile = {}, cwd?: string | URI): ITerminalInstance | null { - const group = this.getGroupForInstance(instanceToSplit); + const group = this._terminalGroupService.getGroupForInstance(instanceToSplit); if (!group) { return null; } @@ -594,7 +594,7 @@ export class TerminalService implements ITerminalService { if (source.target === TerminalLocation.Editor) { return; } - const sourceGroup = this.getGroupForInstance(source); + const sourceGroup = this._terminalGroupService.getGroupForInstance(source); if (!sourceGroup) { return; } @@ -619,7 +619,7 @@ export class TerminalService implements ITerminalService { let group: ITerminalGroup | undefined; if (target) { - group = this.getGroupForInstance(target); + group = this._terminalGroupService.getGroupForInstance(target); } if (!group) { @@ -639,12 +639,10 @@ export class TerminalService implements ITerminalService { // Fire events this._onDidChangeInstances.fire(); - // this._onGroupsChanged.fire(); this._onActiveGroupChanged.fire(); } protected _initInstanceListeners(instance: ITerminalInstance): void { - // instance.addDisposable(instance.onDisposed(this._onInstanceDisposed.fire, this._onInstanceDisposed)); instance.addDisposable(instance.onTitleChanged(this._onInstanceTitleChanged.fire, this._onInstanceTitleChanged)); instance.addDisposable(instance.onIconChanged(this._onInstanceIconChanged.fire, this._onInstanceIconChanged)); instance.addDisposable(instance.onIconChanged(this._onInstanceColorChanged.fire, this._onInstanceColorChanged)); @@ -727,18 +725,13 @@ export class TerminalService implements ITerminalService { } instanceIsSplit(instance: ITerminalInstance): boolean { - const group = this.getGroupForInstance(instance); + const group = this._terminalGroupService.getGroupForInstance(instance); if (!group) { return false; } return group.terminalInstances.length > 1; } - // TODO: Move to group service - getGroupForInstance(instance: ITerminalInstance): ITerminalGroup | undefined { - return this._terminalGroupService.groups.find(group => group.terminalInstances.indexOf(instance) !== -1); - } - async showPanel(focus?: boolean): Promise { if (this.configHelper.config.defaultLocation === TerminalLocation.Editor) { return; diff --git a/src/vs/workbench/contrib/terminal/browser/terminalTabbedView.ts b/src/vs/workbench/contrib/terminal/browser/terminalTabbedView.ts index ae4514b8afb..0da73c85a84 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalTabbedView.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalTabbedView.ts @@ -227,7 +227,7 @@ export class TerminalTabbedView extends Disposable { // Size to include padding, icon, status icon (if any), split annotation (if any), + a little more const additionalWidth = 30; const statusIconWidth = instance.statusList.statuses.length > 0 ? STATUS_ICON_WIDTH : 0; - const splitAnnotationWidth = (this._terminalService.getGroupForInstance(instance)?.terminalInstances.length || 0) > 1 ? SPLIT_ANNOTATION_WIDTH : 0; + const splitAnnotationWidth = (this._terminalGroupService.getGroupForInstance(instance)?.terminalInstances.length || 0) > 1 ? SPLIT_ANNOTATION_WIDTH : 0; return additionalWidth + splitAnnotationWidth + statusIconWidth; } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalTabsList.ts b/src/vs/workbench/contrib/terminal/browser/terminalTabsList.ts index af6a8064032..93220c26798 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalTabsList.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalTabsList.ts @@ -195,6 +195,7 @@ class TerminalTabsRenderer implements IListRenderer ITerminalInstance[], @IInstantiationService private readonly _instantiationService: IInstantiationService, @ITerminalService private readonly _terminalService: ITerminalService, + @ITerminalGroupService private readonly _terminalGroupService: ITerminalGroupService, @IHoverService private readonly _hoverService: IHoverService, @IConfigurationService private readonly _configurationService: IConfigurationService, @IKeybindingService private readonly _keybindingService: IKeybindingService, @@ -251,7 +252,7 @@ class TerminalTabsRenderer implements IListRenderer { - constructor(@ITerminalService private readonly _terminalService: ITerminalService) { } + constructor( + @ITerminalGroupService private readonly _terminalGroupService: ITerminalGroupService, + ) { } getWidgetAriaLabel(): string { return localize('terminal.tabs', "Terminal tabs"); @@ -489,7 +492,7 @@ class TerminalTabsAccessibilityProvider implements IListAccessibilityProvider 1) { const terminalIndex = tab.terminalInstances.indexOf(instance); ariaLabel = localize({ From fbf73bd8e4e0f750a0143b1b985d12a3530a8362 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 18 Jun 2021 10:58:08 -0700 Subject: [PATCH 24/31] Fire active group changed event --- .../contrib/terminal/browser/terminal.ts | 2 +- .../contrib/terminal/browser/terminalGroup.ts | 12 ++++------ .../terminal/browser/terminalGroupService.ts | 24 +++++++------------ .../terminal/browser/terminalInstance.ts | 1 + .../terminal/browser/terminalService.ts | 9 +++---- 5 files changed, 21 insertions(+), 27 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index ee94bdab634..93a8b64b2b1 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -121,7 +121,7 @@ export interface ITerminalService extends ITerminalInstanceHost { readonly profilesReady: Promise; initializeTerminals(): Promise; - onActiveGroupChanged: Event; + onActiveGroupChanged: Event; onGroupDisposed: Event; onInstanceCreated: Event; onInstanceProcessIdReady: Event; diff --git a/src/vs/workbench/contrib/terminal/browser/terminalGroup.ts b/src/vs/workbench/contrib/terminal/browser/terminalGroup.ts index 63ec90439d2..ad355995d14 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalGroup.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalGroup.ts @@ -235,7 +235,7 @@ export class TerminalGroup extends Disposable implements ITerminalGroup { private _terminalLocation: ViewContainerLocation = ViewContainerLocation.Panel; private _instanceDisposables: Map = new Map(); - private _activeInstanceIndex: number; + private _activeInstanceIndex: number = -1; private _isVisible: boolean = false; get terminalInstances(): ITerminalInstance[] { return this._terminalInstances; } @@ -248,6 +248,8 @@ export class TerminalGroup extends Disposable implements ITerminalGroup { readonly onDisposed = this._onDisposed.event; private readonly _onInstancesChanged: Emitter = this._register(new Emitter()); readonly onInstancesChanged = this._onInstancesChanged.event; + private readonly _onDidChangeActiveInstance = new Emitter(); + readonly onDidChangeActiveInstance = this._onDidChangeActiveInstance.event; private readonly _onPanelOrientationChanged = new Emitter(); readonly onPanelOrientationChanged = this._onPanelOrientationChanged.event; @@ -263,7 +265,6 @@ export class TerminalGroup extends Disposable implements ITerminalGroup { if (shellLaunchConfigOrInstance) { this.addInstance(shellLaunchConfigOrInstance); } - this._activeInstanceIndex = 0; if (this._container) { this.attachToElement(this._container); } @@ -421,12 +422,9 @@ export class TerminalGroup extends Disposable implements ITerminalGroup { return; } - const didInstanceChange = this._activeInstanceIndex !== index; this._activeInstanceIndex = index; - - if (didInstanceChange) { - this._onInstancesChanged.fire(); - } + this._onInstancesChanged.fire(); + this._onDidChangeActiveInstance.fire(this.activeInstance); } attachToElement(element: HTMLElement): void { diff --git a/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts b/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts index 9d55affa863..22a5450656c 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts @@ -99,6 +99,7 @@ export class TerminalGroupService extends Disposable implements ITerminalGroupSe group.onPanelOrientationChanged((orientation) => this._onPanelOrientationChanged.fire(orientation)); this.groups.push(group); group.addDisposable(group.onDidDisposeInstance(this._onDidDisposeInstance.fire, this._onDidDisposeInstance)); + group.addDisposable(group.onDidChangeActiveInstance(this._onDidChangeActiveInstance.fire, this._onDidChangeActiveInstance)); group.addDisposable(group.onInstancesChanged(this._onDidChangeInstances.fire, this._onDidChangeInstances)); group.addDisposable(group.onDisposed(this._onDidDisposeGroup.fire, this._onDidDisposeGroup)); if (group.terminalInstances.length > 0) { @@ -109,16 +110,6 @@ export class TerminalGroupService extends Disposable implements ITerminalGroupSe } private _removeGroup(group: ITerminalGroup): void { - const wasActiveGroup = this._removeGroupAndAdjustFocus(group); - - this._onDidChangeInstances.fire(); - this._onDidChangeGroups.fire(); - if (wasActiveGroup) { - this._onDidChangeActiveGroup.fire(this.activeGroup); - } - } - - private _removeGroupAndAdjustFocus(group: ITerminalGroup): boolean { // Get the index of the group and remove it from the list const activeGroup = this.activeGroup; const wasActiveGroup = group === activeGroup; @@ -138,11 +129,15 @@ export class TerminalGroupService extends Disposable implements ITerminalGroupSe this.setActiveGroupByIndex(newIndex); } + this._onDidChangeInstances.fire(); if (this.groups.length === 0) { this._onDidChangeActiveInstance.fire(undefined); } - return wasActiveGroup; + this._onDidChangeGroups.fire(); + if (wasActiveGroup) { + this._onDidChangeActiveGroup.fire(this.activeGroup); + } } setActiveGroupByIndex(index: number): void { @@ -185,13 +180,12 @@ export class TerminalGroupService extends Disposable implements ITerminalGroupSe this.activeInstanceIndex = instanceLocation.instanceIndex; this.activeGroupIndex = instanceLocation.groupIndex; - instanceLocation.group.setActiveInstanceByIndex(this.activeInstanceIndex); - this.groups.forEach((g, i) => g.setVisible(i === instanceLocation.groupIndex)); - if (this.activeGroupIndex !== instanceLocation.groupIndex) { this._onDidChangeActiveGroup.fire(this.activeGroup); } - this._onDidChangeActiveInstance.fire(instanceLocation.instance); + this.groups.forEach((g, i) => g.setVisible(i === instanceLocation.groupIndex)); + + instanceLocation.group.setActiveInstanceByIndex(this.activeInstanceIndex); } setActiveGroupToNext(): void { diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index 2dde0e3093b..557efa45322 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -984,6 +984,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { if (!this._isDisposed) { this._isDisposed = true; + console.log('fire dispose', this.instanceId); this._onDisposed.fire(this); } super.dispose(); diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index 4f8b7ad7d21..327374d234f 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -101,8 +101,8 @@ export class TerminalService implements ITerminalService { } } - private readonly _onActiveGroupChanged = new Emitter(); - get onActiveGroupChanged(): Event { return this._onActiveGroupChanged.event; } + 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 _onDidDisposeInstance = new Emitter(); @@ -210,6 +210,7 @@ export class TerminalService implements ITerminalService { this._forwardInstanceHostEvents(this._terminalGroupService); this._forwardInstanceHostEvents(this._terminalEditorService); + this._terminalGroupService.onDidChangeActiveGroup(this._onActiveGroupChanged.fire, this._onActiveGroupChanged); this._terminalGroupService.onPanelOrientationChanged(this._onPanelOrientationChanged.fire, this.onPanelOrientationChanged); // the below avoids having to poll routinely. @@ -527,7 +528,7 @@ export class TerminalService implements ITerminalService { } refreshActiveGroup(): void { - this._onActiveGroupChanged.fire(); + this._onActiveGroupChanged.fire(this._terminalGroupService.activeGroup); } doWithActiveInstance(callback: (terminal: ITerminalInstance) => T): T | void { @@ -639,7 +640,7 @@ export class TerminalService implements ITerminalService { // Fire events this._onDidChangeInstances.fire(); - this._onActiveGroupChanged.fire(); + this._onActiveGroupChanged.fire(this._terminalGroupService.activeGroup); } protected _initInstanceListeners(instance: ITerminalInstance): void { From f4287f8fdfe299822998a9b3b4ccf0329f8a4052 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 18 Jun 2021 13:14:25 -0700 Subject: [PATCH 25/31] Fire active instance changed in editor if index is the same --- .../contrib/terminal/browser/terminalEditorService.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalEditorService.ts b/src/vs/workbench/contrib/terminal/browser/terminalEditorService.ts index 072767dc33b..8c8c2185b0b 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalEditorService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalEditorService.ts @@ -50,14 +50,15 @@ export class TerminalEditorService extends Disposable implements ITerminalEditor } set activeInstance(value: ITerminalInstance | undefined) { - const oldActiveIndex = this._activeInstanceIndex; + const oldActiveInstance = this.activeInstance; if (value === undefined) { this._activeInstanceIndex = -1; } else { this._activeInstanceIndex = this.instances.findIndex(e => e === value); } - if (oldActiveIndex !== this._activeInstanceIndex) { - this._onDidChangeActiveInstance.fire(this.activeInstance); + const newActiveInstance = this.activeInstance; + if (oldActiveInstance !== newActiveInstance) { + this._onDidChangeActiveInstance.fire(newActiveInstance); } } From 1ffc3100e64250ed0fd50c6c38bedce6a24f4fb3 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 18 Jun 2021 13:15:45 -0700 Subject: [PATCH 26/31] Invert if statement to reduce indentation --- .../contrib/terminal/browser/terminalFindWidget.ts | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalFindWidget.ts b/src/vs/workbench/contrib/terminal/browser/terminalFindWidget.ts index b2f8eb9a4d6..1f14339bb71 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalFindWidget.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalFindWidget.ts @@ -30,12 +30,13 @@ export class TerminalFindWidget extends SimpleFindWidget { find(previous: boolean) { const instance = this._terminalService.activeInstance; - if (instance) { - if (previous) { - instance.findPrevious(this.inputValue, { regex: this._getRegexValue(), wholeWord: this._getWholeWordValue(), caseSensitive: this._getCaseSensitiveValue() }); - } else { - instance.findNext(this.inputValue, { regex: this._getRegexValue(), wholeWord: this._getWholeWordValue(), caseSensitive: this._getCaseSensitiveValue() }); - } + if (!instance) { + return; + } + if (previous) { + instance.findPrevious(this.inputValue, { regex: this._getRegexValue(), wholeWord: this._getWholeWordValue(), caseSensitive: this._getCaseSensitiveValue() }); + } else { + instance.findNext(this.inputValue, { regex: this._getRegexValue(), wholeWord: this._getWholeWordValue(), caseSensitive: this._getCaseSensitiveValue() }); } } From f97906dfb12086fd68285c9e7fcf067af5086959 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 18 Jun 2021 13:38:15 -0700 Subject: [PATCH 27/31] Disallow setting active instance to undefined outside services --- .../api/browser/mainThreadTerminalService.ts | 2 +- .../browser/externalTerminal.contribution.ts | 2 +- .../quickaccess/browser/viewQuickAccess.ts | 2 +- .../tasks/browser/terminalTaskSystem.ts | 12 +++---- .../contrib/terminal/browser/terminal.ts | 4 ++- .../terminal/browser/terminalActions.ts | 16 ++++----- .../terminal/browser/terminalEditorService.ts | 12 ++++--- .../terminal/browser/terminalGroupService.ts | 27 +++++++-------- .../terminal/browser/terminalQuickAccess.ts | 2 +- .../terminal/browser/terminalService.ts | 34 +++++++++---------- .../terminal/browser/terminalTabsList.ts | 10 +++--- .../electron-sandbox/terminalRemote.ts | 2 +- .../browser/testingOutputTerminalService.ts | 4 +-- 13 files changed, 65 insertions(+), 64 deletions(-) diff --git a/src/vs/workbench/api/browser/mainThreadTerminalService.ts b/src/vs/workbench/api/browser/mainThreadTerminalService.ts index a1206838e28..f437285b00d 100644 --- a/src/vs/workbench/api/browser/mainThreadTerminalService.ts +++ b/src/vs/workbench/api/browser/mainThreadTerminalService.ts @@ -159,7 +159,7 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape public $show(id: TerminalIdentifier, preserveFocus: boolean): void { const terminalInstance = this._getTerminalInstance(id); if (terminalInstance) { - this._terminalService.activeInstance = terminalInstance; + this._terminalService.setActiveInstance(terminalInstance); this._terminalService.showPanel(!preserveFocus); } } diff --git a/src/vs/workbench/contrib/externalTerminal/browser/externalTerminal.contribution.ts b/src/vs/workbench/contrib/externalTerminal/browser/externalTerminal.contribution.ts index 4cfa593f991..e2d7b40f433 100644 --- a/src/vs/workbench/contrib/externalTerminal/browser/externalTerminal.contribution.ts +++ b/src/vs/workbench/contrib/externalTerminal/browser/externalTerminal.contribution.ts @@ -66,7 +66,7 @@ CommandsRegistry.registerCommand({ opened[cwd.path] = true; const instance = integratedTerminalService.createTerminal({ config: { cwd } }); if (instance && (resources.length === 1 || !resource || cwd.path === resource.path || cwd.path === dirname(resource.path))) { - integratedTerminalService.activeInstance = instance; + integratedTerminalService.setActiveInstance(instance); integratedTerminalService.showPanel(true); } }); diff --git a/src/vs/workbench/contrib/quickaccess/browser/viewQuickAccess.ts b/src/vs/workbench/contrib/quickaccess/browser/viewQuickAccess.ts index 9a4c4e8eeca..5a47cc54c3b 100644 --- a/src/vs/workbench/contrib/quickaccess/browser/viewQuickAccess.ts +++ b/src/vs/workbench/contrib/quickaccess/browser/viewQuickAccess.ts @@ -157,7 +157,7 @@ export class ViewQuickAccessProvider extends PickerQuickAccessProvider { await this.terminalService.showPanel(true); - this.terminalService.activeInstance = terminal; + this.terminalService.setActiveInstance(terminal); } }); }); diff --git a/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts b/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts index 61483e881d7..31e420ae126 100644 --- a/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts +++ b/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts @@ -324,7 +324,7 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { if (isTerminalInPanel && this.isTaskVisible(task)) { if (this.previousPanelId) { if (this.previousTerminalInstance) { - this.terminalService.activeInstance = this.previousTerminalInstance; + this.terminalService.setActiveInstance(this.previousTerminalInstance); } this.panelService.openPanel(this.previousPanelId); } else { @@ -339,7 +339,7 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { this.previousTerminalInstance = this.terminalService.activeInstance ?? undefined; } } - this.terminalService.activeInstance = terminalData.terminal; + this.terminalService.setActiveInstance(terminalData.terminal); if (CustomTask.is(task) || ContributedTask.is(task)) { this.terminalService.showPanel(task.command.presentation!.focus); } @@ -770,7 +770,7 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { if (revealProblems === RevealProblemKind.OnProblem) { this.viewsService.openView(Constants.MARKERS_VIEW_ID, true); } else if (reveal === RevealKind.Silent) { - this.terminalService.activeInstance = terminal; + this.terminalService.setActiveInstance(terminal!); this.terminalService.showPanel(false); } } @@ -839,7 +839,7 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { if ((reveal === RevealKind.Silent) && ((exitCode !== 0) || (watchingProblemMatcher.numberOfMatches > 0) && watchingProblemMatcher.maxMarkerSeverity && (watchingProblemMatcher.maxMarkerSeverity >= MarkerSeverity.Error))) { try { - this.terminalService.activeInstance = terminal; + this.terminalService.setActiveInstance(terminal!); this.terminalService.showPanel(false); } catch (e) { // If the terminal has already been disposed, then setting the active instance will fail. #99828 @@ -924,7 +924,7 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { } else if (terminal && (reveal === RevealKind.Silent) && ((exitCode !== 0) || (startStopProblemMatcher.numberOfMatches > 0) && startStopProblemMatcher.maxMarkerSeverity && (startStopProblemMatcher.maxMarkerSeverity >= MarkerSeverity.Error))) { try { - this.terminalService.activeInstance = terminal; + this.terminalService.setActiveInstance(terminal); this.terminalService.showPanel(false); } catch (e) { // If the terminal has already been disposed, then setting the active instance will fail. #99828 @@ -957,7 +957,7 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { if (showProblemPanel) { this.viewsService.openView(Constants.MARKERS_VIEW_ID); } else if (task.command.presentation && (task.command.presentation.reveal === RevealKind.Always)) { - this.terminalService.activeInstance = terminal; + this.terminalService.setActiveInstance(terminal); this.terminalService.showPanel(task.command.presentation.focus); } this.activeTasks[task.getMapKey()] = { terminal, task, promise }; diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index 93a8b64b2b1..ad1e71abe4b 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -265,12 +265,14 @@ export interface ITerminalGroupService extends ITerminalInstanceHost { * properties and events. */ export interface ITerminalInstanceHost { - activeInstance: ITerminalInstance | undefined; + readonly activeInstance: ITerminalInstance | undefined; readonly instances: readonly ITerminalInstance[]; readonly onDidDisposeInstance: Event; readonly onDidChangeActiveInstance: Event; readonly onDidChangeInstances: Event; + + setActiveInstance(instance: ITerminalInstance): void; } export interface IRemoteTerminalService extends IOffProcessTerminalService { diff --git a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts index 0350f6b59b0..a9035572261 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts @@ -118,7 +118,7 @@ export function registerTerminalActions() { if (!instance) { return; } - terminalService.activeInstance = instance; + terminalService.setActiveInstance(instance); } await terminalService.showPanel(true); } @@ -184,7 +184,7 @@ export function registerTerminalActions() { } if (instance) { - terminalService.activeInstance = instance; + terminalService.setActiveInstance(instance); } } await terminalService.showPanel(true); @@ -399,7 +399,7 @@ export function registerTerminalActions() { if (!instance) { return; } - terminalService.activeInstance = instance; + terminalService.setActiveInstance(instance); return terminalService.showPanel(true); } }); @@ -945,7 +945,7 @@ export function registerTerminalActions() { const instance = terminalService.createTerminal({ config: { attachPersistentProcess: selected.term } }); - terminalService.activeInstance = instance; + terminalService.setActiveInstance(instance); terminalService.showPanel(true); } } @@ -1163,7 +1163,7 @@ export function registerTerminalActions() { if (!instance) { return; } - terminalService.activeInstance = instance; + terminalService.setActiveInstance(instance); } return terminalService.showPanel(true); } @@ -1436,7 +1436,7 @@ export function registerTerminalActions() { const instances = getSelectedInstances(accessor); if (instances) { for (const t of instances) { - terminalService.activeInstance = t; + terminalService.setActiveInstance(t); terminalService.doWithActiveInstance(async instance => { const cwd = await getCwdForSplit(terminalService.configHelper, instance); terminalService.splitInstance(instance, { cwd }); @@ -1594,7 +1594,7 @@ export function registerTerminalActions() { } ); } - terminalService.activeInstance = instance; + terminalService.setActiveInstance(instance); } await terminalService.showPanel(true); } @@ -1834,7 +1834,7 @@ export function registerTerminalActions() { { config: profile }); - terminalService.activeInstance = instance; + terminalService.setActiveInstance(instance); } else { console.warn(`No profile with name "${profileSelection}"`); } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalEditorService.ts b/src/vs/workbench/contrib/terminal/browser/terminalEditorService.ts index 8c8c2185b0b..e445e846524 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalEditorService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalEditorService.ts @@ -38,7 +38,7 @@ export class TerminalEditorService extends Disposable implements ITerminalEditor })); this._register(this._editorService.onDidActiveEditorChange(() => { const activeEditor = this._editorService.activeEditor; - this.activeInstance = activeEditor instanceof TerminalEditorInput ? activeEditor?.terminalInstance : undefined; + this._setActiveInstance(activeEditor instanceof TerminalEditorInput ? activeEditor?.terminalInstance : undefined); })); } @@ -49,12 +49,16 @@ export class TerminalEditorService extends Disposable implements ITerminalEditor return this.instances[this._activeInstanceIndex]; } - set activeInstance(value: ITerminalInstance | undefined) { + setActiveInstance(instance: ITerminalInstance): void { + this._setActiveInstance(instance); + } + + private _setActiveInstance(instance: ITerminalInstance | undefined): void { const oldActiveInstance = this.activeInstance; - if (value === undefined) { + if (instance === undefined) { this._activeInstanceIndex = -1; } else { - this._activeInstanceIndex = this.instances.findIndex(e => e === value); + this._activeInstanceIndex = this.instances.findIndex(e => e === instance); } const newActiveInstance = this.activeInstance; if (oldActiveInstance !== newActiveInstance) { diff --git a/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts b/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts index 22a5450656c..d90d0f5fd38 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts @@ -73,11 +73,8 @@ export class TerminalGroupService extends Disposable implements ITerminalGroupSe return this.activeGroup?.activeInstance; } - set activeInstance(value: ITerminalInstance | undefined) { - if (value === undefined) { - return; - } - this.setActiveInstanceByIndex(this._getIndexFromId(value.instanceId)); + setActiveInstance(instance: ITerminalInstance) { + this.setActiveInstanceByIndex(this._getIndexFromId(instance.instanceId)); } private _getIndexFromId(terminalId: number): number { @@ -109,7 +106,7 @@ export class TerminalGroupService extends Disposable implements ITerminalGroupSe return group; } - private _removeGroup(group: ITerminalGroup): void { + private _removeGroup(group: ITerminalGroup) { // Get the index of the group and remove it from the list const activeGroup = this.activeGroup; const wasActiveGroup = group === activeGroup; @@ -140,7 +137,7 @@ export class TerminalGroupService extends Disposable implements ITerminalGroupSe } } - setActiveGroupByIndex(index: number): void { + setActiveGroupByIndex(index: number) { if (index >= this.groups.length) { return; } @@ -171,7 +168,7 @@ export class TerminalGroupService extends Disposable implements ITerminalGroupSe return undefined; } - setActiveInstanceByIndex(index: number): void { + setActiveInstanceByIndex(index: number) { const instanceLocation = this._getInstanceLocation(index); if (!instanceLocation || (this.activeInstanceIndex > 0 && this.activeInstanceIndex === index)) { return; @@ -188,7 +185,7 @@ export class TerminalGroupService extends Disposable implements ITerminalGroupSe instanceLocation.group.setActiveInstanceByIndex(this.activeInstanceIndex); } - setActiveGroupToNext(): void { + setActiveGroupToNext() { if (this.groups.length <= 1) { return; } @@ -199,7 +196,7 @@ export class TerminalGroupService extends Disposable implements ITerminalGroupSe this.setActiveGroupByIndex(newIndex); } - setActiveGroupToPrevious(): void { + setActiveGroupToPrevious() { if (this.groups.length <= 1) { return; } @@ -210,7 +207,7 @@ export class TerminalGroupService extends Disposable implements ITerminalGroupSe this.setActiveGroupByIndex(newIndex); } - moveGroup(source: ITerminalInstance, target: ITerminalInstance): void { + moveGroup(source: ITerminalInstance, target: ITerminalInstance) { const sourceGroup = this.getGroupForInstance(source); const targetGroup = this.getGroupForInstance(target); if (!sourceGroup || !targetGroup) { @@ -223,7 +220,7 @@ export class TerminalGroupService extends Disposable implements ITerminalGroupSe this._onDidChangeInstances.fire(); } - moveInstance(source: ITerminalInstance, target: ITerminalInstance, side: 'before' | 'after'): void { + moveInstance(source: ITerminalInstance, target: ITerminalInstance, side: 'before' | 'after') { const sourceGroup = this.getGroupForInstance(source); const targetGroup = this.getGroupForInstance(target); if (!sourceGroup || !targetGroup) { @@ -242,7 +239,7 @@ export class TerminalGroupService extends Disposable implements ITerminalGroupSe targetGroup.moveInstance(source, index); } - unsplitInstance(instance: ITerminalInstance): void { + unsplitInstance(instance: ITerminalInstance) { const oldGroup = this.getGroupForInstance(instance); if (!oldGroup || oldGroup.terminalInstances.length < 2) { return; @@ -252,7 +249,7 @@ export class TerminalGroupService extends Disposable implements ITerminalGroupSe this.createGroup(instance); } - joinInstances(instances: ITerminalInstance[]): void { + joinInstances(instances: ITerminalInstance[]) { // Find the group of the first instance that is the only instance in the group, if one exists let candidateInstance: ITerminalInstance | undefined = undefined; let candidateGroup: ITerminalGroup | undefined = undefined; @@ -288,7 +285,7 @@ export class TerminalGroupService extends Disposable implements ITerminalGroupSe } // Set the active terminal - this.activeInstance = instances[0]; + this.setActiveInstance(instances[0]); // Fire events this._onDidChangeInstances.fire(); diff --git a/src/vs/workbench/contrib/terminal/browser/terminalQuickAccess.ts b/src/vs/workbench/contrib/terminal/browser/terminalQuickAccess.ts index a33a457b028..476611da45d 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalQuickAccess.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalQuickAccess.ts @@ -76,7 +76,7 @@ export class TerminalQuickAccessProvider extends PickerQuickAccessProvider { - this._terminalService.activeInstance = terminal; + this._terminalService.setActiveInstance(terminal); this._terminalService.showPanel(!event.inBackground); } }); diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index 327374d234f..ea1340669ec 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -85,21 +85,6 @@ export class TerminalService implements ITerminalService { private _activeInstance: ITerminalInstance | undefined; get activeInstance(): ITerminalInstance | undefined { return this._activeInstance; } - set activeInstance(value: ITerminalInstance | undefined) { - if (value === undefined) { - throw new Error('Cannot set active instance to undefined'); - } - // If this was a hideFromUser terminal created by the API this was triggered by show, - // in which case we need to create the terminal group - if (value.shellLaunchConfig.hideFromUser) { - this._showBackgroundTerminal(value); - } - if (value.target === TerminalLocation.Editor) { - this._terminalEditorService.activeInstance = value; - } else { - this._terminalGroupService.activeInstance = value; - } - } private readonly _onActiveGroupChanged = new Emitter(); get onActiveGroupChanged(): Event { return this._onActiveGroupChanged.event; } @@ -295,6 +280,19 @@ export class TerminalService implements ITerminalService { }); } + setActiveInstance(value: ITerminalInstance) { + // If this was a hideFromUser terminal created by the API this was triggered by show, + // in which case we need to create the terminal group + if (value.shellLaunchConfig.hideFromUser) { + this._showBackgroundTerminal(value); + } + if (value.target === TerminalLocation.Editor) { + this._terminalEditorService.setActiveInstance(value); + } else { + this._terminalGroupService.setActiveInstance(value); + } + } + async safeDisposeTerminal(instance: ITerminalInstance): Promise { if (this.configHelper.config.confirmOnExit) { const notConfirmed = await this._showTerminalCloseConfirmation(true); @@ -369,7 +367,7 @@ export class TerminalService implements ITerminalService { return t.shellLaunchConfig.attachPersistentProcess?.id === groupLayout.activePersistentProcessId; }); if (activeInstance) { - this.activeInstance = activeInstance; + this.setActiveInstance(activeInstance); } group?.resizePanes(groupLayout.terminals.map(terminal => terminal.relativeSize)); } @@ -628,7 +626,7 @@ export class TerminalService implements ITerminalService { } group.addInstance(source); - this.activeInstance = source; + this.setActiveInstance(source); await this.showPanel(true); // TODO: Shouldn't this happen automatically? source.setVisible(true); @@ -888,7 +886,7 @@ export class TerminalService implements ITerminalService { if (instance && this.configHelper.config.defaultLocation === TerminalLocation.TerminalView) { this.showPanel(true); - this.activeInstance = instance; + this.setActiveInstance(instance); return instance; } } else { // setDefault diff --git a/src/vs/workbench/contrib/terminal/browser/terminalTabsList.ts b/src/vs/workbench/contrib/terminal/browser/terminalTabsList.ts index 93220c26798..274593761e5 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalTabsList.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalTabsList.ts @@ -118,7 +118,7 @@ export class TerminalTabList extends WorkbenchList { this.onMouseDblClick(async () => { if (this.getFocus().length === 0) { const instance = this._terminalService.createTerminal(); - this._terminalService.activeInstance = instance; + this._terminalService.setActiveInstance(instance); await instance.focusWhenReady(); } }); @@ -163,7 +163,7 @@ export class TerminalTabList extends WorkbenchList { if (e.editorOptions.pinned) { return; } - this._terminalService.activeInstance = instance; + this._terminalService.setActiveInstance(instance); if (!e.editorOptions.preserveFocus) { await instance.focusWhenReady(); } @@ -572,7 +572,7 @@ class TerminalTabsDragAndDrop implements IListDragAndDrop { if (didChangeAutoFocusInstance) { this._autoFocusDisposable = disposableTimeout(() => { - this._terminalService.activeInstance = targetInstance; + this._terminalService.setActiveInstance(targetInstance); this._autoFocusInstance = undefined; }, 500); } @@ -616,7 +616,7 @@ class TerminalTabsDragAndDrop implements IListDragAndDrop { for (const instance of sourceInstances) { this._terminalGroupService.moveGroup(instance, targetInstance); if (!focused) { - this._terminalService.activeInstance = instance; + this._terminalService.setActiveInstance(instance); focused = true; } } @@ -641,7 +641,7 @@ class TerminalTabsDragAndDrop implements IListDragAndDrop { return; } - this._terminalService.activeInstance = instance; + this._terminalService.setActiveInstance(instance); const preparedPath = await this._terminalInstanceService.preparePathForTerminalAsync(path, instance.shellLaunchConfig.executable, instance.title, instance.shellType, instance.isRemote); instance.sendText(preparedPath, false); diff --git a/src/vs/workbench/contrib/terminal/electron-sandbox/terminalRemote.ts b/src/vs/workbench/contrib/terminal/electron-sandbox/terminalRemote.ts index 2739f6b7f30..9743f3c138c 100644 --- a/src/vs/workbench/contrib/terminal/electron-sandbox/terminalRemote.ts +++ b/src/vs/workbench/contrib/terminal/electron-sandbox/terminalRemote.ts @@ -35,7 +35,7 @@ export class CreateNewLocalTerminalAction extends Action { return Promise.resolve(undefined); } - this._terminalService.activeInstance = instance; + this._terminalService.setActiveInstance(instance); return this._terminalService.showPanel(true); } } diff --git a/src/vs/workbench/contrib/testing/browser/testingOutputTerminalService.ts b/src/vs/workbench/contrib/testing/browser/testingOutputTerminalService.ts index aacb2d01bbb..ad63dc72cdf 100644 --- a/src/vs/workbench/contrib/testing/browser/testingOutputTerminalService.ts +++ b/src/vs/workbench/contrib/testing/browser/testingOutputTerminalService.ts @@ -87,7 +87,7 @@ export class TestingOutputTerminalService implements ITestingOutputTerminalServi // If there's an existing terminal for the attempted reveal, show that instead. const existing = testOutputPtys.find(([, o]) => o.resultId === result?.id); if (existing) { - this.terminalService.activeInstance = existing[0]; + this.terminalService.setActiveInstance(existing[0]); this.terminalService.showPanel(); return; } @@ -113,7 +113,7 @@ export class TestingOutputTerminalService implements ITestingOutputTerminalServi private async showResultsInTerminal(terminal: ITerminalInstance, output: TestOutputProcess, result: ITestResult | undefined) { this.outputTerminals.set(terminal, output); output.resetFor(result?.id, getTitle(result)); - this.terminalService.activeInstance = terminal; + this.terminalService.setActiveInstance(terminal); this.terminalService.showPanel(); if (!result) { From 9be212b478bd765cdeefcaa4353dc9b556b0d367 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 18 Jun 2021 13:43:02 -0700 Subject: [PATCH 28/31] Resolving feedback --- .../workbench/contrib/terminal/browser/terminalInstance.ts | 1 - .../workbench/contrib/terminal/browser/terminalService.ts | 6 ++++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index 557efa45322..2dde0e3093b 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -984,7 +984,6 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { if (!this._isDisposed) { this._isDisposed = true; - console.log('fire dispose', this.instanceId); this._onDisposed.fire(this); } super.dispose(); diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index ea1340669ec..986bf3f4c86 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -263,8 +263,10 @@ export class TerminalService implements ITerminalService { private _forwardInstanceHostEvents(host: ITerminalInstanceHost) { host.onDidChangeInstances(this._onDidChangeInstances.fire, this._onDidChangeInstances); host.onDidDisposeInstance(this._onDidDisposeInstance.fire, this._onDidDisposeInstance); - // Track the latest active terminal for each host so that when one becomes undefined (eg. - // the last terminal editor is closed) + // Track the latest active terminal for each host so that when one becomes undefined, the + // TerminalService's active terminal is set to the last active terminal from the other host. + // This means if the last terminal editor is closed such that it becomes undefined, the last + // active group's terminal will be used as the active terminal if available. this._hostActiveTerminals.set(host, undefined); host.onDidChangeActiveInstance(instance => { this._hostActiveTerminals.set(host, instance); From 2709165bd7d366718a39b8e65fb828d544438368 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 18 Jun 2021 13:56:11 -0700 Subject: [PATCH 29/31] Have tabs list only deal with terminal groups Fixes #126711 Co-Authored-By: Megan Rogge --- .../contrib/terminal/browser/terminal.ts | 2 +- .../terminal/browser/terminalGroupService.ts | 8 +++++++ .../terminal/browser/terminalService.ts | 9 ------- .../terminal/browser/terminalTabsList.ts | 24 +++++++++---------- 4 files changed, 21 insertions(+), 22 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index ad1e71abe4b..b2b3de7ae7a 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -200,7 +200,6 @@ export interface ITerminalService extends ITerminalInstanceHost { isAttachedToTerminal(remoteTerm: IRemoteTerminalAttachTarget): boolean; getEditableData(instance: ITerminalInstance): IEditableData | undefined; setEditable(instance: ITerminalInstance, data: IEditableData | null): Promise; - instanceIsSplit(instance: ITerminalInstance): boolean; safeDisposeTerminal(instance: ITerminalInstance): Promise; } @@ -249,6 +248,7 @@ export interface ITerminalGroupService extends ITerminalInstanceHost { moveInstance(source: ITerminalInstance, target: ITerminalInstance, side: 'before' | 'after'): void; unsplitInstance(instance: ITerminalInstance): void; joinInstances(instances: ITerminalInstance[]): void; + instanceIsSplit(instance: ITerminalInstance): boolean; getGroupLabels(): string[]; setActiveGroupByIndex(index: number): void; diff --git a/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts b/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts index d90d0f5fd38..dd6423c2fac 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts @@ -294,6 +294,14 @@ export class TerminalGroupService extends Disposable implements ITerminalGroupSe } } + instanceIsSplit(instance: ITerminalInstance): boolean { + const group = this.getGroupForInstance(instance); + if (!group) { + return false; + } + return group.terminalInstances.length > 1; + } + getGroupForInstance(instance: ITerminalInstance): ITerminalGroup | undefined { return this.groups.find(group => group.terminalInstances.indexOf(instance) !== -1); } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index 986bf3f4c86..390bf991163 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -586,7 +586,6 @@ export class TerminalService implements ITerminalService { this._initInstanceListeners(instance); - // TODO: Move into group service? this._terminalGroupService.groups.forEach((g, i) => g.setVisible(i === this._terminalGroupService.activeGroupIndex)); return instance; } @@ -725,14 +724,6 @@ export class TerminalService implements ITerminalService { } } - instanceIsSplit(instance: ITerminalInstance): boolean { - const group = this._terminalGroupService.getGroupForInstance(instance); - if (!group) { - return false; - } - return group.terminalInstances.length > 1; - } - async showPanel(focus?: boolean): Promise { if (this.configHelper.config.defaultLocation === TerminalLocation.Editor) { return; diff --git a/src/vs/workbench/contrib/terminal/browser/terminalTabsList.ts b/src/vs/workbench/contrib/terminal/browser/terminalTabsList.ts index 274593761e5..2c8fceb5959 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalTabsList.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalTabsList.ts @@ -16,7 +16,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; import { MenuItemAction } from 'vs/platform/actions/common/actions'; import { MenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem'; -import { IS_SPLIT_TERMINAL_CONTEXT_KEY, KEYBINDING_CONTEXT_TERMINAL_TABS_SINGULAR_SELECTION, TerminalCommandId, TerminalLocation } from 'vs/workbench/contrib/terminal/common/terminal'; +import { IS_SPLIT_TERMINAL_CONTEXT_KEY, KEYBINDING_CONTEXT_TERMINAL_TABS_SINGULAR_SELECTION, TerminalCommandId } from 'vs/workbench/contrib/terminal/common/terminal'; import { TerminalSettingId } from 'vs/platform/terminal/common/terminal'; import { Codicon } from 'vs/base/common/codicons'; import { Action } from 'vs/base/common/actions'; @@ -68,8 +68,8 @@ export class TerminalTabList extends WorkbenchList { @IThemeService themeService: IThemeService, @IConfigurationService configurationService: IConfigurationService, @IKeybindingService keybindingService: IKeybindingService, - @ITerminalService private _terminalService: ITerminalService, - @ITerminalGroupService terminalGroupService: ITerminalGroupService, + @ITerminalService private readonly _terminalService: ITerminalService, + @ITerminalGroupService private readonly _terminalGroupService: ITerminalGroupService, @ITerminalInstanceService _terminalInstanceService: ITerminalInstanceService, @IInstantiationService instantiationService: IInstantiationService, @IDecorationsService _decorationsService: IDecorationsService, @@ -100,16 +100,16 @@ export class TerminalTabList extends WorkbenchList { configurationService, keybindingService, ); - this._terminalService.onDidChangeInstances(() => this.refresh()); - terminalGroupService.onDidChangeGroups(() => this.refresh()); + this._terminalGroupService.onDidChangeInstances(() => this.refresh()); + this._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.onDidChangeActiveInstance(e => { - if (e && e.target !== TerminalLocation.Editor) { - const i = this._terminalService.instances.indexOf(e); + this._terminalGroupService.onDidChangeActiveInstance(e => { + if (e) { + const i = this._terminalGroupService.instances.indexOf(e); this.setSelection([i]); this.reveal(i); } @@ -118,7 +118,7 @@ export class TerminalTabList extends WorkbenchList { this.onMouseDblClick(async () => { if (this.getFocus().length === 0) { const instance = this._terminalService.createTerminal(); - this._terminalService.setActiveInstance(instance); + this._terminalGroupService.setActiveInstance(instance); await instance.focusWhenReady(); } }); @@ -163,7 +163,7 @@ export class TerminalTabList extends WorkbenchList { if (e.editorOptions.pinned) { return; } - this._terminalService.setActiveInstance(instance); + this._terminalGroupService.setActiveInstance(instance); if (!e.editorOptions.preserveFocus) { await instance.focusWhenReady(); } @@ -176,13 +176,13 @@ export class TerminalTabList extends WorkbenchList { } refresh(): void { - this.splice(0, this.length, this._terminalService.instances.slice()); + this.splice(0, this.length, this._terminalGroupService.instances.slice()); } private _updateContextKey() { this._terminalTabsSingleSelectedContextKey.set(this.getSelectedElements().length === 1); const instance = this.getFocusedElements(); - this._isSplitContextKey.set(instance.length > 0 && this._terminalService.instanceIsSplit(instance[0])); + this._isSplitContextKey.set(instance.length > 0 && this._terminalGroupService.instanceIsSplit(instance[0])); } } From 84a14b105f46ab2f3ebc3a4cd6776ae5633e5b0a Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 18 Jun 2021 14:02:34 -0700 Subject: [PATCH 30/31] Use group service for instances in tabbed view --- .../contrib/terminal/browser/terminal.ts | 8 +++++++- .../terminal/browser/terminalService.ts | 4 ---- .../terminal/browser/terminalTabbedView.ts | 20 +++++++++---------- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index b2b3de7ae7a..5543c983c9c 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -114,6 +114,8 @@ export interface ICreateTerminalOptions { export interface ITerminalService extends ITerminalInstanceHost { readonly _serviceBrand: undefined; + /** Gets all terminal instances, including editor and terminal view (group) instances. */ + readonly instances: readonly ITerminalInstance[]; configHelper: ITerminalConfigHelper; isProcessSupportRegistered: boolean; readonly connectionState: TerminalConnectionState; @@ -135,7 +137,6 @@ export interface ITerminalService extends ITerminalInstanceHost { onDidRegisterProcessSupport: Event; onDidChangeConnectionState: Event; onDidChangeAvailableProfiles: Event; - onPanelOrientationChanged: Event; /** * Creates a terminal. @@ -210,6 +211,9 @@ export interface ITerminalService extends ITerminalInstanceHost { export interface ITerminalEditorService extends ITerminalInstanceHost { readonly _serviceBrand: undefined; + /** Gets all _terminal editor_ instances. */ + readonly instances: readonly ITerminalInstance[]; + createEditor(instance: ITerminalInstance): Promise; createEditorInput(instance: ITerminalInstance): TerminalEditorInput; detachActiveEditorInstance(): ITerminalInstance; @@ -223,6 +227,8 @@ export interface ITerminalEditorService extends ITerminalInstanceHost { export interface ITerminalGroupService extends ITerminalInstanceHost { readonly _serviceBrand: undefined; + /** Gets all _terminal view_ instances, ie. instances contained within terminal groups. */ + readonly instances: readonly ITerminalInstance[]; readonly groups: readonly ITerminalGroup[]; activeGroup: ITerminalGroup | undefined; readonly activeGroupIndex: number; diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index 390bf991163..002edb21900 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -3,7 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Orientation } from 'vs/base/browser/ui/sash/sash'; import { AutoOpenBarrier, timeout } from 'vs/base/common/async'; import { Codicon, iconRegistry } from 'vs/base/common/codicons'; import { debounce, throttle } from 'vs/base/common/decorators'; @@ -124,8 +123,6 @@ export class TerminalService implements ITerminalService { get onDidChangeConnectionState(): Event { return this._onDidChangeConnectionState.event; } private readonly _onDidChangeAvailableProfiles = new Emitter(); get onDidChangeAvailableProfiles(): Event { return this._onDidChangeAvailableProfiles.event; } - private readonly _onPanelOrientationChanged = new Emitter(); - get onPanelOrientationChanged(): Event { return this._onPanelOrientationChanged.event; } constructor( @IContextKeyService private _contextKeyService: IContextKeyService, @@ -196,7 +193,6 @@ export class TerminalService implements ITerminalService { this._forwardInstanceHostEvents(this._terminalGroupService); this._forwardInstanceHostEvents(this._terminalEditorService); this._terminalGroupService.onDidChangeActiveGroup(this._onActiveGroupChanged.fire, this._onActiveGroupChanged); - this._terminalGroupService.onPanelOrientationChanged(this._onPanelOrientationChanged.fire, this.onPanelOrientationChanged); // the below avoids having to poll routinely. // we update detected profiles when an instance is created so that, diff --git a/src/vs/workbench/contrib/terminal/browser/terminalTabbedView.ts b/src/vs/workbench/contrib/terminal/browser/terminalTabbedView.ts index 0da73c85a84..38b52d5d0fa 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.onDidChangeInstances(() => this._refreshShowTabs())); + this._register(this._terminalGroupService.onDidChangeInstances(() => this._refreshShowTabs())); this._register(this._terminalGroupService.onDidChangeGroups(() => this._refreshShowTabs())); this._register(this._themeService.onDidColorThemeChange(theme => this._updateTheme(theme))); this._updateTheme(); @@ -139,7 +139,7 @@ export class TerminalTabbedView extends Disposable { this._attachEventListeners(parentElement, this._terminalContainer); - this._terminalService.onPanelOrientationChanged((orientation) => { + this._terminalGroupService.onPanelOrientationChanged((orientation) => { this._panelOrientation = orientation; }); @@ -159,7 +159,7 @@ export class TerminalTabbedView extends Disposable { return true; } - if (hide === 'singleTerminal' && this._terminalService.instances.length > 1) { + if (hide === 'singleTerminal' && this._terminalGroupService.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.instances.reduce((p, c) => { + const maxInstanceWidth = this._terminalGroupService.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.instances.length === 0) { + if (this._terminalGroupService.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.activeInstance; + const terminal = this._terminalGroupService.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.activeInstance; + const terminal = this._terminalGroupService.activeInstance; if (!terminal) { return; } @@ -491,7 +491,7 @@ export class TerminalTabbedView extends Disposable { focusFindWidget() { this._findWidgetVisible.set(true); - const activeInstance = this._terminalService.activeInstance; + const activeInstance = this._terminalGroupService.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.activeInstance; + const activeInstance = this._terminalGroupService.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.activeInstance?.focusWhenReady(); + this._terminalGroupService.activeInstance?.focusWhenReady(); } } From f8fa1abd92dbce414b8b9f73f40ae32413b74ec1 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 18 Jun 2021 14:16:34 -0700 Subject: [PATCH 31/31] Fire hideFromUser terminal dispose events --- .../contrib/terminal/browser/terminalService.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index 002edb21900..1ead85ecc45 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -7,7 +7,7 @@ import { AutoOpenBarrier, timeout } from 'vs/base/common/async'; import { Codicon, iconRegistry } from 'vs/base/common/codicons'; import { debounce, throttle } from 'vs/base/common/decorators'; import { Emitter, Event } from 'vs/base/common/event'; -import { IDisposable, toDisposable } from 'vs/base/common/lifecycle'; +import { dispose, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { Schemas } from 'vs/base/common/network'; import { equals } from 'vs/base/common/objects'; import { isMacintosh, isWeb, isWindows, OperatingSystem, OS } from 'vs/base/common/platform'; @@ -54,6 +54,7 @@ export class TerminalService implements ITerminalService { private _terminalShellTypeContextKey: IContextKey; private _terminalAltBufferActiveContextKey: IContextKey; private _backgroundedTerminalInstances: ITerminalInstance[] = []; + private _backgroundedTerminalDisposables: Map = new Map(); private _findState: FindReplaceState; private readonly _profileProviders: Map> = new Map(); private _linkProviders: Set = new Set(); @@ -994,6 +995,9 @@ export class TerminalService implements ITerminalService { if (shellLaunchConfig.hideFromUser) { const instance = this.createInstance(shellLaunchConfig); this._backgroundedTerminalInstances.push(instance); + this._backgroundedTerminalDisposables.set(instance.instanceId, [ + instance.onDisposed(this._onDidDisposeInstance.fire, this._onDidDisposeInstance) + ]); this._initInstanceListeners(instance); return instance; } @@ -1033,6 +1037,11 @@ export class TerminalService implements ITerminalService { protected _showBackgroundTerminal(instance: ITerminalInstance): void { this._backgroundedTerminalInstances.splice(this._backgroundedTerminalInstances.indexOf(instance), 1); + const disposables = this._backgroundedTerminalDisposables.get(instance.instanceId); + if (disposables) { + dispose(disposables); + } + this._backgroundedTerminalDisposables.delete(instance.instanceId); instance.shellLaunchConfig.hideFromUser = false; this._terminalGroupService.createGroup(instance);