From 990c0569ceb88179df6429592e09931a7a1189ff Mon Sep 17 00:00:00 2001 From: Ladislau Szomoru <3372902+lszomoru@users.noreply.github.com> Date: Fri, 24 May 2024 16:33:35 +0200 Subject: [PATCH 1/5] Working sets - preserve focus when applying the working set was initiated by an action that was taken in the panel part (ex: switching branches from the terminal) --- .../browser/parts/editor/editorGroupView.ts | 19 ++++++++------- .../browser/parts/editor/editorPart.ts | 24 +++++++++---------- .../browser/parts/editor/editorParts.ts | 22 ++++++++++++----- 3 files changed, 38 insertions(+), 27 deletions(-) diff --git a/src/vs/workbench/browser/parts/editor/editorGroupView.ts b/src/vs/workbench/browser/parts/editor/editorGroupView.ts index d88cd67318658..5ad410782a16f 100644 --- a/src/vs/workbench/browser/parts/editor/editorGroupView.ts +++ b/src/vs/workbench/browser/parts/editor/editorGroupView.ts @@ -63,16 +63,16 @@ export class EditorGroupView extends Themable implements IEditorGroupView { //#region factory - static createNew(editorPartsView: IEditorPartsView, groupsView: IEditorGroupsView, groupsLabel: string, groupIndex: number, instantiationService: IInstantiationService): IEditorGroupView { - return instantiationService.createInstance(EditorGroupView, null, editorPartsView, groupsView, groupsLabel, groupIndex); + static createNew(editorPartsView: IEditorPartsView, groupsView: IEditorGroupsView, groupsLabel: string, groupIndex: number, instantiationService: IInstantiationService, preserveFocus?: boolean): IEditorGroupView { + return instantiationService.createInstance(EditorGroupView, null, editorPartsView, groupsView, groupsLabel, groupIndex, preserveFocus); } - static createFromSerialized(serialized: ISerializedEditorGroupModel, editorPartsView: IEditorPartsView, groupsView: IEditorGroupsView, groupsLabel: string, groupIndex: number, instantiationService: IInstantiationService): IEditorGroupView { - return instantiationService.createInstance(EditorGroupView, serialized, editorPartsView, groupsView, groupsLabel, groupIndex); + static createFromSerialized(serialized: ISerializedEditorGroupModel, editorPartsView: IEditorPartsView, groupsView: IEditorGroupsView, groupsLabel: string, groupIndex: number, instantiationService: IInstantiationService, preserveFocus?: boolean): IEditorGroupView { + return instantiationService.createInstance(EditorGroupView, serialized, editorPartsView, groupsView, groupsLabel, groupIndex, preserveFocus); } - static createCopy(copyFrom: IEditorGroupView, editorPartsView: IEditorPartsView, groupsView: IEditorGroupsView, groupsLabel: string, groupIndex: number, instantiationService: IInstantiationService): IEditorGroupView { - return instantiationService.createInstance(EditorGroupView, copyFrom, editorPartsView, groupsView, groupsLabel, groupIndex); + static createCopy(copyFrom: IEditorGroupView, editorPartsView: IEditorPartsView, groupsView: IEditorGroupsView, groupsLabel: string, groupIndex: number, instantiationService: IInstantiationService, preserveFocus?: boolean): IEditorGroupView { + return instantiationService.createInstance(EditorGroupView, copyFrom, editorPartsView, groupsView, groupsLabel, groupIndex, preserveFocus); } //#endregion @@ -145,6 +145,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { readonly groupsView: IEditorGroupsView, private groupsLabel: string, private _index: number, + private preserveFocus: boolean | undefined, @IInstantiationService private readonly instantiationService: IInstantiationService, @IContextKeyService private readonly contextKeyService: IContextKeyService, @IThemeService themeService: IThemeService, @@ -236,7 +237,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { //#endregion // Restore editors if provided - const restoreEditorsPromise = this.restoreEditors(from) ?? Promise.resolve(); + const restoreEditorsPromise = this.restoreEditors(from, preserveFocus) ?? Promise.resolve(); // Signal restored once editors have restored restoreEditorsPromise.finally(() => { @@ -534,7 +535,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { this.titleContainer.classList.toggle('show-file-icons', this.groupsView.partOptions.showIcons); } - private restoreEditors(from: IEditorGroupView | ISerializedEditorGroupModel | null): Promise | undefined { + private restoreEditors(from: IEditorGroupView | ISerializedEditorGroupModel | null, preserveFocus: boolean | undefined): Promise | undefined { if (this.count === 0) { return; // nothing to show } @@ -571,7 +572,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { // stolen accidentally on startup when the user already // clicked somewhere. - if (this.groupsView.activeGroup === this && activeElement && isActiveElement(activeElement)) { + if (this.groupsView.activeGroup === this && activeElement && isActiveElement(activeElement) && this.preserveFocus === false) { this.focus(); } }); diff --git a/src/vs/workbench/browser/parts/editor/editorPart.ts b/src/vs/workbench/browser/parts/editor/editorPart.ts index e467ab0270ea3..76b5a70f3c358 100644 --- a/src/vs/workbench/browser/parts/editor/editorPart.ts +++ b/src/vs/workbench/browser/parts/editor/editorPart.ts @@ -615,16 +615,16 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupsView { } } - private doCreateGroupView(from?: IEditorGroupView | ISerializedEditorGroupModel | null): IEditorGroupView { + private doCreateGroupView(from?: IEditorGroupView | ISerializedEditorGroupModel | null, preserveFocus?: boolean): IEditorGroupView { // Create group view let groupView: IEditorGroupView; if (from instanceof EditorGroupView) { - groupView = EditorGroupView.createCopy(from, this.editorPartsView, this, this.groupsLabel, this.count, this.scopedInstantiationService,); + groupView = EditorGroupView.createCopy(from, this.editorPartsView, this, this.groupsLabel, this.count, this.scopedInstantiationService, preserveFocus); } else if (isSerializedEditorGroupModel(from)) { - groupView = EditorGroupView.createFromSerialized(from, this.editorPartsView, this, this.groupsLabel, this.count, this.scopedInstantiationService); + groupView = EditorGroupView.createFromSerialized(from, this.editorPartsView, this, this.groupsLabel, this.count, this.scopedInstantiationService, preserveFocus); } else { - groupView = EditorGroupView.createNew(this.editorPartsView, this, this.groupsLabel, this.count, this.scopedInstantiationService); + groupView = EditorGroupView.createNew(this.editorPartsView, this, this.groupsLabel, this.count, this.scopedInstantiationService, preserveFocus); } // Keep in map @@ -1192,7 +1192,7 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupsView { return true; // success } - private doCreateGridControlWithState(serializedGrid: ISerializedGrid, activeGroupId: GroupIdentifier, editorGroupViewsToReuse?: IEditorGroupView[]): void { + private doCreateGridControlWithState(serializedGrid: ISerializedGrid, activeGroupId: GroupIdentifier, editorGroupViewsToReuse?: IEditorGroupView[], preserveFocus?: boolean): void { // Determine group views to reuse if any let reuseGroupViews: IEditorGroupView[]; @@ -1210,7 +1210,7 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupsView { if (reuseGroupViews.length > 0) { groupView = reuseGroupViews.shift()!; } else { - groupView = this.doCreateGroupView(serializedEditorGroup); + groupView = this.doCreateGroupView(serializedEditorGroup, preserveFocus); } groupViews.push(groupView); @@ -1342,15 +1342,15 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupsView { }; } - applyState(state: IEditorPartUIState | 'empty'): Promise { + applyState(state: IEditorPartUIState | 'empty', preserveFocus?: boolean): Promise { if (state === 'empty') { return this.doApplyEmptyState(); } else { - return this.doApplyState(state); + return this.doApplyState(state, preserveFocus); } } - private async doApplyState(state: IEditorPartUIState): Promise { + private async doApplyState(state: IEditorPartUIState, preserveFocus?: boolean): Promise { const groups = await this.doPrepareApplyState(); const resumeEvents = this.disposeGroups(true /* suspress events for the duration of applying state */); @@ -1359,7 +1359,7 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupsView { // Grid Widget try { - this.doApplyGridState(state.serializedGrid, state.activeGroup); + this.doApplyGridState(state.serializedGrid, state.activeGroup, undefined, preserveFocus); } finally { resumeEvents(); } @@ -1396,10 +1396,10 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupsView { return groups; } - private doApplyGridState(gridState: ISerializedGrid, activeGroupId: GroupIdentifier, editorGroupViewsToReuse?: IEditorGroupView[]): void { + private doApplyGridState(gridState: ISerializedGrid, activeGroupId: GroupIdentifier, editorGroupViewsToReuse?: IEditorGroupView[], preserveFocus?: boolean): void { // Recreate grid widget from state - this.doCreateGridControlWithState(gridState, activeGroupId, editorGroupViewsToReuse); + this.doCreateGridControlWithState(gridState, activeGroupId, editorGroupViewsToReuse, preserveFocus); // Layout this.doLayout(this._contentDimension); diff --git a/src/vs/workbench/browser/parts/editor/editorParts.ts b/src/vs/workbench/browser/parts/editor/editorParts.ts index 574c97e41539e..04c60657c8b40 100644 --- a/src/vs/workbench/browser/parts/editor/editorParts.ts +++ b/src/vs/workbench/browser/parts/editor/editorParts.ts @@ -21,6 +21,7 @@ import { IThemeService } from 'vs/platform/theme/common/themeService'; import { IAuxiliaryWindowOpenOptions, IAuxiliaryWindowService } from 'vs/workbench/services/auxiliaryWindow/browser/auxiliaryWindowService'; import { generateUuid } from 'vs/base/common/uuid'; import { ContextKeyValue, IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; +import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService'; interface IEditorPartsUIState { readonly auxiliary: IAuxiliaryEditorPartState[]; @@ -50,7 +51,8 @@ export class EditorParts extends MultiWindowParts implements IEditor @IStorageService private readonly storageService: IStorageService, @IThemeService themeService: IThemeService, @IAuxiliaryWindowService private readonly auxiliaryWindowService: IAuxiliaryWindowService, - @IContextKeyService private readonly contextKeyService: IContextKeyService + @IContextKeyService private readonly contextKeyService: IContextKeyService, + @IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService ) { super('workbench.editorParts', themeService, storageService); @@ -387,6 +389,12 @@ export class EditorParts extends MultiWindowParts implements IEditor return false; } + // Applying a working set can be the result of a user action that has been + // initiated from the terminal (ex: switching branches). As such, we want + // to preserve the focus in the terminal. This does not cover the scenario + // in which the terminal is in the editor part. + const preserveFocus = this.layoutService.hasFocus(Parts.PANEL_PART); + // Apply state: begin with auxiliary windows first because it helps to keep // editors around that need confirmation by moving them into the main part. // Also, in rare cases, the auxiliary part may not be able to apply the state @@ -395,13 +403,15 @@ export class EditorParts extends MultiWindowParts implements IEditor if (!applied) { return false; } - await this.mainPart.applyState(workingSetState === 'empty' ? workingSetState : workingSetState.main); + await this.mainPart.applyState(workingSetState === 'empty' ? workingSetState : workingSetState.main, preserveFocus); // Restore Focus - const mostRecentActivePart = firstOrDefault(this.mostRecentActiveParts); - if (mostRecentActivePart) { - await mostRecentActivePart.whenReady; - mostRecentActivePart.activeGroup.focus(); + if (!preserveFocus) { + const mostRecentActivePart = firstOrDefault(this.mostRecentActiveParts); + if (mostRecentActivePart) { + await mostRecentActivePart.whenReady; + mostRecentActivePart.activeGroup.focus(); + } } return true; From f99ec7b548aec025f84358d73a3e59bcabad3672 Mon Sep 17 00:00:00 2001 From: Ladislau Szomoru <3372902+lszomoru@users.noreply.github.com> Date: Fri, 24 May 2024 21:48:24 +0200 Subject: [PATCH 2/5] Pull request feedback --- .../browser/parts/editor/editorGroupView.ts | 22 ++++++++-------- .../browser/parts/editor/editorPart.ts | 26 +++++++++---------- .../browser/parts/editor/editorParts.ts | 18 ++++--------- .../contrib/scm/browser/workingSet.ts | 12 +++++++-- .../editor/common/editorGroupsService.ts | 6 ++++- .../test/browser/workbenchTestServices.ts | 6 ++--- 6 files changed, 47 insertions(+), 43 deletions(-) diff --git a/src/vs/workbench/browser/parts/editor/editorGroupView.ts b/src/vs/workbench/browser/parts/editor/editorGroupView.ts index 5ad410782a16f..9c6315805f692 100644 --- a/src/vs/workbench/browser/parts/editor/editorGroupView.ts +++ b/src/vs/workbench/browser/parts/editor/editorGroupView.ts @@ -18,7 +18,7 @@ import { ProgressBar } from 'vs/base/browser/ui/progressbar/progressbar'; import { IThemeService, Themable } from 'vs/platform/theme/common/themeService'; import { editorBackground, contrastBorder } from 'vs/platform/theme/common/colorRegistry'; import { EDITOR_GROUP_HEADER_TABS_BACKGROUND, EDITOR_GROUP_HEADER_NO_TABS_BACKGROUND, EDITOR_GROUP_EMPTY_BACKGROUND, EDITOR_GROUP_HEADER_BORDER } from 'vs/workbench/common/theme'; -import { ICloseEditorsFilter, GroupsOrder, ICloseEditorOptions, ICloseAllEditorsOptions, IEditorReplacement, IActiveEditorActions } from 'vs/workbench/services/editor/common/editorGroupsService'; +import { ICloseEditorsFilter, GroupsOrder, ICloseEditorOptions, ICloseAllEditorsOptions, IEditorReplacement, IActiveEditorActions, IEditorWorkingSetApplyOptions } from 'vs/workbench/services/editor/common/editorGroupsService'; import { EditorPanes } from 'vs/workbench/browser/parts/editor/editorPanes'; import { IEditorProgressService } from 'vs/platform/progress/common/progress'; import { EditorProgressIndicator } from 'vs/workbench/services/progress/browser/progressIndicator'; @@ -63,16 +63,16 @@ export class EditorGroupView extends Themable implements IEditorGroupView { //#region factory - static createNew(editorPartsView: IEditorPartsView, groupsView: IEditorGroupsView, groupsLabel: string, groupIndex: number, instantiationService: IInstantiationService, preserveFocus?: boolean): IEditorGroupView { - return instantiationService.createInstance(EditorGroupView, null, editorPartsView, groupsView, groupsLabel, groupIndex, preserveFocus); + static createNew(editorPartsView: IEditorPartsView, groupsView: IEditorGroupsView, groupsLabel: string, groupIndex: number, instantiationService: IInstantiationService, editorWorkingSetApplyOptions?: IEditorWorkingSetApplyOptions): IEditorGroupView { + return instantiationService.createInstance(EditorGroupView, null, editorPartsView, groupsView, groupsLabel, groupIndex, editorWorkingSetApplyOptions); } - static createFromSerialized(serialized: ISerializedEditorGroupModel, editorPartsView: IEditorPartsView, groupsView: IEditorGroupsView, groupsLabel: string, groupIndex: number, instantiationService: IInstantiationService, preserveFocus?: boolean): IEditorGroupView { - return instantiationService.createInstance(EditorGroupView, serialized, editorPartsView, groupsView, groupsLabel, groupIndex, preserveFocus); + static createFromSerialized(serialized: ISerializedEditorGroupModel, editorPartsView: IEditorPartsView, groupsView: IEditorGroupsView, groupsLabel: string, groupIndex: number, instantiationService: IInstantiationService, editorWorkingSetApplyOptions?: IEditorWorkingSetApplyOptions): IEditorGroupView { + return instantiationService.createInstance(EditorGroupView, serialized, editorPartsView, groupsView, groupsLabel, groupIndex, editorWorkingSetApplyOptions); } - static createCopy(copyFrom: IEditorGroupView, editorPartsView: IEditorPartsView, groupsView: IEditorGroupsView, groupsLabel: string, groupIndex: number, instantiationService: IInstantiationService, preserveFocus?: boolean): IEditorGroupView { - return instantiationService.createInstance(EditorGroupView, copyFrom, editorPartsView, groupsView, groupsLabel, groupIndex, preserveFocus); + static createCopy(copyFrom: IEditorGroupView, editorPartsView: IEditorPartsView, groupsView: IEditorGroupsView, groupsLabel: string, groupIndex: number, instantiationService: IInstantiationService, editorWorkingSetApplyOptions?: IEditorWorkingSetApplyOptions): IEditorGroupView { + return instantiationService.createInstance(EditorGroupView, copyFrom, editorPartsView, groupsView, groupsLabel, groupIndex, editorWorkingSetApplyOptions); } //#endregion @@ -145,7 +145,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { readonly groupsView: IEditorGroupsView, private groupsLabel: string, private _index: number, - private preserveFocus: boolean | undefined, + editorWorkingSetApplyOptions: IEditorWorkingSetApplyOptions | undefined, @IInstantiationService private readonly instantiationService: IInstantiationService, @IContextKeyService private readonly contextKeyService: IContextKeyService, @IThemeService themeService: IThemeService, @@ -237,7 +237,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { //#endregion // Restore editors if provided - const restoreEditorsPromise = this.restoreEditors(from, preserveFocus) ?? Promise.resolve(); + const restoreEditorsPromise = this.restoreEditors(from, editorWorkingSetApplyOptions) ?? Promise.resolve(); // Signal restored once editors have restored restoreEditorsPromise.finally(() => { @@ -535,7 +535,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { this.titleContainer.classList.toggle('show-file-icons', this.groupsView.partOptions.showIcons); } - private restoreEditors(from: IEditorGroupView | ISerializedEditorGroupModel | null, preserveFocus: boolean | undefined): Promise | undefined { + private restoreEditors(from: IEditorGroupView | ISerializedEditorGroupModel | null, editorWorkingSetApplyOptions?: IEditorWorkingSetApplyOptions): Promise | undefined { if (this.count === 0) { return; // nothing to show } @@ -572,7 +572,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { // stolen accidentally on startup when the user already // clicked somewhere. - if (this.groupsView.activeGroup === this && activeElement && isActiveElement(activeElement) && this.preserveFocus === false) { + if (this.groupsView.activeGroup === this && activeElement && isActiveElement(activeElement) && editorWorkingSetApplyOptions?.preserveFocus === false) { this.focus(); } }); diff --git a/src/vs/workbench/browser/parts/editor/editorPart.ts b/src/vs/workbench/browser/parts/editor/editorPart.ts index 76b5a70f3c358..749e1f5eee126 100644 --- a/src/vs/workbench/browser/parts/editor/editorPart.ts +++ b/src/vs/workbench/browser/parts/editor/editorPart.ts @@ -8,7 +8,7 @@ import { Part } from 'vs/workbench/browser/part'; import { Dimension, $, EventHelper, addDisposableGenericMouseDownListener, getWindow, isAncestorOfActiveElement, getActiveElement } from 'vs/base/browser/dom'; import { Event, Emitter, Relay, PauseableEmitter } from 'vs/base/common/event'; import { contrastBorder, editorBackground } from 'vs/platform/theme/common/colorRegistry'; -import { GroupDirection, GroupsArrangement, GroupOrientation, IMergeGroupOptions, MergeGroupMode, GroupsOrder, GroupLocation, IFindGroupScope, EditorGroupLayout, GroupLayoutArgument, IEditorSideGroup, IEditorDropTargetDelegate, IEditorPart } from 'vs/workbench/services/editor/common/editorGroupsService'; +import { GroupDirection, GroupsArrangement, GroupOrientation, IMergeGroupOptions, MergeGroupMode, GroupsOrder, GroupLocation, IFindGroupScope, EditorGroupLayout, GroupLayoutArgument, IEditorSideGroup, IEditorDropTargetDelegate, IEditorPart, IEditorWorkingSetApplyOptions } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IView, orthogonal, LayoutPriority, IViewSize, Direction, SerializableGrid, Sizing, ISerializedGrid, ISerializedNode, Orientation, GridBranchNode, isGridBranchNode, GridNode, createSerializedGrid, Grid } from 'vs/base/browser/ui/grid/grid'; import { GroupIdentifier, EditorInputWithOptions, IEditorPartOptions, IEditorPartOptionsChangeEvent, GroupModelChangeKind } from 'vs/workbench/common/editor'; @@ -615,16 +615,16 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupsView { } } - private doCreateGroupView(from?: IEditorGroupView | ISerializedEditorGroupModel | null, preserveFocus?: boolean): IEditorGroupView { + private doCreateGroupView(from?: IEditorGroupView | ISerializedEditorGroupModel | null, options?: IEditorWorkingSetApplyOptions): IEditorGroupView { // Create group view let groupView: IEditorGroupView; if (from instanceof EditorGroupView) { - groupView = EditorGroupView.createCopy(from, this.editorPartsView, this, this.groupsLabel, this.count, this.scopedInstantiationService, preserveFocus); + groupView = EditorGroupView.createCopy(from, this.editorPartsView, this, this.groupsLabel, this.count, this.scopedInstantiationService, options); } else if (isSerializedEditorGroupModel(from)) { - groupView = EditorGroupView.createFromSerialized(from, this.editorPartsView, this, this.groupsLabel, this.count, this.scopedInstantiationService, preserveFocus); + groupView = EditorGroupView.createFromSerialized(from, this.editorPartsView, this, this.groupsLabel, this.count, this.scopedInstantiationService, options); } else { - groupView = EditorGroupView.createNew(this.editorPartsView, this, this.groupsLabel, this.count, this.scopedInstantiationService, preserveFocus); + groupView = EditorGroupView.createNew(this.editorPartsView, this, this.groupsLabel, this.count, this.scopedInstantiationService, options); } // Keep in map @@ -1192,7 +1192,7 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupsView { return true; // success } - private doCreateGridControlWithState(serializedGrid: ISerializedGrid, activeGroupId: GroupIdentifier, editorGroupViewsToReuse?: IEditorGroupView[], preserveFocus?: boolean): void { + private doCreateGridControlWithState(serializedGrid: ISerializedGrid, activeGroupId: GroupIdentifier, editorGroupViewsToReuse?: IEditorGroupView[], options?: IEditorWorkingSetApplyOptions): void { // Determine group views to reuse if any let reuseGroupViews: IEditorGroupView[]; @@ -1210,7 +1210,7 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupsView { if (reuseGroupViews.length > 0) { groupView = reuseGroupViews.shift()!; } else { - groupView = this.doCreateGroupView(serializedEditorGroup, preserveFocus); + groupView = this.doCreateGroupView(serializedEditorGroup, options); } groupViews.push(groupView); @@ -1342,15 +1342,15 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupsView { }; } - applyState(state: IEditorPartUIState | 'empty', preserveFocus?: boolean): Promise { + applyState(state: IEditorPartUIState | 'empty', options?: IEditorWorkingSetApplyOptions): Promise { if (state === 'empty') { return this.doApplyEmptyState(); } else { - return this.doApplyState(state, preserveFocus); + return this.doApplyState(state, options); } } - private async doApplyState(state: IEditorPartUIState, preserveFocus?: boolean): Promise { + private async doApplyState(state: IEditorPartUIState, options?: IEditorWorkingSetApplyOptions): Promise { const groups = await this.doPrepareApplyState(); const resumeEvents = this.disposeGroups(true /* suspress events for the duration of applying state */); @@ -1359,7 +1359,7 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupsView { // Grid Widget try { - this.doApplyGridState(state.serializedGrid, state.activeGroup, undefined, preserveFocus); + this.doApplyGridState(state.serializedGrid, state.activeGroup, undefined, options); } finally { resumeEvents(); } @@ -1396,10 +1396,10 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupsView { return groups; } - private doApplyGridState(gridState: ISerializedGrid, activeGroupId: GroupIdentifier, editorGroupViewsToReuse?: IEditorGroupView[], preserveFocus?: boolean): void { + private doApplyGridState(gridState: ISerializedGrid, activeGroupId: GroupIdentifier, editorGroupViewsToReuse?: IEditorGroupView[], options?: IEditorWorkingSetApplyOptions): void { // Recreate grid widget from state - this.doCreateGridControlWithState(gridState, activeGroupId, editorGroupViewsToReuse, preserveFocus); + this.doCreateGridControlWithState(gridState, activeGroupId, editorGroupViewsToReuse, options); // Layout this.doLayout(this._contentDimension); diff --git a/src/vs/workbench/browser/parts/editor/editorParts.ts b/src/vs/workbench/browser/parts/editor/editorParts.ts index 04c60657c8b40..624b83fc19687 100644 --- a/src/vs/workbench/browser/parts/editor/editorParts.ts +++ b/src/vs/workbench/browser/parts/editor/editorParts.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { localize } from 'vs/nls'; -import { EditorGroupLayout, GroupDirection, GroupLocation, GroupOrientation, GroupsArrangement, GroupsOrder, IAuxiliaryEditorPart, IAuxiliaryEditorPartCreateEvent, IEditorGroupContextKeyProvider, IEditorDropTargetDelegate, IEditorGroupsService, IEditorSideGroup, IEditorWorkingSet, IFindGroupScope, IMergeGroupOptions } from 'vs/workbench/services/editor/common/editorGroupsService'; +import { EditorGroupLayout, GroupDirection, GroupLocation, GroupOrientation, GroupsArrangement, GroupsOrder, IAuxiliaryEditorPart, IAuxiliaryEditorPartCreateEvent, IEditorGroupContextKeyProvider, IEditorDropTargetDelegate, IEditorGroupsService, IEditorSideGroup, IEditorWorkingSet, IFindGroupScope, IMergeGroupOptions, IEditorWorkingSetApplyOptions } from 'vs/workbench/services/editor/common/editorGroupsService'; import { Emitter } from 'vs/base/common/event'; import { DisposableMap, DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { GroupIdentifier } from 'vs/workbench/common/editor'; @@ -21,7 +21,6 @@ import { IThemeService } from 'vs/platform/theme/common/themeService'; import { IAuxiliaryWindowOpenOptions, IAuxiliaryWindowService } from 'vs/workbench/services/auxiliaryWindow/browser/auxiliaryWindowService'; import { generateUuid } from 'vs/base/common/uuid'; import { ContextKeyValue, IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; -import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService'; interface IEditorPartsUIState { readonly auxiliary: IAuxiliaryEditorPartState[]; @@ -51,8 +50,7 @@ export class EditorParts extends MultiWindowParts implements IEditor @IStorageService private readonly storageService: IStorageService, @IThemeService themeService: IThemeService, @IAuxiliaryWindowService private readonly auxiliaryWindowService: IAuxiliaryWindowService, - @IContextKeyService private readonly contextKeyService: IContextKeyService, - @IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService + @IContextKeyService private readonly contextKeyService: IContextKeyService ) { super('workbench.editorParts', themeService, storageService); @@ -377,7 +375,7 @@ export class EditorParts extends MultiWindowParts implements IEditor } } - async applyWorkingSet(workingSet: IEditorWorkingSet | 'empty'): Promise { + async applyWorkingSet(workingSet: IEditorWorkingSet | 'empty', options?: IEditorWorkingSetApplyOptions): Promise { let workingSetState: IEditorWorkingSetState | 'empty' | undefined; if (workingSet === 'empty') { workingSetState = 'empty'; @@ -389,12 +387,6 @@ export class EditorParts extends MultiWindowParts implements IEditor return false; } - // Applying a working set can be the result of a user action that has been - // initiated from the terminal (ex: switching branches). As such, we want - // to preserve the focus in the terminal. This does not cover the scenario - // in which the terminal is in the editor part. - const preserveFocus = this.layoutService.hasFocus(Parts.PANEL_PART); - // Apply state: begin with auxiliary windows first because it helps to keep // editors around that need confirmation by moving them into the main part. // Also, in rare cases, the auxiliary part may not be able to apply the state @@ -403,10 +395,10 @@ export class EditorParts extends MultiWindowParts implements IEditor if (!applied) { return false; } - await this.mainPart.applyState(workingSetState === 'empty' ? workingSetState : workingSetState.main, preserveFocus); + await this.mainPart.applyState(workingSetState === 'empty' ? workingSetState : workingSetState.main, options); // Restore Focus - if (!preserveFocus) { + if (options?.preserveFocus === false) { const mostRecentActivePart = firstOrDefault(this.mostRecentActiveParts); if (mostRecentActivePart) { await mostRecentActivePart.whenReady; diff --git a/src/vs/workbench/contrib/scm/browser/workingSet.ts b/src/vs/workbench/contrib/scm/browser/workingSet.ts index 498b667390e3b..3a023470ea207 100644 --- a/src/vs/workbench/contrib/scm/browser/workingSet.ts +++ b/src/vs/workbench/contrib/scm/browser/workingSet.ts @@ -11,6 +11,7 @@ import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { getProviderKey } from 'vs/workbench/contrib/scm/browser/util'; import { ISCMRepository, ISCMService } from 'vs/workbench/contrib/scm/common/scm'; import { IEditorGroupsService, IEditorWorkingSet } from 'vs/workbench/services/editor/common/editorGroupsService'; +import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService'; type ISCMSerializedWorkingSet = { readonly providerKey: string; @@ -35,7 +36,8 @@ export class SCMWorkingSetController implements IWorkbenchContribution { @IConfigurationService private readonly configurationService: IConfigurationService, @IEditorGroupsService private readonly editorGroupsService: IEditorGroupsService, @ISCMService private readonly scmService: ISCMService, - @IStorageService private readonly storageService: IStorageService + @IStorageService private readonly storageService: IStorageService, + @IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService ) { const onDidChangeConfiguration = Event.filter(configurationService.onDidChangeConfiguration, e => e.affectsConfiguration('scm.workingSets.enabled'), this._disposables); this._disposables.add(Event.runAndSubscribe(onDidChangeConfiguration, () => this._onDidChangeConfiguration())); @@ -147,7 +149,13 @@ export class SCMWorkingSetController implements IWorkbenchContribution { } if (editorWorkingSetId) { - await this.editorGroupsService.applyWorkingSet(editorWorkingSetId); + // Applying a working set can be the result of a user action that has been + // initiated from the terminal (ex: switching branches). As such, we want + // to preserve the focus in the terminal. This does not cover the scenario + // in which the terminal is in the editor part. + const preserveFocus = this.layoutService.hasFocus(Parts.PANEL_PART); + + await this.editorGroupsService.applyWorkingSet(editorWorkingSetId, { preserveFocus }); } } diff --git a/src/vs/workbench/services/editor/common/editorGroupsService.ts b/src/vs/workbench/services/editor/common/editorGroupsService.ts index 6a7acef2ae618..8d974a4217643 100644 --- a/src/vs/workbench/services/editor/common/editorGroupsService.ts +++ b/src/vs/workbench/services/editor/common/editorGroupsService.ts @@ -491,6 +491,10 @@ export interface IEditorWorkingSet { readonly name: string; } +export interface IEditorWorkingSetApplyOptions { + readonly preserveFocus?: boolean; +} + export interface IEditorGroupContextKeyProvider { /** @@ -573,7 +577,7 @@ export interface IEditorGroupsService extends IEditorGroupsContainer { * * @returns `true` when the working set as applied. */ - applyWorkingSet(workingSet: IEditorWorkingSet | 'empty'): Promise; + applyWorkingSet(workingSet: IEditorWorkingSet | 'empty', options?: IEditorWorkingSetApplyOptions): Promise; /** * Deletes a working set. diff --git a/src/vs/workbench/test/browser/workbenchTestServices.ts b/src/vs/workbench/test/browser/workbenchTestServices.ts index cf3df1f56ce65..017acbdbef550 100644 --- a/src/vs/workbench/test/browser/workbenchTestServices.ts +++ b/src/vs/workbench/test/browser/workbenchTestServices.ts @@ -52,7 +52,7 @@ import { IExtensionService } from 'vs/workbench/services/extensions/common/exten import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IDecorationsService, IResourceDecorationChangeEvent, IDecoration, IDecorationData, IDecorationsProvider } from 'vs/workbench/services/decorations/common/decorations'; import { IDisposable, toDisposable, Disposable, DisposableStore } from 'vs/base/common/lifecycle'; -import { IEditorGroupsService, IEditorGroup, GroupsOrder, GroupsArrangement, GroupDirection, IMergeGroupOptions, IEditorReplacement, IFindGroupScope, EditorGroupLayout, ICloseEditorOptions, GroupOrientation, ICloseAllEditorsOptions, ICloseEditorsFilter, IEditorDropTargetDelegate, IEditorPart, IAuxiliaryEditorPart, IEditorGroupsContainer, IAuxiliaryEditorPartCreateEvent, IEditorWorkingSet, IEditorGroupContextKeyProvider } from 'vs/workbench/services/editor/common/editorGroupsService'; +import { IEditorGroupsService, IEditorGroup, GroupsOrder, GroupsArrangement, GroupDirection, IMergeGroupOptions, IEditorReplacement, IFindGroupScope, EditorGroupLayout, ICloseEditorOptions, GroupOrientation, ICloseAllEditorsOptions, ICloseEditorsFilter, IEditorDropTargetDelegate, IEditorPart, IAuxiliaryEditorPart, IEditorGroupsContainer, IAuxiliaryEditorPartCreateEvent, IEditorWorkingSet, IEditorGroupContextKeyProvider, IEditorWorkingSetApplyOptions } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IEditorService, ISaveEditorsOptions, IRevertAllEditorsOptions, PreferredGroup, IEditorsChangeEvent, ISaveEditorsResult } from 'vs/workbench/services/editor/common/editorService'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { IEditorPaneRegistry, EditorPaneDescriptor } from 'vs/workbench/browser/editor'; @@ -841,7 +841,7 @@ export class TestEditorGroupsService implements IEditorGroupsService { getPart(group: number | IEditorGroup): IEditorPart { return this; } saveWorkingSet(name: string): IEditorWorkingSet { throw new Error('Method not implemented.'); } getWorkingSets(): IEditorWorkingSet[] { throw new Error('Method not implemented.'); } - applyWorkingSet(workingSet: IEditorWorkingSet | 'empty'): Promise { throw new Error('Method not implemented.'); } + applyWorkingSet(workingSet: IEditorWorkingSet | 'empty', options?: IEditorWorkingSetApplyOptions): Promise { throw new Error('Method not implemented.'); } deleteWorkingSet(workingSet: IEditorWorkingSet): Promise { throw new Error('Method not implemented.'); } getGroups(_order?: GroupsOrder): readonly IEditorGroup[] { return this.groups; } getGroup(identifier: number): IEditorGroup | undefined { return this.groups.find(group => group.id === identifier); } @@ -1841,7 +1841,7 @@ export class TestEditorPart extends MainEditorPart implements IEditorGroupsServi saveWorkingSet(name: string): IEditorWorkingSet { throw new Error('Method not implemented.'); } getWorkingSets(): IEditorWorkingSet[] { throw new Error('Method not implemented.'); } - applyWorkingSet(workingSet: IEditorWorkingSet | 'empty'): Promise { throw new Error('Method not implemented.'); } + applyWorkingSet(workingSet: IEditorWorkingSet | 'empty', options?: IEditorWorkingSetApplyOptions): Promise { throw new Error('Method not implemented.'); } deleteWorkingSet(workingSet: IEditorWorkingSet): Promise { throw new Error('Method not implemented.'); } registerContextKeyProvider(provider: IEditorGroupContextKeyProvider): IDisposable { throw new Error('Method not implemented.'); } From 0921e9462c45d291aeb3e4d869c7f84cf6fee3c7 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Sat, 25 May 2024 10:04:04 +0200 Subject: [PATCH 3/5] renames and cleanup --- .../workbench/browser/parts/editor/editor.ts | 9 +++++++++ .../browser/parts/editor/editorGroupView.ts | 18 +++++++++--------- .../browser/parts/editor/editorPart.ts | 14 +++++++------- .../browser/parts/editor/editorParts.ts | 4 ++-- 4 files changed, 27 insertions(+), 18 deletions(-) diff --git a/src/vs/workbench/browser/parts/editor/editor.ts b/src/vs/workbench/browser/parts/editor/editor.ts index 138541a6ecfb7..066385368f863 100644 --- a/src/vs/workbench/browser/parts/editor/editor.ts +++ b/src/vs/workbench/browser/parts/editor/editor.ts @@ -242,6 +242,15 @@ export interface IEditorGroupTitleHeight { readonly offset: number; } +export interface IEditorGroupViewOptions { + + /** + * Whether the editor group should receive keyboard focus + * after creation or not. + */ + readonly preserveFocus?: boolean; +} + /** * A helper to access and mutate an editor group within an editor part. */ diff --git a/src/vs/workbench/browser/parts/editor/editorGroupView.ts b/src/vs/workbench/browser/parts/editor/editorGroupView.ts index 9c6315805f692..29c35254a4b88 100644 --- a/src/vs/workbench/browser/parts/editor/editorGroupView.ts +++ b/src/vs/workbench/browser/parts/editor/editorGroupView.ts @@ -28,7 +28,7 @@ import { DisposableStore, MutableDisposable, toDisposable } from 'vs/base/common import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { DeferredPromise, Promises, RunOnceWorker } from 'vs/base/common/async'; import { EventType as TouchEventType, GestureEvent } from 'vs/base/browser/touch'; -import { IEditorGroupsView, IEditorGroupView, fillActiveEditorViewState, EditorServiceImpl, IEditorGroupTitleHeight, IInternalEditorOpenOptions, IInternalMoveCopyOptions, IInternalEditorCloseOptions, IInternalEditorTitleControlOptions, IEditorPartsView } from 'vs/workbench/browser/parts/editor/editor'; +import { IEditorGroupsView, IEditorGroupView, fillActiveEditorViewState, EditorServiceImpl, IEditorGroupTitleHeight, IInternalEditorOpenOptions, IInternalMoveCopyOptions, IInternalEditorCloseOptions, IInternalEditorTitleControlOptions, IEditorPartsView, IEditorGroupViewOptions } from 'vs/workbench/browser/parts/editor/editor'; import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IAction, SubmenuAction } from 'vs/base/common/actions'; @@ -63,16 +63,16 @@ export class EditorGroupView extends Themable implements IEditorGroupView { //#region factory - static createNew(editorPartsView: IEditorPartsView, groupsView: IEditorGroupsView, groupsLabel: string, groupIndex: number, instantiationService: IInstantiationService, editorWorkingSetApplyOptions?: IEditorWorkingSetApplyOptions): IEditorGroupView { - return instantiationService.createInstance(EditorGroupView, null, editorPartsView, groupsView, groupsLabel, groupIndex, editorWorkingSetApplyOptions); + static createNew(editorPartsView: IEditorPartsView, groupsView: IEditorGroupsView, groupsLabel: string, groupIndex: number, instantiationService: IInstantiationService, options?: IEditorGroupViewOptions): IEditorGroupView { + return instantiationService.createInstance(EditorGroupView, null, editorPartsView, groupsView, groupsLabel, groupIndex, options); } - static createFromSerialized(serialized: ISerializedEditorGroupModel, editorPartsView: IEditorPartsView, groupsView: IEditorGroupsView, groupsLabel: string, groupIndex: number, instantiationService: IInstantiationService, editorWorkingSetApplyOptions?: IEditorWorkingSetApplyOptions): IEditorGroupView { - return instantiationService.createInstance(EditorGroupView, serialized, editorPartsView, groupsView, groupsLabel, groupIndex, editorWorkingSetApplyOptions); + static createFromSerialized(serialized: ISerializedEditorGroupModel, editorPartsView: IEditorPartsView, groupsView: IEditorGroupsView, groupsLabel: string, groupIndex: number, instantiationService: IInstantiationService, options?: IEditorGroupViewOptions): IEditorGroupView { + return instantiationService.createInstance(EditorGroupView, serialized, editorPartsView, groupsView, groupsLabel, groupIndex, options); } - static createCopy(copyFrom: IEditorGroupView, editorPartsView: IEditorPartsView, groupsView: IEditorGroupsView, groupsLabel: string, groupIndex: number, instantiationService: IInstantiationService, editorWorkingSetApplyOptions?: IEditorWorkingSetApplyOptions): IEditorGroupView { - return instantiationService.createInstance(EditorGroupView, copyFrom, editorPartsView, groupsView, groupsLabel, groupIndex, editorWorkingSetApplyOptions); + static createCopy(copyFrom: IEditorGroupView, editorPartsView: IEditorPartsView, groupsView: IEditorGroupsView, groupsLabel: string, groupIndex: number, instantiationService: IInstantiationService, options?: IEditorGroupViewOptions): IEditorGroupView { + return instantiationService.createInstance(EditorGroupView, copyFrom, editorPartsView, groupsView, groupsLabel, groupIndex, options); } //#endregion @@ -535,7 +535,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { this.titleContainer.classList.toggle('show-file-icons', this.groupsView.partOptions.showIcons); } - private restoreEditors(from: IEditorGroupView | ISerializedEditorGroupModel | null, editorWorkingSetApplyOptions?: IEditorWorkingSetApplyOptions): Promise | undefined { + private restoreEditors(from: IEditorGroupView | ISerializedEditorGroupModel | null, groupViewOptions?: IEditorGroupViewOptions): Promise | undefined { if (this.count === 0) { return; // nothing to show } @@ -572,7 +572,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { // stolen accidentally on startup when the user already // clicked somewhere. - if (this.groupsView.activeGroup === this && activeElement && isActiveElement(activeElement) && editorWorkingSetApplyOptions?.preserveFocus === false) { + if (this.groupsView.activeGroup === this && activeElement && isActiveElement(activeElement) && !groupViewOptions?.preserveFocus) { this.focus(); } }); diff --git a/src/vs/workbench/browser/parts/editor/editorPart.ts b/src/vs/workbench/browser/parts/editor/editorPart.ts index 749e1f5eee126..6d2df54a86672 100644 --- a/src/vs/workbench/browser/parts/editor/editorPart.ts +++ b/src/vs/workbench/browser/parts/editor/editorPart.ts @@ -8,13 +8,13 @@ import { Part } from 'vs/workbench/browser/part'; import { Dimension, $, EventHelper, addDisposableGenericMouseDownListener, getWindow, isAncestorOfActiveElement, getActiveElement } from 'vs/base/browser/dom'; import { Event, Emitter, Relay, PauseableEmitter } from 'vs/base/common/event'; import { contrastBorder, editorBackground } from 'vs/platform/theme/common/colorRegistry'; -import { GroupDirection, GroupsArrangement, GroupOrientation, IMergeGroupOptions, MergeGroupMode, GroupsOrder, GroupLocation, IFindGroupScope, EditorGroupLayout, GroupLayoutArgument, IEditorSideGroup, IEditorDropTargetDelegate, IEditorPart, IEditorWorkingSetApplyOptions } from 'vs/workbench/services/editor/common/editorGroupsService'; +import { GroupDirection, GroupsArrangement, GroupOrientation, IMergeGroupOptions, MergeGroupMode, GroupsOrder, GroupLocation, IFindGroupScope, EditorGroupLayout, GroupLayoutArgument, IEditorSideGroup, IEditorDropTargetDelegate, IEditorPart } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IView, orthogonal, LayoutPriority, IViewSize, Direction, SerializableGrid, Sizing, ISerializedGrid, ISerializedNode, Orientation, GridBranchNode, isGridBranchNode, GridNode, createSerializedGrid, Grid } from 'vs/base/browser/ui/grid/grid'; import { GroupIdentifier, EditorInputWithOptions, IEditorPartOptions, IEditorPartOptionsChangeEvent, GroupModelChangeKind } from 'vs/workbench/common/editor'; import { EDITOR_GROUP_BORDER, EDITOR_PANE_BACKGROUND } from 'vs/workbench/common/theme'; import { distinct, coalesce } from 'vs/base/common/arrays'; -import { IEditorGroupView, getEditorPartOptions, impactsEditorPartOptions, IEditorPartCreationOptions, IEditorPartsView, IEditorGroupsView } from 'vs/workbench/browser/parts/editor/editor'; +import { IEditorGroupView, getEditorPartOptions, impactsEditorPartOptions, IEditorPartCreationOptions, IEditorPartsView, IEditorGroupsView, IEditorGroupViewOptions } from 'vs/workbench/browser/parts/editor/editor'; import { EditorGroupView } from 'vs/workbench/browser/parts/editor/editorGroupView'; import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration'; import { IDisposable, dispose, toDisposable, DisposableStore } from 'vs/base/common/lifecycle'; @@ -615,7 +615,7 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupsView { } } - private doCreateGroupView(from?: IEditorGroupView | ISerializedEditorGroupModel | null, options?: IEditorWorkingSetApplyOptions): IEditorGroupView { + private doCreateGroupView(from?: IEditorGroupView | ISerializedEditorGroupModel | null, options?: IEditorGroupViewOptions): IEditorGroupView { // Create group view let groupView: IEditorGroupView; @@ -1192,7 +1192,7 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupsView { return true; // success } - private doCreateGridControlWithState(serializedGrid: ISerializedGrid, activeGroupId: GroupIdentifier, editorGroupViewsToReuse?: IEditorGroupView[], options?: IEditorWorkingSetApplyOptions): void { + private doCreateGridControlWithState(serializedGrid: ISerializedGrid, activeGroupId: GroupIdentifier, editorGroupViewsToReuse?: IEditorGroupView[], options?: IEditorGroupViewOptions): void { // Determine group views to reuse if any let reuseGroupViews: IEditorGroupView[]; @@ -1342,7 +1342,7 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupsView { }; } - applyState(state: IEditorPartUIState | 'empty', options?: IEditorWorkingSetApplyOptions): Promise { + applyState(state: IEditorPartUIState | 'empty', options?: IEditorGroupViewOptions): Promise { if (state === 'empty') { return this.doApplyEmptyState(); } else { @@ -1350,7 +1350,7 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupsView { } } - private async doApplyState(state: IEditorPartUIState, options?: IEditorWorkingSetApplyOptions): Promise { + private async doApplyState(state: IEditorPartUIState, options?: IEditorGroupViewOptions): Promise { const groups = await this.doPrepareApplyState(); const resumeEvents = this.disposeGroups(true /* suspress events for the duration of applying state */); @@ -1396,7 +1396,7 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupsView { return groups; } - private doApplyGridState(gridState: ISerializedGrid, activeGroupId: GroupIdentifier, editorGroupViewsToReuse?: IEditorGroupView[], options?: IEditorWorkingSetApplyOptions): void { + private doApplyGridState(gridState: ISerializedGrid, activeGroupId: GroupIdentifier, editorGroupViewsToReuse?: IEditorGroupView[], options?: IEditorGroupViewOptions): void { // Recreate grid widget from state this.doCreateGridControlWithState(gridState, activeGroupId, editorGroupViewsToReuse, options); diff --git a/src/vs/workbench/browser/parts/editor/editorParts.ts b/src/vs/workbench/browser/parts/editor/editorParts.ts index 624b83fc19687..7eee0ae8917d5 100644 --- a/src/vs/workbench/browser/parts/editor/editorParts.ts +++ b/src/vs/workbench/browser/parts/editor/editorParts.ts @@ -397,8 +397,8 @@ export class EditorParts extends MultiWindowParts implements IEditor } await this.mainPart.applyState(workingSetState === 'empty' ? workingSetState : workingSetState.main, options); - // Restore Focus - if (options?.preserveFocus === false) { + // Restore Focus unless instructed otherwise + if (!options?.preserveFocus) { const mostRecentActivePart = firstOrDefault(this.mostRecentActiveParts); if (mostRecentActivePart) { await mostRecentActivePart.whenReady; From c9eb899f4254601fd6b0eacee5dcafb9fca6b351 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Sat, 25 May 2024 10:04:48 +0200 Subject: [PATCH 4/5] renames and cleanup --- src/vs/workbench/browser/parts/editor/editorGroupView.ts | 4 ++-- src/vs/workbench/browser/parts/editor/editorParts.ts | 4 ++-- .../workbench/services/editor/common/editorGroupsService.ts | 4 ++-- src/vs/workbench/test/browser/workbenchTestServices.ts | 6 +++--- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/vs/workbench/browser/parts/editor/editorGroupView.ts b/src/vs/workbench/browser/parts/editor/editorGroupView.ts index 29c35254a4b88..399f5d8e50cca 100644 --- a/src/vs/workbench/browser/parts/editor/editorGroupView.ts +++ b/src/vs/workbench/browser/parts/editor/editorGroupView.ts @@ -18,7 +18,7 @@ import { ProgressBar } from 'vs/base/browser/ui/progressbar/progressbar'; import { IThemeService, Themable } from 'vs/platform/theme/common/themeService'; import { editorBackground, contrastBorder } from 'vs/platform/theme/common/colorRegistry'; import { EDITOR_GROUP_HEADER_TABS_BACKGROUND, EDITOR_GROUP_HEADER_NO_TABS_BACKGROUND, EDITOR_GROUP_EMPTY_BACKGROUND, EDITOR_GROUP_HEADER_BORDER } from 'vs/workbench/common/theme'; -import { ICloseEditorsFilter, GroupsOrder, ICloseEditorOptions, ICloseAllEditorsOptions, IEditorReplacement, IActiveEditorActions, IEditorWorkingSetApplyOptions } from 'vs/workbench/services/editor/common/editorGroupsService'; +import { ICloseEditorsFilter, GroupsOrder, ICloseEditorOptions, ICloseAllEditorsOptions, IEditorReplacement, IActiveEditorActions, IEditorWorkingSetOptions } from 'vs/workbench/services/editor/common/editorGroupsService'; import { EditorPanes } from 'vs/workbench/browser/parts/editor/editorPanes'; import { IEditorProgressService } from 'vs/platform/progress/common/progress'; import { EditorProgressIndicator } from 'vs/workbench/services/progress/browser/progressIndicator'; @@ -145,7 +145,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { readonly groupsView: IEditorGroupsView, private groupsLabel: string, private _index: number, - editorWorkingSetApplyOptions: IEditorWorkingSetApplyOptions | undefined, + editorWorkingSetApplyOptions: IEditorWorkingSetOptions | undefined, @IInstantiationService private readonly instantiationService: IInstantiationService, @IContextKeyService private readonly contextKeyService: IContextKeyService, @IThemeService themeService: IThemeService, diff --git a/src/vs/workbench/browser/parts/editor/editorParts.ts b/src/vs/workbench/browser/parts/editor/editorParts.ts index 7eee0ae8917d5..564464012e0d2 100644 --- a/src/vs/workbench/browser/parts/editor/editorParts.ts +++ b/src/vs/workbench/browser/parts/editor/editorParts.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { localize } from 'vs/nls'; -import { EditorGroupLayout, GroupDirection, GroupLocation, GroupOrientation, GroupsArrangement, GroupsOrder, IAuxiliaryEditorPart, IAuxiliaryEditorPartCreateEvent, IEditorGroupContextKeyProvider, IEditorDropTargetDelegate, IEditorGroupsService, IEditorSideGroup, IEditorWorkingSet, IFindGroupScope, IMergeGroupOptions, IEditorWorkingSetApplyOptions } from 'vs/workbench/services/editor/common/editorGroupsService'; +import { EditorGroupLayout, GroupDirection, GroupLocation, GroupOrientation, GroupsArrangement, GroupsOrder, IAuxiliaryEditorPart, IAuxiliaryEditorPartCreateEvent, IEditorGroupContextKeyProvider, IEditorDropTargetDelegate, IEditorGroupsService, IEditorSideGroup, IEditorWorkingSet, IFindGroupScope, IMergeGroupOptions, IEditorWorkingSetOptions } from 'vs/workbench/services/editor/common/editorGroupsService'; import { Emitter } from 'vs/base/common/event'; import { DisposableMap, DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { GroupIdentifier } from 'vs/workbench/common/editor'; @@ -375,7 +375,7 @@ export class EditorParts extends MultiWindowParts implements IEditor } } - async applyWorkingSet(workingSet: IEditorWorkingSet | 'empty', options?: IEditorWorkingSetApplyOptions): Promise { + async applyWorkingSet(workingSet: IEditorWorkingSet | 'empty', options?: IEditorWorkingSetOptions): Promise { let workingSetState: IEditorWorkingSetState | 'empty' | undefined; if (workingSet === 'empty') { workingSetState = 'empty'; diff --git a/src/vs/workbench/services/editor/common/editorGroupsService.ts b/src/vs/workbench/services/editor/common/editorGroupsService.ts index 8d974a4217643..b90d84720f01c 100644 --- a/src/vs/workbench/services/editor/common/editorGroupsService.ts +++ b/src/vs/workbench/services/editor/common/editorGroupsService.ts @@ -491,7 +491,7 @@ export interface IEditorWorkingSet { readonly name: string; } -export interface IEditorWorkingSetApplyOptions { +export interface IEditorWorkingSetOptions { readonly preserveFocus?: boolean; } @@ -577,7 +577,7 @@ export interface IEditorGroupsService extends IEditorGroupsContainer { * * @returns `true` when the working set as applied. */ - applyWorkingSet(workingSet: IEditorWorkingSet | 'empty', options?: IEditorWorkingSetApplyOptions): Promise; + applyWorkingSet(workingSet: IEditorWorkingSet | 'empty', options?: IEditorWorkingSetOptions): Promise; /** * Deletes a working set. diff --git a/src/vs/workbench/test/browser/workbenchTestServices.ts b/src/vs/workbench/test/browser/workbenchTestServices.ts index 017acbdbef550..e7c8dbf262aff 100644 --- a/src/vs/workbench/test/browser/workbenchTestServices.ts +++ b/src/vs/workbench/test/browser/workbenchTestServices.ts @@ -52,7 +52,7 @@ import { IExtensionService } from 'vs/workbench/services/extensions/common/exten import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IDecorationsService, IResourceDecorationChangeEvent, IDecoration, IDecorationData, IDecorationsProvider } from 'vs/workbench/services/decorations/common/decorations'; import { IDisposable, toDisposable, Disposable, DisposableStore } from 'vs/base/common/lifecycle'; -import { IEditorGroupsService, IEditorGroup, GroupsOrder, GroupsArrangement, GroupDirection, IMergeGroupOptions, IEditorReplacement, IFindGroupScope, EditorGroupLayout, ICloseEditorOptions, GroupOrientation, ICloseAllEditorsOptions, ICloseEditorsFilter, IEditorDropTargetDelegate, IEditorPart, IAuxiliaryEditorPart, IEditorGroupsContainer, IAuxiliaryEditorPartCreateEvent, IEditorWorkingSet, IEditorGroupContextKeyProvider, IEditorWorkingSetApplyOptions } from 'vs/workbench/services/editor/common/editorGroupsService'; +import { IEditorGroupsService, IEditorGroup, GroupsOrder, GroupsArrangement, GroupDirection, IMergeGroupOptions, IEditorReplacement, IFindGroupScope, EditorGroupLayout, ICloseEditorOptions, GroupOrientation, ICloseAllEditorsOptions, ICloseEditorsFilter, IEditorDropTargetDelegate, IEditorPart, IAuxiliaryEditorPart, IEditorGroupsContainer, IAuxiliaryEditorPartCreateEvent, IEditorWorkingSet, IEditorGroupContextKeyProvider, IEditorWorkingSetOptions } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IEditorService, ISaveEditorsOptions, IRevertAllEditorsOptions, PreferredGroup, IEditorsChangeEvent, ISaveEditorsResult } from 'vs/workbench/services/editor/common/editorService'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { IEditorPaneRegistry, EditorPaneDescriptor } from 'vs/workbench/browser/editor'; @@ -841,7 +841,7 @@ export class TestEditorGroupsService implements IEditorGroupsService { getPart(group: number | IEditorGroup): IEditorPart { return this; } saveWorkingSet(name: string): IEditorWorkingSet { throw new Error('Method not implemented.'); } getWorkingSets(): IEditorWorkingSet[] { throw new Error('Method not implemented.'); } - applyWorkingSet(workingSet: IEditorWorkingSet | 'empty', options?: IEditorWorkingSetApplyOptions): Promise { throw new Error('Method not implemented.'); } + applyWorkingSet(workingSet: IEditorWorkingSet | 'empty', options?: IEditorWorkingSetOptions): Promise { throw new Error('Method not implemented.'); } deleteWorkingSet(workingSet: IEditorWorkingSet): Promise { throw new Error('Method not implemented.'); } getGroups(_order?: GroupsOrder): readonly IEditorGroup[] { return this.groups; } getGroup(identifier: number): IEditorGroup | undefined { return this.groups.find(group => group.id === identifier); } @@ -1841,7 +1841,7 @@ export class TestEditorPart extends MainEditorPart implements IEditorGroupsServi saveWorkingSet(name: string): IEditorWorkingSet { throw new Error('Method not implemented.'); } getWorkingSets(): IEditorWorkingSet[] { throw new Error('Method not implemented.'); } - applyWorkingSet(workingSet: IEditorWorkingSet | 'empty', options?: IEditorWorkingSetApplyOptions): Promise { throw new Error('Method not implemented.'); } + applyWorkingSet(workingSet: IEditorWorkingSet | 'empty', options?: IEditorWorkingSetOptions): Promise { throw new Error('Method not implemented.'); } deleteWorkingSet(workingSet: IEditorWorkingSet): Promise { throw new Error('Method not implemented.'); } registerContextKeyProvider(provider: IEditorGroupContextKeyProvider): IDisposable { throw new Error('Method not implemented.'); } From abfc91513c49e4a283ec7c07a6f04b6d51320a6d Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Sat, 25 May 2024 10:07:01 +0200 Subject: [PATCH 5/5] renames and cleanup --- src/vs/workbench/browser/parts/editor/editorGroupView.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/browser/parts/editor/editorGroupView.ts b/src/vs/workbench/browser/parts/editor/editorGroupView.ts index 399f5d8e50cca..6c8c42ec330a3 100644 --- a/src/vs/workbench/browser/parts/editor/editorGroupView.ts +++ b/src/vs/workbench/browser/parts/editor/editorGroupView.ts @@ -18,7 +18,7 @@ import { ProgressBar } from 'vs/base/browser/ui/progressbar/progressbar'; import { IThemeService, Themable } from 'vs/platform/theme/common/themeService'; import { editorBackground, contrastBorder } from 'vs/platform/theme/common/colorRegistry'; import { EDITOR_GROUP_HEADER_TABS_BACKGROUND, EDITOR_GROUP_HEADER_NO_TABS_BACKGROUND, EDITOR_GROUP_EMPTY_BACKGROUND, EDITOR_GROUP_HEADER_BORDER } from 'vs/workbench/common/theme'; -import { ICloseEditorsFilter, GroupsOrder, ICloseEditorOptions, ICloseAllEditorsOptions, IEditorReplacement, IActiveEditorActions, IEditorWorkingSetOptions } from 'vs/workbench/services/editor/common/editorGroupsService'; +import { ICloseEditorsFilter, GroupsOrder, ICloseEditorOptions, ICloseAllEditorsOptions, IEditorReplacement, IActiveEditorActions } from 'vs/workbench/services/editor/common/editorGroupsService'; import { EditorPanes } from 'vs/workbench/browser/parts/editor/editorPanes'; import { IEditorProgressService } from 'vs/platform/progress/common/progress'; import { EditorProgressIndicator } from 'vs/workbench/services/progress/browser/progressIndicator'; @@ -145,7 +145,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { readonly groupsView: IEditorGroupsView, private groupsLabel: string, private _index: number, - editorWorkingSetApplyOptions: IEditorWorkingSetOptions | undefined, + options: IEditorGroupViewOptions | undefined, @IInstantiationService private readonly instantiationService: IInstantiationService, @IContextKeyService private readonly contextKeyService: IContextKeyService, @IThemeService themeService: IThemeService, @@ -237,7 +237,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { //#endregion // Restore editors if provided - const restoreEditorsPromise = this.restoreEditors(from, editorWorkingSetApplyOptions) ?? Promise.resolve(); + const restoreEditorsPromise = this.restoreEditors(from, options) ?? Promise.resolve(); // Signal restored once editors have restored restoreEditorsPromise.finally(() => {