Path: blob/main/src/vs/editor/contrib/gotoSymbol/browser/goToCommands.ts
3296 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { alert } from '../../../../base/browser/ui/aria/aria.js';6import { createCancelablePromise, raceCancellation } from '../../../../base/common/async.js';7import { CancellationToken } from '../../../../base/common/cancellation.js';8import { KeyChord, KeyCode, KeyMod } from '../../../../base/common/keyCodes.js';9import { assertType } from '../../../../base/common/types.js';10import { URI } from '../../../../base/common/uri.js';11import { CodeEditorStateFlag, EditorStateCancellationTokenSource } from '../../editorState/browser/editorState.js';12import { IActiveCodeEditor, ICodeEditor, isCodeEditor } from '../../../browser/editorBrowser.js';13import { EditorAction2, ServicesAccessor } from '../../../browser/editorExtensions.js';14import { ICodeEditorService } from '../../../browser/services/codeEditorService.js';15import { EmbeddedCodeEditorWidget } from '../../../browser/widget/codeEditor/embeddedCodeEditorWidget.js';16import { EditorOption, GoToLocationValues } from '../../../common/config/editorOptions.js';17import * as corePosition from '../../../common/core/position.js';18import { IRange, Range } from '../../../common/core/range.js';19import { ScrollType } from '../../../common/editorCommon.js';20import { EditorContextKeys } from '../../../common/editorContextKeys.js';21import { ITextModel } from '../../../common/model.js';22import { isLocationLink, Location, LocationLink } from '../../../common/languages.js';23import { ReferencesController } from './peek/referencesController.js';24import { ReferencesModel } from './referencesModel.js';25import { ISymbolNavigationService } from './symbolNavigation.js';26import { MessageController } from '../../message/browser/messageController.js';27import { PeekContext } from '../../peekView/browser/peekView.js';28import * as nls from '../../../../nls.js';29import { IAction2F1RequiredOptions, IAction2Options, ISubmenuItem, MenuId, MenuRegistry, registerAction2 } from '../../../../platform/actions/common/actions.js';30import { CommandsRegistry, ICommandService } from '../../../../platform/commands/common/commands.js';31import { ContextKeyExpr } from '../../../../platform/contextkey/common/contextkey.js';32import { TextEditorSelectionRevealType, TextEditorSelectionSource } from '../../../../platform/editor/common/editor.js';33import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js';34import { KeybindingWeight } from '../../../../platform/keybinding/common/keybindingsRegistry.js';35import { INotificationService } from '../../../../platform/notification/common/notification.js';36import { IEditorProgressService } from '../../../../platform/progress/common/progress.js';37import { getDeclarationsAtPosition, getDefinitionsAtPosition, getImplementationsAtPosition, getReferencesAtPosition, getTypeDefinitionsAtPosition } from './goToSymbol.js';38import { IWordAtPosition } from '../../../common/core/wordHelper.js';39import { ILanguageFeaturesService } from '../../../common/services/languageFeatures.js';40import { Iterable } from '../../../../base/common/iterator.js';41import { IsWebContext } from '../../../../platform/contextkey/common/contextkeys.js';4243MenuRegistry.appendMenuItem(MenuId.EditorContext, {44submenu: MenuId.EditorContextPeek,45title: nls.localize('peek.submenu', "Peek"),46group: 'navigation',47order: 10048} satisfies ISubmenuItem);4950export interface SymbolNavigationActionConfig {51openToSide: boolean;52openInPeek: boolean;53muteMessage: boolean;54}5556export class SymbolNavigationAnchor {5758static is(thing: any): thing is SymbolNavigationAnchor {59if (!thing || typeof thing !== 'object') {60return false;61}62if (thing instanceof SymbolNavigationAnchor) {63return true;64}65if (corePosition.Position.isIPosition((<SymbolNavigationAnchor>thing).position) && (<SymbolNavigationAnchor>thing).model) {66return true;67}68return false;69}7071constructor(readonly model: ITextModel, readonly position: corePosition.Position) { }72}7374export abstract class SymbolNavigationAction extends EditorAction2 {7576private static _allSymbolNavigationCommands = new Map<string, SymbolNavigationAction>();77private static _activeAlternativeCommands = new Set<string>();7879static all(): IterableIterator<SymbolNavigationAction> {80return SymbolNavigationAction._allSymbolNavigationCommands.values();81}8283private static _patchConfig(opts: IAction2Options & IAction2F1RequiredOptions): IAction2Options {84const result = { ...opts, f1: true };85// patch context menu when clause86if (result.menu) {87for (const item of Iterable.wrap(result.menu)) {88if (item.id === MenuId.EditorContext || item.id === MenuId.EditorContextPeek) {89item.when = ContextKeyExpr.and(opts.precondition, item.when);90}91}92}93return <typeof opts>result;94}9596readonly configuration: SymbolNavigationActionConfig;9798constructor(configuration: SymbolNavigationActionConfig, opts: IAction2Options & IAction2F1RequiredOptions) {99super(SymbolNavigationAction._patchConfig(opts));100this.configuration = configuration;101SymbolNavigationAction._allSymbolNavigationCommands.set(opts.id, this);102}103104override runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, arg?: SymbolNavigationAnchor | unknown, range?: Range): Promise<void> {105if (!editor.hasModel()) {106return Promise.resolve(undefined);107}108const notificationService = accessor.get(INotificationService);109const editorService = accessor.get(ICodeEditorService);110const progressService = accessor.get(IEditorProgressService);111const symbolNavService = accessor.get(ISymbolNavigationService);112const languageFeaturesService = accessor.get(ILanguageFeaturesService);113const instaService = accessor.get(IInstantiationService);114115const model = editor.getModel();116const position = editor.getPosition();117const anchor = SymbolNavigationAnchor.is(arg) ? arg : new SymbolNavigationAnchor(model, position);118119const cts = new EditorStateCancellationTokenSource(editor, CodeEditorStateFlag.Value | CodeEditorStateFlag.Position);120121const promise = raceCancellation(this._getLocationModel(languageFeaturesService, anchor.model, anchor.position, cts.token), cts.token).then(async references => {122123if (!references || cts.token.isCancellationRequested) {124return;125}126127alert(references.ariaMessage);128129let altAction: SymbolNavigationAction | null | undefined;130if (references.referenceAt(model.uri, position)) {131const altActionId = this._getAlternativeCommand(editor);132if (altActionId !== undefined && !SymbolNavigationAction._activeAlternativeCommands.has(altActionId) && SymbolNavigationAction._allSymbolNavigationCommands.has(altActionId)) {133altAction = SymbolNavigationAction._allSymbolNavigationCommands.get(altActionId)!;134}135}136137const referenceCount = references.references.length;138139if (referenceCount === 0) {140// no result -> show message141if (!this.configuration.muteMessage) {142const info = model.getWordAtPosition(position);143MessageController.get(editor)?.showMessage(this._getNoResultFoundMessage(info), position);144}145} else if (referenceCount === 1 && altAction) {146// already at the only result, run alternative147SymbolNavigationAction._activeAlternativeCommands.add(this.desc.id);148instaService.invokeFunction((accessor) => altAction.runEditorCommand(accessor, editor, arg, range).finally(() => {149SymbolNavigationAction._activeAlternativeCommands.delete(this.desc.id);150}));151152} else {153// normal results handling154return this._onResult(editorService, symbolNavService, editor, references, range);155}156157}, (err) => {158// report an error159notificationService.error(err);160}).finally(() => {161cts.dispose();162});163164progressService.showWhile(promise, 250);165return promise;166}167168protected abstract _getLocationModel(languageFeaturesService: ILanguageFeaturesService, model: ITextModel, position: corePosition.Position, token: CancellationToken): Promise<ReferencesModel | undefined>;169170protected abstract _getNoResultFoundMessage(info: IWordAtPosition | null): string;171172protected abstract _getAlternativeCommand(editor: IActiveCodeEditor): string | undefined;173174protected abstract _getGoToPreference(editor: IActiveCodeEditor): GoToLocationValues;175176private async _onResult(editorService: ICodeEditorService, symbolNavService: ISymbolNavigationService, editor: IActiveCodeEditor, model: ReferencesModel, range?: Range): Promise<void> {177178const gotoLocation = this._getGoToPreference(editor);179if (!(editor instanceof EmbeddedCodeEditorWidget) && (this.configuration.openInPeek || (gotoLocation === 'peek' && model.references.length > 1))) {180this._openInPeek(editor, model, range);181182} else {183const next = model.firstReference()!;184const peek = model.references.length > 1 && gotoLocation === 'gotoAndPeek';185const targetEditor = await this._openReference(editor, editorService, next, this.configuration.openToSide, !peek);186if (peek && targetEditor) {187this._openInPeek(targetEditor, model, range);188} else {189model.dispose();190}191192// keep remaining locations around when using193// 'goto'-mode194if (gotoLocation === 'goto') {195symbolNavService.put(next);196}197}198}199200private async _openReference(editor: ICodeEditor, editorService: ICodeEditorService, reference: Location | LocationLink, sideBySide: boolean, highlight: boolean): Promise<ICodeEditor | undefined> {201// range is the target-selection-range when we have one202// and the fallback is the 'full' range203let range: IRange | undefined = undefined;204if (isLocationLink(reference)) {205range = reference.targetSelectionRange;206}207if (!range) {208range = reference.range;209}210if (!range) {211return undefined;212}213214const targetEditor = await editorService.openCodeEditor({215resource: reference.uri,216options: {217selection: Range.collapseToStart(range),218selectionRevealType: TextEditorSelectionRevealType.NearTopIfOutsideViewport,219selectionSource: TextEditorSelectionSource.JUMP220}221}, editor, sideBySide);222223if (!targetEditor) {224return undefined;225}226227if (highlight) {228const modelNow = targetEditor.getModel();229const decorations = targetEditor.createDecorationsCollection([{ range, options: { description: 'symbol-navigate-action-highlight', className: 'symbolHighlight' } }]);230setTimeout(() => {231if (targetEditor.getModel() === modelNow) {232decorations.clear();233}234}, 350);235}236237return targetEditor;238}239240private _openInPeek(target: ICodeEditor, model: ReferencesModel, range?: Range) {241const controller = ReferencesController.get(target);242if (controller && target.hasModel()) {243controller.toggleWidget(range ?? target.getSelection(), createCancelablePromise(_ => Promise.resolve(model)), this.configuration.openInPeek);244} else {245model.dispose();246}247}248}249250//#region --- DEFINITION251252export class DefinitionAction extends SymbolNavigationAction {253254protected async _getLocationModel(languageFeaturesService: ILanguageFeaturesService, model: ITextModel, position: corePosition.Position, token: CancellationToken): Promise<ReferencesModel> {255return new ReferencesModel(await getDefinitionsAtPosition(languageFeaturesService.definitionProvider, model, position, false, token), nls.localize('def.title', 'Definitions'));256}257258protected _getNoResultFoundMessage(info: IWordAtPosition | null): string {259return info && info.word260? nls.localize('noResultWord', "No definition found for '{0}'", info.word)261: nls.localize('generic.noResults', "No definition found");262}263264protected _getAlternativeCommand(editor: IActiveCodeEditor): string {265return editor.getOption(EditorOption.gotoLocation).alternativeDefinitionCommand;266}267268protected _getGoToPreference(editor: IActiveCodeEditor): GoToLocationValues {269return editor.getOption(EditorOption.gotoLocation).multipleDefinitions;270}271}272273registerAction2(class GoToDefinitionAction extends DefinitionAction {274275static readonly id = 'editor.action.revealDefinition';276277constructor() {278super({279openToSide: false,280openInPeek: false,281muteMessage: false282}, {283id: GoToDefinitionAction.id,284title: {285...nls.localize2('actions.goToDecl.label', "Go to Definition"),286mnemonicTitle: nls.localize({ key: 'miGotoDefinition', comment: ['&& denotes a mnemonic'] }, "Go to &&Definition"),287},288precondition: EditorContextKeys.hasDefinitionProvider,289keybinding: [{290when: EditorContextKeys.editorTextFocus,291primary: KeyCode.F12,292weight: KeybindingWeight.EditorContrib293}, {294when: ContextKeyExpr.and(EditorContextKeys.editorTextFocus, IsWebContext),295primary: KeyMod.CtrlCmd | KeyCode.F12,296weight: KeybindingWeight.EditorContrib297}],298menu: [{299id: MenuId.EditorContext,300group: 'navigation',301order: 1.1302}, {303id: MenuId.MenubarGoMenu,304precondition: null,305group: '4_symbol_nav',306order: 2,307}]308});309CommandsRegistry.registerCommandAlias('editor.action.goToDeclaration', GoToDefinitionAction.id);310}311});312313registerAction2(class OpenDefinitionToSideAction extends DefinitionAction {314315static readonly id = 'editor.action.revealDefinitionAside';316317constructor() {318super({319openToSide: true,320openInPeek: false,321muteMessage: false322}, {323id: OpenDefinitionToSideAction.id,324title: nls.localize2('actions.goToDeclToSide.label', "Open Definition to the Side"),325precondition: ContextKeyExpr.and(326EditorContextKeys.hasDefinitionProvider,327EditorContextKeys.isInEmbeddedEditor.toNegated()),328keybinding: [{329when: EditorContextKeys.editorTextFocus,330primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyCode.F12),331weight: KeybindingWeight.EditorContrib332}, {333when: ContextKeyExpr.and(EditorContextKeys.editorTextFocus, IsWebContext),334primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.F12),335weight: KeybindingWeight.EditorContrib336}]337});338CommandsRegistry.registerCommandAlias('editor.action.openDeclarationToTheSide', OpenDefinitionToSideAction.id);339}340});341342registerAction2(class PeekDefinitionAction extends DefinitionAction {343344static readonly id = 'editor.action.peekDefinition';345346constructor() {347super({348openToSide: false,349openInPeek: true,350muteMessage: false351}, {352id: PeekDefinitionAction.id,353title: nls.localize2('actions.previewDecl.label', "Peek Definition"),354precondition: ContextKeyExpr.and(355EditorContextKeys.hasDefinitionProvider,356PeekContext.notInPeekEditor,357EditorContextKeys.isInEmbeddedEditor.toNegated()358),359keybinding: {360when: EditorContextKeys.editorTextFocus,361primary: KeyMod.Alt | KeyCode.F12,362linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.F10 },363weight: KeybindingWeight.EditorContrib364},365menu: {366id: MenuId.EditorContextPeek,367group: 'peek',368order: 2369}370});371CommandsRegistry.registerCommandAlias('editor.action.previewDeclaration', PeekDefinitionAction.id);372}373});374375//#endregion376377//#region --- DECLARATION378379class DeclarationAction extends SymbolNavigationAction {380381protected async _getLocationModel(languageFeaturesService: ILanguageFeaturesService, model: ITextModel, position: corePosition.Position, token: CancellationToken): Promise<ReferencesModel> {382return new ReferencesModel(await getDeclarationsAtPosition(languageFeaturesService.declarationProvider, model, position, false, token), nls.localize('decl.title', 'Declarations'));383}384385protected _getNoResultFoundMessage(info: IWordAtPosition | null): string {386return info && info.word387? nls.localize('decl.noResultWord', "No declaration found for '{0}'", info.word)388: nls.localize('decl.generic.noResults', "No declaration found");389}390391protected _getAlternativeCommand(editor: IActiveCodeEditor): string {392return editor.getOption(EditorOption.gotoLocation).alternativeDeclarationCommand;393}394395protected _getGoToPreference(editor: IActiveCodeEditor): GoToLocationValues {396return editor.getOption(EditorOption.gotoLocation).multipleDeclarations;397}398}399400registerAction2(class GoToDeclarationAction extends DeclarationAction {401402static readonly id = 'editor.action.revealDeclaration';403404constructor() {405super({406openToSide: false,407openInPeek: false,408muteMessage: false409}, {410id: GoToDeclarationAction.id,411title: {412...nls.localize2('actions.goToDeclaration.label', "Go to Declaration"),413mnemonicTitle: nls.localize({ key: 'miGotoDeclaration', comment: ['&& denotes a mnemonic'] }, "Go to &&Declaration"),414},415precondition: ContextKeyExpr.and(416EditorContextKeys.hasDeclarationProvider,417EditorContextKeys.isInEmbeddedEditor.toNegated()418),419menu: [{420id: MenuId.EditorContext,421group: 'navigation',422order: 1.3423}, {424id: MenuId.MenubarGoMenu,425precondition: null,426group: '4_symbol_nav',427order: 3,428}],429});430}431432protected override _getNoResultFoundMessage(info: IWordAtPosition | null): string {433return info && info.word434? nls.localize('decl.noResultWord', "No declaration found for '{0}'", info.word)435: nls.localize('decl.generic.noResults', "No declaration found");436}437});438439registerAction2(class PeekDeclarationAction extends DeclarationAction {440constructor() {441super({442openToSide: false,443openInPeek: true,444muteMessage: false445}, {446id: 'editor.action.peekDeclaration',447title: nls.localize2('actions.peekDecl.label', "Peek Declaration"),448precondition: ContextKeyExpr.and(449EditorContextKeys.hasDeclarationProvider,450PeekContext.notInPeekEditor,451EditorContextKeys.isInEmbeddedEditor.toNegated()452),453menu: {454id: MenuId.EditorContextPeek,455group: 'peek',456order: 3457}458});459}460});461462//#endregion463464//#region --- TYPE DEFINITION465466class TypeDefinitionAction extends SymbolNavigationAction {467468protected async _getLocationModel(languageFeaturesService: ILanguageFeaturesService, model: ITextModel, position: corePosition.Position, token: CancellationToken): Promise<ReferencesModel> {469return new ReferencesModel(await getTypeDefinitionsAtPosition(languageFeaturesService.typeDefinitionProvider, model, position, false, token), nls.localize('typedef.title', 'Type Definitions'));470}471472protected _getNoResultFoundMessage(info: IWordAtPosition | null): string {473return info && info.word474? nls.localize('goToTypeDefinition.noResultWord', "No type definition found for '{0}'", info.word)475: nls.localize('goToTypeDefinition.generic.noResults', "No type definition found");476}477478protected _getAlternativeCommand(editor: IActiveCodeEditor): string {479return editor.getOption(EditorOption.gotoLocation).alternativeTypeDefinitionCommand;480}481482protected _getGoToPreference(editor: IActiveCodeEditor): GoToLocationValues {483return editor.getOption(EditorOption.gotoLocation).multipleTypeDefinitions;484}485}486487registerAction2(class GoToTypeDefinitionAction extends TypeDefinitionAction {488489public static readonly ID = 'editor.action.goToTypeDefinition';490491constructor() {492super({493openToSide: false,494openInPeek: false,495muteMessage: false496}, {497id: GoToTypeDefinitionAction.ID,498title: {499...nls.localize2('actions.goToTypeDefinition.label', "Go to Type Definition"),500mnemonicTitle: nls.localize({ key: 'miGotoTypeDefinition', comment: ['&& denotes a mnemonic'] }, "Go to &&Type Definition"),501},502precondition: EditorContextKeys.hasTypeDefinitionProvider,503keybinding: {504when: EditorContextKeys.editorTextFocus,505primary: 0,506weight: KeybindingWeight.EditorContrib507},508menu: [{509id: MenuId.EditorContext,510group: 'navigation',511order: 1.4512}, {513id: MenuId.MenubarGoMenu,514precondition: null,515group: '4_symbol_nav',516order: 3,517}]518});519}520});521522registerAction2(class PeekTypeDefinitionAction extends TypeDefinitionAction {523524public static readonly ID = 'editor.action.peekTypeDefinition';525526constructor() {527super({528openToSide: false,529openInPeek: true,530muteMessage: false531}, {532id: PeekTypeDefinitionAction.ID,533title: nls.localize2('actions.peekTypeDefinition.label', "Peek Type Definition"),534precondition: ContextKeyExpr.and(535EditorContextKeys.hasTypeDefinitionProvider,536PeekContext.notInPeekEditor,537EditorContextKeys.isInEmbeddedEditor.toNegated()538),539menu: {540id: MenuId.EditorContextPeek,541group: 'peek',542order: 4543}544});545}546});547548//#endregion549550//#region --- IMPLEMENTATION551552class ImplementationAction extends SymbolNavigationAction {553554protected async _getLocationModel(languageFeaturesService: ILanguageFeaturesService, model: ITextModel, position: corePosition.Position, token: CancellationToken): Promise<ReferencesModel> {555return new ReferencesModel(await getImplementationsAtPosition(languageFeaturesService.implementationProvider, model, position, false, token), nls.localize('impl.title', 'Implementations'));556}557558protected _getNoResultFoundMessage(info: IWordAtPosition | null): string {559return info && info.word560? nls.localize('goToImplementation.noResultWord', "No implementation found for '{0}'", info.word)561: nls.localize('goToImplementation.generic.noResults', "No implementation found");562}563564protected _getAlternativeCommand(editor: IActiveCodeEditor): string {565return editor.getOption(EditorOption.gotoLocation).alternativeImplementationCommand;566}567568protected _getGoToPreference(editor: IActiveCodeEditor): GoToLocationValues {569return editor.getOption(EditorOption.gotoLocation).multipleImplementations;570}571}572573registerAction2(class GoToImplementationAction extends ImplementationAction {574575public static readonly ID = 'editor.action.goToImplementation';576577constructor() {578super({579openToSide: false,580openInPeek: false,581muteMessage: false582}, {583id: GoToImplementationAction.ID,584title: {585...nls.localize2('actions.goToImplementation.label', "Go to Implementations"),586mnemonicTitle: nls.localize({ key: 'miGotoImplementation', comment: ['&& denotes a mnemonic'] }, "Go to &&Implementations"),587},588precondition: EditorContextKeys.hasImplementationProvider,589keybinding: {590when: EditorContextKeys.editorTextFocus,591primary: KeyMod.CtrlCmd | KeyCode.F12,592weight: KeybindingWeight.EditorContrib593},594menu: [{595id: MenuId.EditorContext,596group: 'navigation',597order: 1.45598}, {599id: MenuId.MenubarGoMenu,600precondition: null,601group: '4_symbol_nav',602order: 4,603}]604});605}606});607608registerAction2(class PeekImplementationAction extends ImplementationAction {609610public static readonly ID = 'editor.action.peekImplementation';611612constructor() {613super({614openToSide: false,615openInPeek: true,616muteMessage: false617}, {618id: PeekImplementationAction.ID,619title: nls.localize2('actions.peekImplementation.label', "Peek Implementations"),620precondition: ContextKeyExpr.and(621EditorContextKeys.hasImplementationProvider,622PeekContext.notInPeekEditor,623EditorContextKeys.isInEmbeddedEditor.toNegated()624),625keybinding: {626when: EditorContextKeys.editorTextFocus,627primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.F12,628weight: KeybindingWeight.EditorContrib629},630menu: {631id: MenuId.EditorContextPeek,632group: 'peek',633order: 5634}635});636}637});638639//#endregion640641//#region --- REFERENCES642643abstract class ReferencesAction extends SymbolNavigationAction {644645protected _getNoResultFoundMessage(info: IWordAtPosition | null): string {646return info647? nls.localize('references.no', "No references found for '{0}'", info.word)648: nls.localize('references.noGeneric', "No references found");649}650651protected _getAlternativeCommand(editor: IActiveCodeEditor): string {652return editor.getOption(EditorOption.gotoLocation).alternativeReferenceCommand;653}654655protected _getGoToPreference(editor: IActiveCodeEditor): GoToLocationValues {656return editor.getOption(EditorOption.gotoLocation).multipleReferences;657}658}659660registerAction2(class GoToReferencesAction extends ReferencesAction {661662constructor() {663super({664openToSide: false,665openInPeek: false,666muteMessage: false667}, {668id: 'editor.action.goToReferences',669title: {670...nls.localize2('goToReferences.label', "Go to References"),671mnemonicTitle: nls.localize({ key: 'miGotoReference', comment: ['&& denotes a mnemonic'] }, "Go to &&References"),672},673precondition: ContextKeyExpr.and(674EditorContextKeys.hasReferenceProvider,675PeekContext.notInPeekEditor,676EditorContextKeys.isInEmbeddedEditor.toNegated()677),678keybinding: {679when: EditorContextKeys.editorTextFocus,680primary: KeyMod.Shift | KeyCode.F12,681weight: KeybindingWeight.EditorContrib682},683menu: [{684id: MenuId.EditorContext,685group: 'navigation',686order: 1.45687}, {688id: MenuId.MenubarGoMenu,689precondition: null,690group: '4_symbol_nav',691order: 5,692}]693});694}695696protected async _getLocationModel(languageFeaturesService: ILanguageFeaturesService, model: ITextModel, position: corePosition.Position, token: CancellationToken): Promise<ReferencesModel> {697return new ReferencesModel(await getReferencesAtPosition(languageFeaturesService.referenceProvider, model, position, true, false, token), nls.localize('ref.title', 'References'));698}699});700701registerAction2(class PeekReferencesAction extends ReferencesAction {702703constructor() {704super({705openToSide: false,706openInPeek: true,707muteMessage: false708}, {709id: 'editor.action.referenceSearch.trigger',710title: nls.localize2('references.action.label', "Peek References"),711precondition: ContextKeyExpr.and(712EditorContextKeys.hasReferenceProvider,713PeekContext.notInPeekEditor,714EditorContextKeys.isInEmbeddedEditor.toNegated()715),716menu: {717id: MenuId.EditorContextPeek,718group: 'peek',719order: 6720}721});722}723724protected async _getLocationModel(languageFeaturesService: ILanguageFeaturesService, model: ITextModel, position: corePosition.Position, token: CancellationToken): Promise<ReferencesModel> {725return new ReferencesModel(await getReferencesAtPosition(languageFeaturesService.referenceProvider, model, position, false, false, token), nls.localize('ref.title', 'References'));726}727});728729//#endregion730731732//#region --- GENERIC goto symbols command733734class GenericGoToLocationAction extends SymbolNavigationAction {735736constructor(737config: SymbolNavigationActionConfig,738private readonly _references: Location[],739private readonly _gotoMultipleBehaviour: GoToLocationValues | undefined,740) {741super(config, {742id: 'editor.action.goToLocation',743title: nls.localize2('label.generic', "Go to Any Symbol"),744precondition: ContextKeyExpr.and(745PeekContext.notInPeekEditor,746EditorContextKeys.isInEmbeddedEditor.toNegated()747),748});749}750751protected async _getLocationModel(languageFeaturesService: ILanguageFeaturesService, _model: ITextModel, _position: corePosition.Position, _token: CancellationToken): Promise<ReferencesModel | undefined> {752return new ReferencesModel(this._references, nls.localize('generic.title', 'Locations'));753}754755protected _getNoResultFoundMessage(info: IWordAtPosition | null): string {756return info && nls.localize('generic.noResult', "No results for '{0}'", info.word) || '';757}758759protected _getGoToPreference(editor: IActiveCodeEditor): GoToLocationValues {760return this._gotoMultipleBehaviour ?? editor.getOption(EditorOption.gotoLocation).multipleReferences;761}762763protected _getAlternativeCommand(): undefined {764return undefined;765}766}767768CommandsRegistry.registerCommand({769id: 'editor.action.goToLocations',770metadata: {771description: 'Go to locations from a position in a file',772args: [773{ name: 'uri', description: 'The text document in which to start', constraint: URI },774{ name: 'position', description: 'The position at which to start', constraint: corePosition.Position.isIPosition },775{ name: 'locations', description: 'An array of locations.', constraint: Array },776{ name: 'multiple', description: 'Define what to do when having multiple results, either `peek`, `gotoAndPeek`, or `goto`' },777{ name: 'noResultsMessage', description: 'Human readable message that shows when locations is empty.' },778]779},780handler: async (accessor: ServicesAccessor, resource: any, position: any, references: any, multiple?: any, noResultsMessage?: string, openInPeek?: boolean) => {781assertType(URI.isUri(resource));782assertType(corePosition.Position.isIPosition(position));783assertType(Array.isArray(references));784assertType(typeof multiple === 'undefined' || typeof multiple === 'string');785assertType(typeof openInPeek === 'undefined' || typeof openInPeek === 'boolean');786787const editorService = accessor.get(ICodeEditorService);788const editor = await editorService.openCodeEditor({ resource }, editorService.getFocusedCodeEditor());789790if (isCodeEditor(editor)) {791editor.setPosition(position);792editor.revealPositionInCenterIfOutsideViewport(position, ScrollType.Smooth);793794return editor.invokeWithinContext(accessor => {795const command = new class extends GenericGoToLocationAction {796protected override _getNoResultFoundMessage(info: IWordAtPosition | null) {797return noResultsMessage || super._getNoResultFoundMessage(info);798}799}({800muteMessage: !Boolean(noResultsMessage),801openInPeek: Boolean(openInPeek),802openToSide: false803}, references, multiple as GoToLocationValues);804805accessor.get(IInstantiationService).invokeFunction(command.run.bind(command), editor);806});807}808}809});810811CommandsRegistry.registerCommand({812id: 'editor.action.peekLocations',813metadata: {814description: 'Peek locations from a position in a file',815args: [816{ name: 'uri', description: 'The text document in which to start', constraint: URI },817{ name: 'position', description: 'The position at which to start', constraint: corePosition.Position.isIPosition },818{ name: 'locations', description: 'An array of locations.', constraint: Array },819{ name: 'multiple', description: 'Define what to do when having multiple results, either `peek`, `gotoAndPeek`, or `goto`' },820]821},822handler: async (accessor: ServicesAccessor, resource: any, position: any, references: any, multiple?: any) => {823accessor.get(ICommandService).executeCommand('editor.action.goToLocations', resource, position, references, multiple, undefined, true);824}825});826827//#endregion828829830//#region --- REFERENCE search special commands831832CommandsRegistry.registerCommand({833id: 'editor.action.findReferences',834handler: (accessor: ServicesAccessor, resource: any, position: any) => {835assertType(URI.isUri(resource));836assertType(corePosition.Position.isIPosition(position));837838const languageFeaturesService = accessor.get(ILanguageFeaturesService);839const codeEditorService = accessor.get(ICodeEditorService);840return codeEditorService.openCodeEditor({ resource }, codeEditorService.getFocusedCodeEditor()).then(control => {841if (!isCodeEditor(control) || !control.hasModel()) {842return undefined;843}844845const controller = ReferencesController.get(control);846if (!controller) {847return undefined;848}849850const references = createCancelablePromise(token => getReferencesAtPosition(languageFeaturesService.referenceProvider, control.getModel(), corePosition.Position.lift(position), false, false, token).then(references => new ReferencesModel(references, nls.localize('ref.title', 'References'))));851const range = new Range(position.lineNumber, position.column, position.lineNumber, position.column);852return Promise.resolve(controller.toggleWidget(range, references, false));853});854}855});856857// use NEW command858CommandsRegistry.registerCommandAlias('editor.action.showReferences', 'editor.action.peekLocations');859860//#endregion861862863