diff --git a/src/vs/workbench/browser/parts/editor2/nextEditorControl.ts b/src/vs/workbench/browser/parts/editor2/nextEditorControl.ts index dae3e56cc58557386b154ec19c4eb7f74d4c3245..fd0ecebd3dac97ab30f387d22c53c07b8982b063 100644 --- a/src/vs/workbench/browser/parts/editor2/nextEditorControl.ts +++ b/src/vs/workbench/browser/parts/editor2/nextEditorControl.ts @@ -117,6 +117,9 @@ export class NextEditorControl extends Disposable { } private doSetInput(control: BaseEditor, editor: EditorInput, options: EditorOptions): Thenable { + + // Show progress while setting input after a certain timeout. If the workbench is opening + // be more relaxed about progress showing by increasing the delay a little bit to reduce flicker. const operationId = this.editorOperation.start(this.partService.isCreated() ? 800 : 3200); // Call into editor control diff --git a/src/vs/workbench/browser/parts/editor2/nextEditorGroupView.ts b/src/vs/workbench/browser/parts/editor2/nextEditorGroupView.ts index d673a7398e020c5451cca0d20d09aab395997673..14fb78e16a93c4156596cb7f55751e20899f0433 100644 --- a/src/vs/workbench/browser/parts/editor2/nextEditorGroupView.ts +++ b/src/vs/workbench/browser/parts/editor2/nextEditorGroupView.ts @@ -462,6 +462,14 @@ export class NextEditorGroupView extends Themable implements IView, INextEditorG //#endregion + //#region isOpen() + + isOpened(editor: EditorInput): boolean { + return this.group.contains(editor); + } + + //#endregion + //#region moveEditor() moveEditor(editor: EditorInput, target: NextEditorGroupView, options?: IMoveEditorOptions): void { diff --git a/src/vs/workbench/browser/parts/editor2/nextEditorPart.ts b/src/vs/workbench/browser/parts/editor2/nextEditorPart.ts index bdcd4199a9eaef789014de7045f6c4682c71b4c8..e0c2520b985178fc588c9487f587cc7372fb87b1 100644 --- a/src/vs/workbench/browser/parts/editor2/nextEditorPart.ts +++ b/src/vs/workbench/browser/parts/editor2/nextEditorPart.ts @@ -19,6 +19,7 @@ import { NextEditorGroupView, IGroupsAccessor } from 'vs/workbench/browser/parts import { GroupIdentifier, EditorOptions } from 'vs/workbench/common/editor'; import { values } from 'vs/base/common/map'; import { EDITOR_GROUP_BORDER } from 'vs/workbench/common/theme'; +import { distinct } from 'vs/base/common/arrays'; // TODO@grid provide DND support of groups/editors: // - editor: move/copy to existing group, move/copy to new split group (up, down, left, right) @@ -73,6 +74,18 @@ export class NextEditorPart extends Part implements INextEditorGroupsService { return values(this.groupViews); } + getGroups(sortByMostRecentlyActive?: boolean): NextEditorGroupView[] { + if (!sortByMostRecentlyActive) { + return this.groups; + } + + const mostRecentActive = this.mostRecentActive.map(groupId => this.getGroup(groupId)); + + // there can be groups that got never active, even though they exist. in this case + // make sure to ust append them at the end so that all groups are returned properly + return distinct([...mostRecentActive, ...this.groups]); + } + getGroup(identifier: GroupIdentifier): NextEditorGroupView { return this.groupViews.get(identifier); } @@ -148,7 +161,7 @@ export class NextEditorPart extends Part implements INextEditorGroupsService { // Activate next group if the removed one was active if (!this._activeGroup) { - const nextActiveGroup = this.asGroupView(this.mostRecentActive[this.mostRecentActive.length - 1]); + const nextActiveGroup = this.asGroupView(this.mostRecentActive[0]); this.activateGroup(nextActiveGroup); // Restore focus if we had it previously @@ -218,12 +231,15 @@ export class NextEditorPart extends Part implements INextEditorGroupsService { private doUpdateMostRecentActive(group: NextEditorGroupView, makeMostRecentlyActive?: boolean): void { const index = this.mostRecentActive.indexOf(group.id); + + // Remove from MRU list if (index !== -1) { this.mostRecentActive.splice(index, 1); } + // Add to front as needed if (makeMostRecentlyActive) { - this.mostRecentActive.push(group.id); + this.mostRecentActive.unshift(group.id); } } diff --git a/src/vs/workbench/services/editor/browser/nextEditorService.ts b/src/vs/workbench/services/editor/browser/nextEditorService.ts index 8cd50eb6852ae86a819b6b214f956b8a2e33d3f8..677cb76fb0b7a210803d12f667fd6fad625dea60 100644 --- a/src/vs/workbench/services/editor/browser/nextEditorService.ts +++ b/src/vs/workbench/services/editor/browser/nextEditorService.ts @@ -24,8 +24,9 @@ import { basename } from 'vs/base/common/paths'; import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput'; import { localize } from 'vs/nls'; import { TPromise } from 'vs/base/common/winjs.base'; -import { INextEditorGroupsService, INextEditorGroup } from 'vs/workbench/services/editor/common/nextEditorGroupsService'; -import { INextEditorService, IResourceEditor, SIDE_BY_SIDE } from 'vs/workbench/services/editor/common/nextEditorService'; +import { INextEditorGroupsService, INextEditorGroup, Direction } from 'vs/workbench/services/editor/common/nextEditorGroupsService'; +import { INextEditorService, IResourceEditor, SIDE_BY_SIDE, SIDE_BY_SIDE_VALUE } from 'vs/workbench/services/editor/common/nextEditorService'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; type ICachedEditorInput = ResourceEditorInput | IFileEditorInput | DataUriEditorInput; @@ -43,7 +44,8 @@ export class NextEditorService implements INextEditorService { @IWorkspaceContextService private workspaceContextService: IWorkspaceContextService, @IInstantiationService private instantiationService: IInstantiationService, @IEnvironmentService private environmentService: IEnvironmentService, - @IFileService private fileService: IFileService + @IFileService private fileService: IFileService, + @IConfigurationService private configurationService: IConfigurationService ) { this.fileInputFactory = Registry.as(EditorExtensions.EditorInputFactories).getFileInputFactory(); } @@ -79,14 +81,44 @@ export class NextEditorService implements INextEditorService { private doOpenEditor(input: IEditorInput, options?: EditorOptions, group?: GroupIdentifier | SIDE_BY_SIDE): Thenable { let targetGroup: INextEditorGroup; - if (group === -1) { - group = void 0; // TODO@grid find correct side group based on active group + // Group: Side by Side + if (group === SIDE_BY_SIDE_VALUE) { + targetGroup = this.nextEditorGroupsService.addGroup(this.nextEditorGroupsService.activeGroup, Direction.RIGHT); } + // Group: Specific Group if (typeof group === 'number') { targetGroup = this.nextEditorGroupsService.getGroup(group); } + // Group: Unspecified without a specific index to open + else if (!options || typeof options.index !== 'number') { + const groupsByLastActive = this.nextEditorGroupsService.getGroups(true); + + // Respect option to reveal an editor if it is already visible in any group + if (options && options.revealIfVisible) { + for (let i = 0; i < groupsByLastActive.length; i++) { + const group = groupsByLastActive[i]; + if (input.matches(group.activeEditor)) { + targetGroup = group; + break; + } + } + } + + // Respect option to reveal an editor if it is open (not necessarily visible) + if ((options && options.revealIfOpened) || this.configurationService.getValue('workbench.editor.revealIfOpen')) { + for (let i = 0; i < groupsByLastActive.length; i++) { + const group = groupsByLastActive[i]; + if (group.isOpened(input)) { + targetGroup = group; + break; + } + } + } + } + + // Fallback to active group if target not valid if (!targetGroup) { targetGroup = this.nextEditorGroupsService.activeGroup; } @@ -212,73 +244,4 @@ export class NextEditorService implements INextEditorService { // Otherwise: for diff labels prefer to see the path as part of the label return getPathLabel(res.fsPath, context, environment); } -} - -//#region TODO@grid adopt legacy code to find a position based on options -// private findPosition(input: EditorInput, options ?: EditorOptions, sideBySide ?: boolean, ratio ?: number[]): Position; -// private findPosition(input: EditorInput, options ?: EditorOptions, desiredPosition ?: Position, ratio ?: number[]): Position; -// private findPosition(input: EditorInput, options ?: EditorOptions, arg1 ?: any, ratio ?: number[]): Position { - -// // With defined ratios, always trust the provided position -// if (ratio && types.isNumber(arg1)) { -// return arg1; -// } - -// // No editor open -// const visibleEditors = this.getVisibleEditors(); -// const activeEditor = this.getActiveEditor(); -// if (visibleEditors.length === 0 || !activeEditor) { -// return Position.ONE; // can only be ONE -// } - -// // Ignore revealIfVisible/revealIfOpened option if we got instructed explicitly to -// // * open at a specific index -// // * open to the side -// // * open in a specific group -// const skipReveal = (options && options.index) || arg1 === true /* open to side */ || typeof arg1 === 'number' /* open specific group */; - -// // Respect option to reveal an editor if it is already visible -// if (!skipReveal && options && options.revealIfVisible) { -// const group = this.stacks.findGroup(input, true); -// if (group) { -// return this.stacks.positionOfGroup(group); -// } -// } - -// // Respect option to reveal an editor if it is open (not necessarily visible) -// if (!skipReveal && (this.revealIfOpen /* workbench.editor.revealIfOpen */ || (options && options.revealIfOpened))) { -// const group = this.stacks.findGroup(input); -// if (group) { -// return this.stacks.positionOfGroup(group); -// } -// } - -// // Position is unknown: pick last active or ONE -// if (types.isUndefinedOrNull(arg1) || arg1 === false) { -// const lastActivePosition = this.editorGroupsControl.getActivePosition(); - -// return lastActivePosition || Position.ONE; -// } - -// // Position is sideBySide: Find position relative to active editor -// if (arg1 === true) { -// switch (activeEditor.position) { -// case Position.ONE: -// return Position.TWO; -// case Position.TWO: -// return Position.THREE; -// case Position.THREE: -// return null; // Cannot open to the side of the right/bottom most editor -// } - -// return null; // Prevent opening to the side -// } - -// // Position is provided, validate it -// if (arg1 === Position.THREE && visibleEditors.length === 1) { -// return Position.TWO; -// } - -// return arg1; -// } -//#endregion \ No newline at end of file +} \ No newline at end of file diff --git a/src/vs/workbench/services/editor/common/nextEditorGroupsService.ts b/src/vs/workbench/services/editor/common/nextEditorGroupsService.ts index 4b1b26621c29814e4aeeb9c7b6696bf4318293a5..1814f835c249ac7a639005e50329f5d261b3285a 100644 --- a/src/vs/workbench/services/editor/common/nextEditorGroupsService.ts +++ b/src/vs/workbench/services/editor/common/nextEditorGroupsService.ts @@ -40,6 +40,12 @@ export interface INextEditorGroup { */ openEditor(editor: IEditorInput, options?: IEditorOptions): Thenable; + /** + * Find out if the provided editor is opened in the group. An editor can be opened + * but not actively visible. + */ + isOpened(editor: IEditorInput): boolean; + /** * Move an editor from this group either within this group or to another group. */ @@ -85,6 +91,7 @@ export interface INextEditorGroupsService { readonly activeGroup: INextEditorGroup; readonly groups: INextEditorGroup[]; + getGroups(sortByMostRecentlyActive?: boolean): INextEditorGroup[]; getGroup(identifier: GroupIdentifier): INextEditorGroup; focusGroup(group: INextEditorGroup | GroupIdentifier): INextEditorGroup; diff --git a/src/vs/workbench/services/editor/common/nextEditorService.ts b/src/vs/workbench/services/editor/common/nextEditorService.ts index 05b5dbd821318bc70457a08e2b4f065c158ecf5c..cc61f0570e792cb5595bfa84a52aaa7ac67e98c5 100644 --- a/src/vs/workbench/services/editor/common/nextEditorService.ts +++ b/src/vs/workbench/services/editor/common/nextEditorService.ts @@ -13,7 +13,8 @@ export const INextEditorService = createDecorator('nextEdito export type IResourceEditor = IResourceInput | IUntitledResourceInput | IResourceDiffInput | IResourceSideBySideInput; -export type SIDE_BY_SIDE = -1; +export const SIDE_BY_SIDE_VALUE = -1; +export type SIDE_BY_SIDE = typeof SIDE_BY_SIDE_VALUE; // TODO@grid this should provide convinience methods on top of INextEditorGroupsService to make the 99% // case of opening editors as simple as possible