diff --git a/src/vs/workbench/contrib/files/browser/files.contribution.ts b/src/vs/workbench/contrib/files/browser/files.contribution.ts index 2343d7ee2182791c3d0610f2083357ca555320f1..4fb8391d0abdc61db13ebd4d745bc019cb3296e6 100644 --- a/src/vs/workbench/contrib/files/browser/files.contribution.ts +++ b/src/vs/workbench/contrib/files/browser/files.contribution.ts @@ -393,6 +393,16 @@ configurationRegistry.registerConfiguration({ 'description': nls.localize({ key: 'openEditorsVisible', comment: ['Open is an adjective'] }, "Number of editors shown in the Open Editors pane. Setting this to 0 hides the Open Editors pane."), 'default': 9 }, + 'explorer.openEditors.sortOrder': { + 'type': 'string', + 'enum': ['editorOrder', 'alphabetical'], + 'description': nls.localize({ key: 'openEditorsSortOrder', comment: ['Open is an adjective'] }, "Controls the sorting order of editors in the Open Editors pane."), + 'enumDescriptions': [ + nls.localize('sortOrder.editorOrder', 'Editors are ordered in the same order editor tabs are shown.'), + nls.localize('sortOrder.alphabetical', 'Editors are ordered in alphabetical order inside each editor group.') + ], + 'default': 'editorOrder' + }, 'explorer.autoReveal': { 'type': ['boolean', 'string'], 'enum': [true, false, 'focusNoScroll'], diff --git a/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts b/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts index 5c1e9e59b5f3e652bcc93be48bf8504497dc0b91..8c2a78e037dc06c621764dcaa6f6f675dcaa838a 100644 --- a/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts +++ b/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts @@ -48,6 +48,7 @@ import { IViewDescriptorService } from 'vs/workbench/common/views'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { Orientation } from 'vs/base/browser/ui/splitview/splitview'; import { IListAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget'; +import { compareFileNamesDefault } from 'vs/base/common/comparers'; const $ = dom.$; @@ -64,6 +65,8 @@ export class OpenEditorsView extends ViewPane { private listLabels: ResourceLabels | undefined; private contributedContextMenu!: IMenu; private needsRefresh = false; + private elements: (OpenEditor | IEditorGroup)[] = []; + private sortOrder: 'editorOrder' | 'alphabetical'; private resourceContext!: ResourceContextKey; private groupFocusedContext!: IContextKey; private dirtyEditorFocusedContext!: IContextKey; @@ -91,13 +94,14 @@ export class OpenEditorsView extends ViewPane { this.structuralRefreshDelay = 0; this.listRefreshScheduler = new RunOnceScheduler(() => { const previousLength = this.list.length; - this.list.splice(0, this.list.length, this.elements); + this.list.splice(0, this.list.length, this.getElements()); this.focusActiveEditor(); if (previousLength !== this.list.length) { this.updateSize(); } this.needsRefresh = false; }, this.structuralRefreshDelay); + this.sortOrder = configurationService.getValue('explorer.openEditors.sortOrder'); this.registerUpdateEvents(); @@ -132,7 +136,7 @@ export class OpenEditorsView extends ViewPane { const index = this.getIndex(group, e.editor); switch (e.kind) { case GroupChangeKind.GROUP_INDEX: { - if (this.showGroups) { + if (index >= 0) { this.list.splice(index, 1, [group]); } break; @@ -149,19 +153,10 @@ export class OpenEditorsView extends ViewPane { this.list.splice(index, 1, [new OpenEditor(e.editor!, group)]); break; } - case GroupChangeKind.EDITOR_OPEN: { - this.list.splice(index, 0, [new OpenEditor(e.editor!, group)]); - setTimeout(() => this.updateSize(), this.structuralRefreshDelay); - break; - } - case GroupChangeKind.EDITOR_CLOSE: { - const previousIndex = this.getIndex(group, undefined) + (e.editorIndex || 0) + (this.showGroups ? 1 : 0); - this.list.splice(previousIndex, 1); - this.updateSize(); - break; - } + case GroupChangeKind.EDITOR_OPEN: + case GroupChangeKind.EDITOR_CLOSE: case GroupChangeKind.EDITOR_MOVE: { - this.listRefreshScheduler.schedule(); + updateWholeList(); break; } } @@ -331,33 +326,28 @@ export class OpenEditorsView extends ViewPane { return this.editorGroupService.groups.length > 1; } - private get elements(): Array { - const result: Array = []; + private getElements(): Array { + this.elements = []; this.editorGroupService.getGroups(GroupsOrder.GRID_APPEARANCE).forEach(g => { if (this.showGroups) { - result.push(g); + this.elements.push(g); + } + let editors = g.editors.map(ei => new OpenEditor(ei, g)); + if (this.sortOrder === 'alphabetical') { + editors = editors.sort((first, second) => compareFileNamesDefault(first.editor.getName(), second.editor.getName())); } - result.push(...g.editors.map(ei => new OpenEditor(ei, g))); + this.elements.push(...editors); }); - return result; + return this.elements; } private getIndex(group: IEditorGroup, editor: IEditorInput | undefined | null): number { - let index = editor ? group.getIndexOfEditor(editor) : 0; - if (!this.showGroups) { - return index; + if (!editor) { + return this.elements.findIndex(e => !(e instanceof OpenEditor) && e.id === group.id); } - for (let g of this.editorGroupService.getGroups(GroupsOrder.GRID_APPEARANCE)) { - if (g.id === group.id) { - return index + (!!editor ? 1 : 0); - } else { - index += g.count + 1; - } - } - - return -1; + return this.elements.findIndex(e => e instanceof OpenEditor && e.editor === editor && e.group.id === group.id); } private openEditor(element: OpenEditor, options: { preserveFocus?: boolean; pinned?: boolean; sideBySide?: boolean; }): void { @@ -384,7 +374,7 @@ export class OpenEditorsView extends ViewPane { this.contextMenuService.showContextMenu({ getAnchor: () => e.anchor, getActions: () => actions, - getActionsContext: () => element instanceof OpenEditor ? { groupId: element.groupId, editorIndex: element.editorIndex } : { groupId: element.id }, + getActionsContext: () => element instanceof OpenEditor ? { groupId: element.groupId, editorIndex: element.group.getIndexOfEditor(element.editor) } : { groupId: element.id }, onHide: () => dispose(actionsDisposable) }); } @@ -393,9 +383,13 @@ export class OpenEditorsView extends ViewPane { if (this.list.length && this.editorGroupService.activeGroup) { const index = this.getIndex(this.editorGroupService.activeGroup, this.editorGroupService.activeGroup.activeEditor); if (index >= 0) { - this.list.setFocus([index]); - this.list.setSelection([index]); - this.list.reveal(index); + try { + this.list.setFocus([index]); + this.list.setSelection([index]); + this.list.reveal(index); + } catch (e) { + // noop list updated in the meantime + } return; } } @@ -408,9 +402,9 @@ export class OpenEditorsView extends ViewPane { if (event.affectsConfiguration('explorer.openEditors')) { this.updateSize(); } - - // Trigger a 'repaint' when decoration settings change - if (event.affectsConfiguration('explorer.decorations')) { + // Trigger a 'repaint' when decoration settings change or the sort order changed + if (event.affectsConfiguration('explorer.decorations') || event.affectsConfiguration('explorer.openEditors.sortOrder')) { + this.sortOrder = this.configurationService.getValue('explorer.openEditors.sortOrder'); this.listRefreshScheduler.schedule(); } } @@ -500,7 +494,7 @@ class OpenEditorActionRunner extends ActionRunner { return; } - return super.run(action, { groupId: this.editor.groupId, editorIndex: this.editor.editorIndex }); + return super.run(action, { groupId: this.editor.groupId, editorIndex: this.editor.group.getIndexOfEditor(this.editor.editor) }); } } @@ -687,7 +681,7 @@ class OpenEditorsDragAndDrop implements IListDragAndDrop