diff --git a/src/vs/editor/contrib/quickAccess/gotoSymbolQuickAccess.ts b/src/vs/editor/contrib/quickAccess/gotoSymbolQuickAccess.ts index ff93ddf72c33d1b2debde28a331b5ac4cf6e9a9c..14fd0da987af0ebcd95b90d0c8e53ea157abd15f 100644 --- a/src/vs/editor/contrib/quickAccess/gotoSymbolQuickAccess.ts +++ b/src/vs/editor/contrib/quickAccess/gotoSymbolQuickAccess.ts @@ -18,7 +18,7 @@ import { trim, format } from 'vs/base/common/strings'; import { fuzzyScore, FuzzyScore, createMatches } from 'vs/base/common/filters'; import { assign } from 'vs/base/common/objects'; -interface IGotoSymbolQuickPickItem extends IQuickPickItem { +export interface IGotoSymbolQuickPickItem extends IQuickPickItem { kind: SymbolKind, index: number, score?: FuzzyScore; @@ -90,7 +90,7 @@ export abstract class AbstractGotoSymbolQuickAccessProvider extends AbstractEdit return disposables; } - private async waitForLanguageSymbolRegistry(model: ITextModel, disposables: DisposableStore): Promise { + protected async waitForLanguageSymbolRegistry(model: ITextModel, disposables: DisposableStore): Promise { if (DocumentSymbolProviderRegistry.has(model)) { return true; } @@ -194,7 +194,7 @@ export abstract class AbstractGotoSymbolQuickAccessProvider extends AbstractEdit return disposables; } - private async doGetSymbolPicks(symbolsPromise: Promise, filter: string, token: CancellationToken): Promise> { + protected async doGetSymbolPicks(symbolsPromise: Promise, filter: string, token: CancellationToken): Promise> { const symbols = await symbolsPromise; if (token.isCancellationRequested) { return []; @@ -367,7 +367,7 @@ export abstract class AbstractGotoSymbolQuickAccessProvider extends AbstractEdit return result; } - private async getDocumentSymbols(document: ITextModel, flatten: boolean, token: CancellationToken): Promise { + protected async getDocumentSymbols(document: ITextModel, flatten: boolean, token: CancellationToken): Promise { const model = await OutlineModel.create(document, token); if (token.isCancellationRequested) { return []; @@ -411,32 +411,6 @@ export abstract class AbstractGotoSymbolQuickAccessProvider extends AbstractEdit } } } - - - //#region public methods to use this picker from other pickers - - async getSymbolPicks(model: ITextModel, filter: string, disposables: DisposableStore, token: CancellationToken): Promise> { - - // If the registry does not know the model, we wait for as long as - // the registry knows it. This helps in cases where a language - // registry was not activated yet for providing any symbols. - const result = await this.waitForLanguageSymbolRegistry(model, disposables); - if (!result || token.isCancellationRequested) { - return []; - } - - return this.doGetSymbolPicks(this.getDocumentSymbols(model, true, token), filter, token); - } - - addDecorations(editor: IEditor, range: IRange): void { - super.addDecorations(editor, range); - } - - clearDecorations(editor: IEditor): void { - super.clearDecorations(editor); - } - - //#endregion } // #region NLS Helpers diff --git a/src/vs/workbench/contrib/codeEditor/browser/quickaccess/gotoSymbolQuickAccess.ts b/src/vs/workbench/contrib/codeEditor/browser/quickaccess/gotoSymbolQuickAccess.ts index 30c15adc69dc28689b604b7618ebfa9cddfd22ba..9cc9b501b4557a93ec37a55529241e51b6c5496f 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/quickaccess/gotoSymbolQuickAccess.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/quickaccess/gotoSymbolQuickAccess.ts @@ -4,15 +4,19 @@ *--------------------------------------------------------------------------------------------*/ import { localize } from 'vs/nls'; -import { IKeyMods } from 'vs/platform/quickinput/common/quickInput'; +import { IKeyMods, IQuickPickSeparator } from 'vs/platform/quickinput/common/quickInput'; import { IEditor } from 'vs/editor/common/editorCommon'; import { IEditorService, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService'; import { IRange } from 'vs/editor/common/core/range'; import { Registry } from 'vs/platform/registry/common/platform'; import { IQuickAccessRegistry, Extensions } from 'vs/platform/quickinput/common/quickAccess'; -import { AbstractGotoSymbolQuickAccessProvider } from 'vs/editor/contrib/quickAccess/gotoSymbolQuickAccess'; +import { AbstractGotoSymbolQuickAccessProvider, IGotoSymbolQuickPickItem } from 'vs/editor/contrib/quickAccess/gotoSymbolQuickAccess'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IWorkbenchEditorConfiguration } from 'vs/workbench/common/editor'; +import { ITextModel } from 'vs/editor/common/model'; +import { DisposableStore } from 'vs/base/common/lifecycle'; +import { timeout } from 'vs/base/common/async'; +import { CancellationToken } from 'vs/base/common/cancellation'; export class GotoSymbolQuickAccessProvider extends AbstractGotoSymbolQuickAccessProvider { @@ -56,6 +60,39 @@ export class GotoSymbolQuickAccessProvider extends AbstractGotoSymbolQuickAccess super.gotoLocation(editor, options); } } + + + //#region public methods to use this picker from other pickers + + private static readonly SYMBOL_PICKS_TIMEOUT = 8000; + + async getSymbolPicks(model: ITextModel, filter: string, disposables: DisposableStore, token: CancellationToken): Promise> { + + // If the registry does not know the model, we wait for as long as + // the registry knows it. This helps in cases where a language + // registry was not activated yet for providing any symbols. + // To not wait forever, we eventually timeout though. + const result = await Promise.race([ + this.waitForLanguageSymbolRegistry(model, disposables), + timeout(GotoSymbolQuickAccessProvider.SYMBOL_PICKS_TIMEOUT) + ]); + + if (!result || token.isCancellationRequested) { + return []; + } + + return this.doGetSymbolPicks(this.getDocumentSymbols(model, true, token), filter, token); + } + + addDecorations(editor: IEditor, range: IRange): void { + super.addDecorations(editor, range); + } + + clearDecorations(editor: IEditor): void { + super.clearDecorations(editor); + } + + //#endregion } Registry.as(Extensions.Quickaccess).registerQuickAccessProvider({ diff --git a/src/vs/workbench/contrib/search/browser/anythingQuickAccess.ts b/src/vs/workbench/contrib/search/browser/anythingQuickAccess.ts index 6396ebd118df768e2cba6990b9b0289231e4d24c..60ca2633227c310f39b9a28db9dba6e306e725d2 100644 --- a/src/vs/workbench/contrib/search/browser/anythingQuickAccess.ts +++ b/src/vs/workbench/contrib/search/browser/anythingQuickAccess.ts @@ -171,7 +171,7 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider> | FastAndSlowPicksType | null { const query = prepareQuery(filter); // Return early if we have editor symbol picks. We support this by: @@ -610,27 +614,35 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider> { - // Obtain model from resource - let model = this.modelService.getModel(activeGlobalResource); - if (!model) { - const modelReference = disposables.add(await this.textModelService.createModelReference(activeGlobalResource)); - if (token.isCancellationRequested) { - return []; - } - - model = modelReference.object.textEditorModel; - } - // Bring the editor to front to review symbols to go to - await this.editorService.openEditor({ - resource: activeGlobalResource, - options: { preserveFocus: true, revealIfOpened: true } - }); + try { + await this.editorService.openEditor({ + resource: activeGlobalResource, + options: { preserveFocus: true, revealIfOpened: true, ignoreError: true } + }); + } catch (error) { + return []; // return if resource cannot be opened + } if (token.isCancellationRequested) { return []; } + // Obtain model from resource + let model = this.modelService.getModel(activeGlobalResource); + if (!model) { + try { + const modelReference = disposables.add(await this.textModelService.createModelReference(activeGlobalResource)); + if (token.isCancellationRequested) { + return []; + } + + model = modelReference.object.textEditorModel; + } catch (error) { + return []; // return if model cannot be resolved + } + } + // Ask provider for editor symbols const editorSymbolPicks = (await this.editorSymbolsQuickAccess.getSymbolPicks(model, filter, disposables, token)); if (token.isCancellationRequested) {