diff --git a/src/vs/editor/contrib/documentSymbols/outlineTree.ts b/src/vs/editor/contrib/documentSymbols/outlineTree.ts index cf83dd2df8eefc8e9ff64eb824f04b093c101578..3731090248a4ca90f8e1ad6e432e63a45260f79f 100644 --- a/src/vs/editor/contrib/documentSymbols/outlineTree.ts +++ b/src/vs/editor/contrib/documentSymbols/outlineTree.ts @@ -324,24 +324,37 @@ export class OutlineItemComparator implements ITreeSorter { private readonly _collator = new IdleValue(() => new Intl.Collator(undefined, { numeric: true })); constructor( - public type: OutlineSortOrder = OutlineSortOrder.ByPosition + private readonly _prefix: 'breadcrumbs' | 'outline', + @ITextResourceConfigurationService private readonly _textResourceConfigService: ITextResourceConfigurationService, ) { } compare(a: OutlineItem, b: OutlineItem): number { if (a instanceof OutlineGroup && b instanceof OutlineGroup) { return a.order - b.order; - } else if (a instanceof OutlineElement && b instanceof OutlineElement) { - if (this.type === OutlineSortOrder.ByKind) { + const type = this._getSortOrder(OutlineModel.get(a)); + if (type === OutlineSortOrder.ByKind) { return a.symbol.kind - b.symbol.kind || this._collator.value.compare(a.symbol.name, b.symbol.name); - } else if (this.type === OutlineSortOrder.ByName) { + } else if (type === OutlineSortOrder.ByName) { return this._collator.value.compare(a.symbol.name, b.symbol.name) || Range.compareRangesUsingStarts(a.symbol.range, b.symbol.range); - } else if (this.type === OutlineSortOrder.ByPosition) { + } else if (type === OutlineSortOrder.ByPosition) { return Range.compareRangesUsingStarts(a.symbol.range, b.symbol.range) || this._collator.value.compare(a.symbol.name, b.symbol.name); } } return 0; } + + private _getSortOrder(model: OutlineModel | undefined): OutlineSortOrder { + const uri = model?.textModel.uri; + const value = this._textResourceConfigService.getValue(uri, `${this._prefix}.symbolSortOrder`); + if (value === 'name') { + return OutlineSortOrder.ByName; + } else if (value === 'type') { + return OutlineSortOrder.ByKind; + } else { + return OutlineSortOrder.ByPosition; + } + } } export class OutlineDataSource implements IDataSource { diff --git a/src/vs/workbench/contrib/codeEditor/browser/outline/documentSymbolsOutline.ts b/src/vs/workbench/contrib/codeEditor/browser/outline/documentSymbolsOutline.ts index e212fd5157a00bb4e6205b0dc4926945fe9eca15..12308817afac4cadc981b190adaa7f9a9e01d339 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/outline/documentSymbolsOutline.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/outline/documentSymbolsOutline.ts @@ -31,7 +31,7 @@ import { IModelContentChangedEvent } from 'vs/editor/common/model/textModelEvent import { IDataSource } from 'vs/base/browser/ui/tree/tree'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { localize } from 'vs/nls'; -import { OutlineConfigKeys, OutlineSortOrder } from 'vs/editor/contrib/documentSymbols/outline'; +import { OutlineConfigKeys } from 'vs/editor/contrib/documentSymbols/outline'; import { IMarkerDecorationsService } from 'vs/editor/common/services/markersDecorationService'; import { MarkerSeverity } from 'vs/platform/markers/common/markers'; @@ -184,8 +184,6 @@ class DocumentSymbolsOutline implements IOutline { keyboardNavigationLabelProvider: new OutlineNavigationLabelProvider(), }; - const breadcrumbsSorter = new OutlineItemComparator(); - this.breadcrumbsConfig = { breadcrumbsDataSource: this._breadcrumbsDataSource, delegate, @@ -193,7 +191,7 @@ class DocumentSymbolsOutline implements IOutline { treeDataSource, options: { ...options, - sorter: breadcrumbsSorter, + sorter: instantiationService.createInstance(OutlineItemComparator, 'breadcrumbs'), filter: instantiationService.createInstance(OutlineFilter, 'breadcrumbs'), accessibilityProvider: new OutlineAccessibilityProvider(localize('breadcrumbs', "Breadcrumbs")), } @@ -205,7 +203,7 @@ class DocumentSymbolsOutline implements IOutline { treeDataSource, options: { ...options, - sorter: new OutlineItemComparator(), //todo@jrieken + sorter: instantiationService.createInstance(OutlineItemComparator, 'outline'), filter: instantiationService.createInstance(OutlineFilter, 'outline'), accessibilityProvider: new OutlineAccessibilityProvider(localize('outline', "Outline")), } @@ -215,22 +213,6 @@ class DocumentSymbolsOutline implements IOutline { quickPickDataSource: { getQuickPickElements: () => { throw new Error('not implemented'); } } }; - // special sorting for breadcrumbs - const updateSort = () => { - const uri = this._outlineModel?.textModel.uri; - const value = textResourceConfigurationService.getValue(uri, `breadcrumbs.symbolSortOrder`); - if (value === 'name') { - breadcrumbsSorter.type = OutlineSortOrder.ByName; - } else if (value === 'type') { - breadcrumbsSorter.type = OutlineSortOrder.ByKind; - } else { - breadcrumbsSorter.type = OutlineSortOrder.ByPosition; - } - }; - this._disposables.add(textResourceConfigurationService.onDidChangeConfiguration(() => updateSort())); - updateSort(); - - // update as language, model, providers changes this._disposables.add(DocumentSymbolProviderRegistry.onDidChange(_ => this._createOutline())); this._disposables.add(this._editor.onDidChangeModel(_ => this._createOutline())); diff --git a/src/vs/workbench/contrib/outline/browser/outline.contribution.ts b/src/vs/workbench/contrib/outline/browser/outline.contribution.ts index 886dbd130a12ed18a50fdfda1e97973f26ea8470..496168ddce409703bfa0e1c8900f7585289c3922 100644 --- a/src/vs/workbench/contrib/outline/browser/outline.contribution.ts +++ b/src/vs/workbench/contrib/outline/browser/outline.contribution.ts @@ -44,6 +44,18 @@ Registry.as(ConfigurationExtensions.Configuration).regis 'type': 'boolean', 'default': true }, + 'outline.symbolSortOrder': { + description: localize('symbolSortOrder', "Controls how symbols are sorted in the outline view."), + type: 'string', + default: 'position', + // scope: ConfigurationScope.LANGUAGE_OVERRIDABLE, + enum: ['position', 'name', 'type'], + enumDescriptions: [ + localize('symbolSortOrder.position', "Show symbol outline in file position order."), + localize('symbolSortOrder.name', "Show symbol outline in alphabetical order."), + localize('symbolSortOrder.type', "Show symbol outline in symbol type order."), + ] + }, [OutlineConfigKeys.problemsEnabled]: { 'description': localize('outline.showProblem', "Show Errors & Warnings on Outline Elements."), 'type': 'boolean', diff --git a/src/vs/workbench/contrib/outline/browser/outlinePane.ts b/src/vs/workbench/contrib/outline/browser/outlinePane.ts index 07b13fdc74ed6420c9da9714446090a6b219ef6c..e892d3569a7c4e1ce435810d8ead5510a4e51443 100644 --- a/src/vs/workbench/contrib/outline/browser/outlinePane.ts +++ b/src/vs/workbench/contrib/outline/browser/outlinePane.ts @@ -11,7 +11,7 @@ import { IDisposable, toDisposable, DisposableStore, MutableDisposable } from 'v import { LRUCache } from 'vs/base/common/map'; import { localize } from 'vs/nls'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { ContextKeyEqualsExpr, IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; +import { ContextKeyEqualsExpr, ContextKeyExpr, IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; @@ -22,7 +22,7 @@ import { IThemeService } from 'vs/platform/theme/common/themeService'; import { ViewAction, ViewPane } from 'vs/workbench/browser/parts/views/viewPane'; import { IViewletViewOptions } from 'vs/workbench/browser/parts/views/viewsViewlet'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; -import { OutlineViewFocused, OutlineViewFiltered, OutlineViewId, OutlineSortOrder } from 'vs/editor/contrib/documentSymbols/outline'; +import { OutlineViewFocused, OutlineViewFiltered, OutlineViewId } from 'vs/editor/contrib/documentSymbols/outline'; import { FuzzyScore } from 'vs/base/common/filters'; import { IDataTreeViewState } from 'vs/base/browser/ui/tree/dataTree'; import { basename } from 'vs/base/common/resources'; @@ -58,7 +58,6 @@ export class OutlinePane extends ViewPane { private readonly _ctxFiltered: IContextKey; private readonly _ctxFollowsCursor: IContextKey; private readonly _ctxFilterOnType: IContextKey; - private readonly _ctxSortMode: IContextKey; constructor( options: IViewletViewOptions, @@ -78,21 +77,19 @@ export class OutlinePane extends ViewPane { ) { super(options, keybindingService, contextMenuService, configurationService, contextKeyService, viewDescriptorService, _instantiationService, openerService, themeService, telemetryService); this._outlineViewState.restore(this._storageService); + this._ctxFocused = OutlineViewFocused.bindTo(contextKeyService); this._ctxFiltered = OutlineViewFiltered.bindTo(contextKeyService); + this._ctxFollowsCursor = _ctxFollowsCursor.bindTo(contextKeyService); + this._ctxFilterOnType = _ctxFilterOnType.bindTo(contextKeyService); this._disposables.add(this.onDidFocus(_ => this._ctxFocused.set(true))); this._disposables.add(this.onDidBlur(_ => this._ctxFocused.set(false))); - this._ctxFollowsCursor = _ctxFollowsCursor.bindTo(contextKeyService); - this._ctxFilterOnType = _ctxFilterOnType.bindTo(contextKeyService); - this._ctxSortMode = _ctxSortMode.bindTo(contextKeyService); - const viewStateToContext = () => { - this._ctxFollowsCursor.set(this._outlineViewState.followCursor); - this._ctxFilterOnType.set(this._outlineViewState.filterOnType); - this._ctxSortMode.set(this._outlineViewState.sortBy); - }; - viewStateToContext(); - this._outlineViewState.onDidChange(viewStateToContext, this); + this._disposables.add(configurationService.onDidChangeConfiguration(e => { + if (e.affectsConfiguration('outline.symbolSortOrder')) { + this._tree?.resort(); + } + })); } dispose(): void { @@ -149,18 +146,19 @@ export class OutlinePane extends ViewPane { } private _onDidChangeUserState(e: { followCursor?: boolean, sortBy?: boolean, filterOnType?: boolean }) { - this._outlineViewState.persist(this._storageService); - if (e.sortBy) { - // todo@jrieken - // this._treeComparator.type = this._outlineViewState.sortBy; - this._tree?.resort(); - } + this._ctxFollowsCursor.set(this._outlineViewState.followCursor); + this._ctxFilterOnType.set(this._outlineViewState.filterOnType); + + this._outlineViewState.persist(this._storageService); if (e.filterOnType) { this._tree?.updateOptions({ filterOnType: this._outlineViewState.filterOnType }); } + if (e.followCursor) { + + } } private _showMessage(message: string) { @@ -306,7 +304,6 @@ export class OutlinePane extends ViewPane { const _ctxFollowsCursor = new RawContextKey('outlineFollowsCursor', false); const _ctxFilterOnType = new RawContextKey('outlineFiltersOnType', false); -const _ctxSortMode = new RawContextKey('outlineSortMode', OutlineSortOrder.ByPosition); // --- commands @@ -379,7 +376,7 @@ registerAction2(class SortByPosition extends ViewAction { id: 'outline.sortByPosition', title: localize('sortByPosition', "Sort By: Position"), f1: false, - toggled: _ctxSortMode.isEqualTo(OutlineSortOrder.ByPosition), + toggled: ContextKeyExpr.equals('config.outline.symbolSortOrder', 'position'), menu: { id: MenuId.ViewTitle, group: 'sort', @@ -388,8 +385,8 @@ registerAction2(class SortByPosition extends ViewAction { } }); } - runInView(_accessor: ServicesAccessor, view: OutlinePane) { - view.outlineViewState.sortBy = OutlineSortOrder.ByPosition; + runInView(accessor: ServicesAccessor) { + accessor.get(IConfigurationService).updateValue('outline.symbolSortOrder', 'position'); } }); @@ -400,7 +397,7 @@ registerAction2(class SortByName extends ViewAction { id: 'outline.sortByName', title: localize('sortByName', "Sort By: Name"), f1: false, - toggled: _ctxSortMode.isEqualTo(OutlineSortOrder.ByName), + toggled: ContextKeyExpr.equals('config.outline.symbolSortOrder', 'name'), menu: { id: MenuId.ViewTitle, group: 'sort', @@ -409,8 +406,8 @@ registerAction2(class SortByName extends ViewAction { } }); } - runInView(_accessor: ServicesAccessor, view: OutlinePane) { - view.outlineViewState.sortBy = OutlineSortOrder.ByName; + runInView(accessor: ServicesAccessor) { + accessor.get(IConfigurationService).updateValue('outline.symbolSortOrder', 'name'); } }); @@ -421,7 +418,7 @@ registerAction2(class SortByKind extends ViewAction { id: 'outline.sortByKind', title: localize('sortByKind', "Sort By: Category"), f1: false, - toggled: _ctxSortMode.isEqualTo(OutlineSortOrder.ByKind), + toggled: ContextKeyExpr.equals('config.outline.symbolSortOrder', 'type'), menu: { id: MenuId.ViewTitle, group: 'sort', @@ -430,7 +427,7 @@ registerAction2(class SortByKind extends ViewAction { } }); } - runInView(_accessor: ServicesAccessor, view: OutlinePane) { - view.outlineViewState.sortBy = OutlineSortOrder.ByKind; + runInView(accessor: ServicesAccessor) { + accessor.get(IConfigurationService).updateValue('outline.symbolSortOrder', 'type'); } }); diff --git a/src/vs/workbench/contrib/outline/browser/outlineViewState.ts b/src/vs/workbench/contrib/outline/browser/outlineViewState.ts index d8ebe51ee8c4a5c3aea7855a7a77aeed9b50a4cc..8239edaccef6126d0be1a846a963939063f19393 100644 --- a/src/vs/workbench/contrib/outline/browser/outlineViewState.ts +++ b/src/vs/workbench/contrib/outline/browser/outlineViewState.ts @@ -5,13 +5,11 @@ import { Emitter } from 'vs/base/common/event'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; -import { OutlineSortOrder } from 'vs/editor/contrib/documentSymbols/outline'; export class OutlineViewState { private _followCursor = false; private _filterOnType = true; - private _sortBy = OutlineSortOrder.ByKind; private readonly _onDidChange = new Emitter<{ followCursor?: boolean; sortBy?: boolean; filterOnType?: boolean; }>(); readonly onDidChange = this._onDidChange.event; @@ -38,21 +36,9 @@ export class OutlineViewState { } } - set sortBy(value: OutlineSortOrder) { - if (value !== this._sortBy) { - this._sortBy = value; - this._onDidChange.fire({ sortBy: true }); - } - } - - get sortBy(): OutlineSortOrder { - return this._sortBy; - } - persist(storageService: IStorageService): void { storageService.store('outline/state', JSON.stringify({ followCursor: this.followCursor, - sortBy: this.sortBy, filterOnType: this.filterOnType, }), StorageScope.WORKSPACE, StorageTarget.USER); } @@ -69,7 +55,6 @@ export class OutlineViewState { return; } this.followCursor = data.followCursor; - this.sortBy = data.sortBy; if (typeof data.filterOnType === 'boolean') { this.filterOnType = data.filterOnType; }