monaco-editor-core
Version:
A browser based code editor
690 lines (689 loc) • 32.9 kB
JavaScript
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { alert } from '../../../../base/browser/ui/aria/aria.js';
import { createCancelablePromise, raceCancellation } from '../../../../base/common/async.js';
import { KeyChord } from '../../../../base/common/keyCodes.js';
import { assertType } from '../../../../base/common/types.js';
import { URI } from '../../../../base/common/uri.js';
import { EditorStateCancellationTokenSource } from '../../editorState/browser/editorState.js';
import { isCodeEditor } from '../../../browser/editorBrowser.js';
import { EditorAction2 } from '../../../browser/editorExtensions.js';
import { ICodeEditorService } from '../../../browser/services/codeEditorService.js';
import { EmbeddedCodeEditorWidget } from '../../../browser/widget/codeEditor/embeddedCodeEditorWidget.js';
import * as corePosition from '../../../common/core/position.js';
import { Range } from '../../../common/core/range.js';
import { EditorContextKeys } from '../../../common/editorContextKeys.js';
import { isLocationLink } from '../../../common/languages.js';
import { ReferencesController } from './peek/referencesController.js';
import { ReferencesModel } from './referencesModel.js';
import { ISymbolNavigationService } from './symbolNavigation.js';
import { MessageController } from '../../message/browser/messageController.js';
import { PeekContext } from '../../peekView/browser/peekView.js';
import * as nls from '../../../../nls.js';
import { MenuId, MenuRegistry, registerAction2 } from '../../../../platform/actions/common/actions.js';
import { CommandsRegistry, ICommandService } from '../../../../platform/commands/common/commands.js';
import { ContextKeyExpr } from '../../../../platform/contextkey/common/contextkey.js';
import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js';
import { INotificationService } from '../../../../platform/notification/common/notification.js';
import { IEditorProgressService } from '../../../../platform/progress/common/progress.js';
import { getDeclarationsAtPosition, getDefinitionsAtPosition, getImplementationsAtPosition, getReferencesAtPosition, getTypeDefinitionsAtPosition } from './goToSymbol.js';
import { ILanguageFeaturesService } from '../../../common/services/languageFeatures.js';
import { Iterable } from '../../../../base/common/iterator.js';
import { IsWebContext } from '../../../../platform/contextkey/common/contextkeys.js';
MenuRegistry.appendMenuItem(MenuId.EditorContext, {
submenu: MenuId.EditorContextPeek,
title: nls.localize('peek.submenu', "Peek"),
group: 'navigation',
order: 100
});
export class SymbolNavigationAnchor {
static is(thing) {
if (!thing || typeof thing !== 'object') {
return false;
}
if (thing instanceof SymbolNavigationAnchor) {
return true;
}
if (corePosition.Position.isIPosition(thing.position) && thing.model) {
return true;
}
return false;
}
constructor(model, position) {
this.model = model;
this.position = position;
}
}
export class SymbolNavigationAction extends EditorAction2 {
static { this._allSymbolNavigationCommands = new Map(); }
static { this._activeAlternativeCommands = new Set(); }
static all() {
return SymbolNavigationAction._allSymbolNavigationCommands.values();
}
static _patchConfig(opts) {
const result = { ...opts, f1: true };
// patch context menu when clause
if (result.menu) {
for (const item of Iterable.wrap(result.menu)) {
if (item.id === MenuId.EditorContext || item.id === MenuId.EditorContextPeek) {
item.when = ContextKeyExpr.and(opts.precondition, item.when);
}
}
}
return result;
}
constructor(configuration, opts) {
super(SymbolNavigationAction._patchConfig(opts));
this.configuration = configuration;
SymbolNavigationAction._allSymbolNavigationCommands.set(opts.id, this);
}
runEditorCommand(accessor, editor, arg, range) {
if (!editor.hasModel()) {
return Promise.resolve(undefined);
}
const notificationService = accessor.get(INotificationService);
const editorService = accessor.get(ICodeEditorService);
const progressService = accessor.get(IEditorProgressService);
const symbolNavService = accessor.get(ISymbolNavigationService);
const languageFeaturesService = accessor.get(ILanguageFeaturesService);
const instaService = accessor.get(IInstantiationService);
const model = editor.getModel();
const position = editor.getPosition();
const anchor = SymbolNavigationAnchor.is(arg) ? arg : new SymbolNavigationAnchor(model, position);
const cts = new EditorStateCancellationTokenSource(editor, 1 /* CodeEditorStateFlag.Value */ | 4 /* CodeEditorStateFlag.Position */);
const promise = raceCancellation(this._getLocationModel(languageFeaturesService, anchor.model, anchor.position, cts.token), cts.token).then(async (references) => {
if (!references || cts.token.isCancellationRequested) {
return;
}
alert(references.ariaMessage);
let altAction;
if (references.referenceAt(model.uri, position)) {
const altActionId = this._getAlternativeCommand(editor);
if (!SymbolNavigationAction._activeAlternativeCommands.has(altActionId) && SymbolNavigationAction._allSymbolNavigationCommands.has(altActionId)) {
altAction = SymbolNavigationAction._allSymbolNavigationCommands.get(altActionId);
}
}
const referenceCount = references.references.length;
if (referenceCount === 0) {
// no result -> show message
if (!this.configuration.muteMessage) {
const info = model.getWordAtPosition(position);
MessageController.get(editor)?.showMessage(this._getNoResultFoundMessage(info), position);
}
}
else if (referenceCount === 1 && altAction) {
// already at the only result, run alternative
SymbolNavigationAction._activeAlternativeCommands.add(this.desc.id);
instaService.invokeFunction((accessor) => altAction.runEditorCommand(accessor, editor, arg, range).finally(() => {
SymbolNavigationAction._activeAlternativeCommands.delete(this.desc.id);
}));
}
else {
// normal results handling
return this._onResult(editorService, symbolNavService, editor, references, range);
}
}, (err) => {
// report an error
notificationService.error(err);
}).finally(() => {
cts.dispose();
});
progressService.showWhile(promise, 250);
return promise;
}
async _onResult(editorService, symbolNavService, editor, model, range) {
const gotoLocation = this._getGoToPreference(editor);
if (!(editor instanceof EmbeddedCodeEditorWidget) && (this.configuration.openInPeek || (gotoLocation === 'peek' && model.references.length > 1))) {
this._openInPeek(editor, model, range);
}
else {
const next = model.firstReference();
const peek = model.references.length > 1 && gotoLocation === 'gotoAndPeek';
const targetEditor = await this._openReference(editor, editorService, next, this.configuration.openToSide, !peek);
if (peek && targetEditor) {
this._openInPeek(targetEditor, model, range);
}
else {
model.dispose();
}
// keep remaining locations around when using
// 'goto'-mode
if (gotoLocation === 'goto') {
symbolNavService.put(next);
}
}
}
async _openReference(editor, editorService, reference, sideBySide, highlight) {
// range is the target-selection-range when we have one
// and the fallback is the 'full' range
let range = undefined;
if (isLocationLink(reference)) {
range = reference.targetSelectionRange;
}
if (!range) {
range = reference.range;
}
if (!range) {
return undefined;
}
const targetEditor = await editorService.openCodeEditor({
resource: reference.uri,
options: {
selection: Range.collapseToStart(range),
selectionRevealType: 3 /* TextEditorSelectionRevealType.NearTopIfOutsideViewport */,
selectionSource: "code.jump" /* TextEditorSelectionSource.JUMP */
}
}, editor, sideBySide);
if (!targetEditor) {
return undefined;
}
if (highlight) {
const modelNow = targetEditor.getModel();
const decorations = targetEditor.createDecorationsCollection([{ range, options: { description: 'symbol-navigate-action-highlight', className: 'symbolHighlight' } }]);
setTimeout(() => {
if (targetEditor.getModel() === modelNow) {
decorations.clear();
}
}, 350);
}
return targetEditor;
}
_openInPeek(target, model, range) {
const controller = ReferencesController.get(target);
if (controller && target.hasModel()) {
controller.toggleWidget(range ?? target.getSelection(), createCancelablePromise(_ => Promise.resolve(model)), this.configuration.openInPeek);
}
else {
model.dispose();
}
}
}
//#region --- DEFINITION
export class DefinitionAction extends SymbolNavigationAction {
async _getLocationModel(languageFeaturesService, model, position, token) {
return new ReferencesModel(await getDefinitionsAtPosition(languageFeaturesService.definitionProvider, model, position, false, token), nls.localize('def.title', 'Definitions'));
}
_getNoResultFoundMessage(info) {
return info && info.word
? nls.localize('noResultWord', "No definition found for '{0}'", info.word)
: nls.localize('generic.noResults', "No definition found");
}
_getAlternativeCommand(editor) {
return editor.getOption(58 /* EditorOption.gotoLocation */).alternativeDefinitionCommand;
}
_getGoToPreference(editor) {
return editor.getOption(58 /* EditorOption.gotoLocation */).multipleDefinitions;
}
}
registerAction2(class GoToDefinitionAction extends DefinitionAction {
static { this.id = 'editor.action.revealDefinition'; }
constructor() {
super({
openToSide: false,
openInPeek: false,
muteMessage: false
}, {
id: GoToDefinitionAction.id,
title: {
...nls.localize2('actions.goToDecl.label', "Go to Definition"),
mnemonicTitle: nls.localize({ key: 'miGotoDefinition', comment: ['&& denotes a mnemonic'] }, "Go to &&Definition"),
},
precondition: EditorContextKeys.hasDefinitionProvider,
keybinding: [{
when: EditorContextKeys.editorTextFocus,
primary: 70 /* KeyCode.F12 */,
weight: 100 /* KeybindingWeight.EditorContrib */
}, {
when: ContextKeyExpr.and(EditorContextKeys.editorTextFocus, IsWebContext),
primary: 2048 /* KeyMod.CtrlCmd */ | 70 /* KeyCode.F12 */,
weight: 100 /* KeybindingWeight.EditorContrib */
}],
menu: [{
id: MenuId.EditorContext,
group: 'navigation',
order: 1.1
}, {
id: MenuId.MenubarGoMenu,
precondition: null,
group: '4_symbol_nav',
order: 2,
}]
});
CommandsRegistry.registerCommandAlias('editor.action.goToDeclaration', GoToDefinitionAction.id);
}
});
registerAction2(class OpenDefinitionToSideAction extends DefinitionAction {
static { this.id = 'editor.action.revealDefinitionAside'; }
constructor() {
super({
openToSide: true,
openInPeek: false,
muteMessage: false
}, {
id: OpenDefinitionToSideAction.id,
title: nls.localize2('actions.goToDeclToSide.label', "Open Definition to the Side"),
precondition: ContextKeyExpr.and(EditorContextKeys.hasDefinitionProvider, EditorContextKeys.isInEmbeddedEditor.toNegated()),
keybinding: [{
when: EditorContextKeys.editorTextFocus,
primary: KeyChord(2048 /* KeyMod.CtrlCmd */ | 41 /* KeyCode.KeyK */, 70 /* KeyCode.F12 */),
weight: 100 /* KeybindingWeight.EditorContrib */
}, {
when: ContextKeyExpr.and(EditorContextKeys.editorTextFocus, IsWebContext),
primary: KeyChord(2048 /* KeyMod.CtrlCmd */ | 41 /* KeyCode.KeyK */, 2048 /* KeyMod.CtrlCmd */ | 70 /* KeyCode.F12 */),
weight: 100 /* KeybindingWeight.EditorContrib */
}]
});
CommandsRegistry.registerCommandAlias('editor.action.openDeclarationToTheSide', OpenDefinitionToSideAction.id);
}
});
registerAction2(class PeekDefinitionAction extends DefinitionAction {
static { this.id = 'editor.action.peekDefinition'; }
constructor() {
super({
openToSide: false,
openInPeek: true,
muteMessage: false
}, {
id: PeekDefinitionAction.id,
title: nls.localize2('actions.previewDecl.label', "Peek Definition"),
precondition: ContextKeyExpr.and(EditorContextKeys.hasDefinitionProvider, PeekContext.notInPeekEditor, EditorContextKeys.isInEmbeddedEditor.toNegated()),
keybinding: {
when: EditorContextKeys.editorTextFocus,
primary: 512 /* KeyMod.Alt */ | 70 /* KeyCode.F12 */,
linux: { primary: 2048 /* KeyMod.CtrlCmd */ | 1024 /* KeyMod.Shift */ | 68 /* KeyCode.F10 */ },
weight: 100 /* KeybindingWeight.EditorContrib */
},
menu: {
id: MenuId.EditorContextPeek,
group: 'peek',
order: 2
}
});
CommandsRegistry.registerCommandAlias('editor.action.previewDeclaration', PeekDefinitionAction.id);
}
});
//#endregion
//#region --- DECLARATION
class DeclarationAction extends SymbolNavigationAction {
async _getLocationModel(languageFeaturesService, model, position, token) {
return new ReferencesModel(await getDeclarationsAtPosition(languageFeaturesService.declarationProvider, model, position, false, token), nls.localize('decl.title', 'Declarations'));
}
_getNoResultFoundMessage(info) {
return info && info.word
? nls.localize('decl.noResultWord', "No declaration found for '{0}'", info.word)
: nls.localize('decl.generic.noResults', "No declaration found");
}
_getAlternativeCommand(editor) {
return editor.getOption(58 /* EditorOption.gotoLocation */).alternativeDeclarationCommand;
}
_getGoToPreference(editor) {
return editor.getOption(58 /* EditorOption.gotoLocation */).multipleDeclarations;
}
}
registerAction2(class GoToDeclarationAction extends DeclarationAction {
static { this.id = 'editor.action.revealDeclaration'; }
constructor() {
super({
openToSide: false,
openInPeek: false,
muteMessage: false
}, {
id: GoToDeclarationAction.id,
title: {
...nls.localize2('actions.goToDeclaration.label', "Go to Declaration"),
mnemonicTitle: nls.localize({ key: 'miGotoDeclaration', comment: ['&& denotes a mnemonic'] }, "Go to &&Declaration"),
},
precondition: ContextKeyExpr.and(EditorContextKeys.hasDeclarationProvider, EditorContextKeys.isInEmbeddedEditor.toNegated()),
menu: [{
id: MenuId.EditorContext,
group: 'navigation',
order: 1.3
}, {
id: MenuId.MenubarGoMenu,
precondition: null,
group: '4_symbol_nav',
order: 3,
}],
});
}
_getNoResultFoundMessage(info) {
return info && info.word
? nls.localize('decl.noResultWord', "No declaration found for '{0}'", info.word)
: nls.localize('decl.generic.noResults', "No declaration found");
}
});
registerAction2(class PeekDeclarationAction extends DeclarationAction {
constructor() {
super({
openToSide: false,
openInPeek: true,
muteMessage: false
}, {
id: 'editor.action.peekDeclaration',
title: nls.localize2('actions.peekDecl.label', "Peek Declaration"),
precondition: ContextKeyExpr.and(EditorContextKeys.hasDeclarationProvider, PeekContext.notInPeekEditor, EditorContextKeys.isInEmbeddedEditor.toNegated()),
menu: {
id: MenuId.EditorContextPeek,
group: 'peek',
order: 3
}
});
}
});
//#endregion
//#region --- TYPE DEFINITION
class TypeDefinitionAction extends SymbolNavigationAction {
async _getLocationModel(languageFeaturesService, model, position, token) {
return new ReferencesModel(await getTypeDefinitionsAtPosition(languageFeaturesService.typeDefinitionProvider, model, position, false, token), nls.localize('typedef.title', 'Type Definitions'));
}
_getNoResultFoundMessage(info) {
return info && info.word
? nls.localize('goToTypeDefinition.noResultWord', "No type definition found for '{0}'", info.word)
: nls.localize('goToTypeDefinition.generic.noResults', "No type definition found");
}
_getAlternativeCommand(editor) {
return editor.getOption(58 /* EditorOption.gotoLocation */).alternativeTypeDefinitionCommand;
}
_getGoToPreference(editor) {
return editor.getOption(58 /* EditorOption.gotoLocation */).multipleTypeDefinitions;
}
}
registerAction2(class GoToTypeDefinitionAction extends TypeDefinitionAction {
static { this.ID = 'editor.action.goToTypeDefinition'; }
constructor() {
super({
openToSide: false,
openInPeek: false,
muteMessage: false
}, {
id: GoToTypeDefinitionAction.ID,
title: {
...nls.localize2('actions.goToTypeDefinition.label', "Go to Type Definition"),
mnemonicTitle: nls.localize({ key: 'miGotoTypeDefinition', comment: ['&& denotes a mnemonic'] }, "Go to &&Type Definition"),
},
precondition: EditorContextKeys.hasTypeDefinitionProvider,
keybinding: {
when: EditorContextKeys.editorTextFocus,
primary: 0,
weight: 100 /* KeybindingWeight.EditorContrib */
},
menu: [{
id: MenuId.EditorContext,
group: 'navigation',
order: 1.4
}, {
id: MenuId.MenubarGoMenu,
precondition: null,
group: '4_symbol_nav',
order: 3,
}]
});
}
});
registerAction2(class PeekTypeDefinitionAction extends TypeDefinitionAction {
static { this.ID = 'editor.action.peekTypeDefinition'; }
constructor() {
super({
openToSide: false,
openInPeek: true,
muteMessage: false
}, {
id: PeekTypeDefinitionAction.ID,
title: nls.localize2('actions.peekTypeDefinition.label', "Peek Type Definition"),
precondition: ContextKeyExpr.and(EditorContextKeys.hasTypeDefinitionProvider, PeekContext.notInPeekEditor, EditorContextKeys.isInEmbeddedEditor.toNegated()),
menu: {
id: MenuId.EditorContextPeek,
group: 'peek',
order: 4
}
});
}
});
//#endregion
//#region --- IMPLEMENTATION
class ImplementationAction extends SymbolNavigationAction {
async _getLocationModel(languageFeaturesService, model, position, token) {
return new ReferencesModel(await getImplementationsAtPosition(languageFeaturesService.implementationProvider, model, position, false, token), nls.localize('impl.title', 'Implementations'));
}
_getNoResultFoundMessage(info) {
return info && info.word
? nls.localize('goToImplementation.noResultWord', "No implementation found for '{0}'", info.word)
: nls.localize('goToImplementation.generic.noResults', "No implementation found");
}
_getAlternativeCommand(editor) {
return editor.getOption(58 /* EditorOption.gotoLocation */).alternativeImplementationCommand;
}
_getGoToPreference(editor) {
return editor.getOption(58 /* EditorOption.gotoLocation */).multipleImplementations;
}
}
registerAction2(class GoToImplementationAction extends ImplementationAction {
static { this.ID = 'editor.action.goToImplementation'; }
constructor() {
super({
openToSide: false,
openInPeek: false,
muteMessage: false
}, {
id: GoToImplementationAction.ID,
title: {
...nls.localize2('actions.goToImplementation.label', "Go to Implementations"),
mnemonicTitle: nls.localize({ key: 'miGotoImplementation', comment: ['&& denotes a mnemonic'] }, "Go to &&Implementations"),
},
precondition: EditorContextKeys.hasImplementationProvider,
keybinding: {
when: EditorContextKeys.editorTextFocus,
primary: 2048 /* KeyMod.CtrlCmd */ | 70 /* KeyCode.F12 */,
weight: 100 /* KeybindingWeight.EditorContrib */
},
menu: [{
id: MenuId.EditorContext,
group: 'navigation',
order: 1.45
}, {
id: MenuId.MenubarGoMenu,
precondition: null,
group: '4_symbol_nav',
order: 4,
}]
});
}
});
registerAction2(class PeekImplementationAction extends ImplementationAction {
static { this.ID = 'editor.action.peekImplementation'; }
constructor() {
super({
openToSide: false,
openInPeek: true,
muteMessage: false
}, {
id: PeekImplementationAction.ID,
title: nls.localize2('actions.peekImplementation.label', "Peek Implementations"),
precondition: ContextKeyExpr.and(EditorContextKeys.hasImplementationProvider, PeekContext.notInPeekEditor, EditorContextKeys.isInEmbeddedEditor.toNegated()),
keybinding: {
when: EditorContextKeys.editorTextFocus,
primary: 2048 /* KeyMod.CtrlCmd */ | 1024 /* KeyMod.Shift */ | 70 /* KeyCode.F12 */,
weight: 100 /* KeybindingWeight.EditorContrib */
},
menu: {
id: MenuId.EditorContextPeek,
group: 'peek',
order: 5
}
});
}
});
//#endregion
//#region --- REFERENCES
class ReferencesAction extends SymbolNavigationAction {
_getNoResultFoundMessage(info) {
return info
? nls.localize('references.no', "No references found for '{0}'", info.word)
: nls.localize('references.noGeneric', "No references found");
}
_getAlternativeCommand(editor) {
return editor.getOption(58 /* EditorOption.gotoLocation */).alternativeReferenceCommand;
}
_getGoToPreference(editor) {
return editor.getOption(58 /* EditorOption.gotoLocation */).multipleReferences;
}
}
registerAction2(class GoToReferencesAction extends ReferencesAction {
constructor() {
super({
openToSide: false,
openInPeek: false,
muteMessage: false
}, {
id: 'editor.action.goToReferences',
title: {
...nls.localize2('goToReferences.label', "Go to References"),
mnemonicTitle: nls.localize({ key: 'miGotoReference', comment: ['&& denotes a mnemonic'] }, "Go to &&References"),
},
precondition: ContextKeyExpr.and(EditorContextKeys.hasReferenceProvider, PeekContext.notInPeekEditor, EditorContextKeys.isInEmbeddedEditor.toNegated()),
keybinding: {
when: EditorContextKeys.editorTextFocus,
primary: 1024 /* KeyMod.Shift */ | 70 /* KeyCode.F12 */,
weight: 100 /* KeybindingWeight.EditorContrib */
},
menu: [{
id: MenuId.EditorContext,
group: 'navigation',
order: 1.45
}, {
id: MenuId.MenubarGoMenu,
precondition: null,
group: '4_symbol_nav',
order: 5,
}]
});
}
async _getLocationModel(languageFeaturesService, model, position, token) {
return new ReferencesModel(await getReferencesAtPosition(languageFeaturesService.referenceProvider, model, position, true, false, token), nls.localize('ref.title', 'References'));
}
});
registerAction2(class PeekReferencesAction extends ReferencesAction {
constructor() {
super({
openToSide: false,
openInPeek: true,
muteMessage: false
}, {
id: 'editor.action.referenceSearch.trigger',
title: nls.localize2('references.action.label', "Peek References"),
precondition: ContextKeyExpr.and(EditorContextKeys.hasReferenceProvider, PeekContext.notInPeekEditor, EditorContextKeys.isInEmbeddedEditor.toNegated()),
menu: {
id: MenuId.EditorContextPeek,
group: 'peek',
order: 6
}
});
}
async _getLocationModel(languageFeaturesService, model, position, token) {
return new ReferencesModel(await getReferencesAtPosition(languageFeaturesService.referenceProvider, model, position, false, false, token), nls.localize('ref.title', 'References'));
}
});
//#endregion
//#region --- GENERIC goto symbols command
class GenericGoToLocationAction extends SymbolNavigationAction {
constructor(config, _references, _gotoMultipleBehaviour) {
super(config, {
id: 'editor.action.goToLocation',
title: nls.localize2('label.generic', "Go to Any Symbol"),
precondition: ContextKeyExpr.and(PeekContext.notInPeekEditor, EditorContextKeys.isInEmbeddedEditor.toNegated()),
});
this._references = _references;
this._gotoMultipleBehaviour = _gotoMultipleBehaviour;
}
async _getLocationModel(languageFeaturesService, _model, _position, _token) {
return new ReferencesModel(this._references, nls.localize('generic.title', 'Locations'));
}
_getNoResultFoundMessage(info) {
return info && nls.localize('generic.noResult', "No results for '{0}'", info.word) || '';
}
_getGoToPreference(editor) {
return this._gotoMultipleBehaviour ?? editor.getOption(58 /* EditorOption.gotoLocation */).multipleReferences;
}
_getAlternativeCommand() { return ''; }
}
CommandsRegistry.registerCommand({
id: 'editor.action.goToLocations',
metadata: {
description: 'Go to locations from a position in a file',
args: [
{ name: 'uri', description: 'The text document in which to start', constraint: URI },
{ name: 'position', description: 'The position at which to start', constraint: corePosition.Position.isIPosition },
{ name: 'locations', description: 'An array of locations.', constraint: Array },
{ name: 'multiple', description: 'Define what to do when having multiple results, either `peek`, `gotoAndPeek`, or `goto`' },
{ name: 'noResultsMessage', description: 'Human readable message that shows when locations is empty.' },
]
},
handler: async (accessor, resource, position, references, multiple, noResultsMessage, openInPeek) => {
assertType(URI.isUri(resource));
assertType(corePosition.Position.isIPosition(position));
assertType(Array.isArray(references));
assertType(typeof multiple === 'undefined' || typeof multiple === 'string');
assertType(typeof openInPeek === 'undefined' || typeof openInPeek === 'boolean');
const editorService = accessor.get(ICodeEditorService);
const editor = await editorService.openCodeEditor({ resource }, editorService.getFocusedCodeEditor());
if (isCodeEditor(editor)) {
editor.setPosition(position);
editor.revealPositionInCenterIfOutsideViewport(position, 0 /* ScrollType.Smooth */);
return editor.invokeWithinContext(accessor => {
const command = new class extends GenericGoToLocationAction {
_getNoResultFoundMessage(info) {
return noResultsMessage || super._getNoResultFoundMessage(info);
}
}({
muteMessage: !Boolean(noResultsMessage),
openInPeek: Boolean(openInPeek),
openToSide: false
}, references, multiple);
accessor.get(IInstantiationService).invokeFunction(command.run.bind(command), editor);
});
}
}
});
CommandsRegistry.registerCommand({
id: 'editor.action.peekLocations',
metadata: {
description: 'Peek locations from a position in a file',
args: [
{ name: 'uri', description: 'The text document in which to start', constraint: URI },
{ name: 'position', description: 'The position at which to start', constraint: corePosition.Position.isIPosition },
{ name: 'locations', description: 'An array of locations.', constraint: Array },
{ name: 'multiple', description: 'Define what to do when having multiple results, either `peek`, `gotoAndPeek`, or `goto`' },
]
},
handler: async (accessor, resource, position, references, multiple) => {
accessor.get(ICommandService).executeCommand('editor.action.goToLocations', resource, position, references, multiple, undefined, true);
}
});
//#endregion
//#region --- REFERENCE search special commands
CommandsRegistry.registerCommand({
id: 'editor.action.findReferences',
handler: (accessor, resource, position) => {
assertType(URI.isUri(resource));
assertType(corePosition.Position.isIPosition(position));
const languageFeaturesService = accessor.get(ILanguageFeaturesService);
const codeEditorService = accessor.get(ICodeEditorService);
return codeEditorService.openCodeEditor({ resource }, codeEditorService.getFocusedCodeEditor()).then(control => {
if (!isCodeEditor(control) || !control.hasModel()) {
return undefined;
}
const controller = ReferencesController.get(control);
if (!controller) {
return undefined;
}
const 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'))));
const range = new Range(position.lineNumber, position.column, position.lineNumber, position.column);
return Promise.resolve(controller.toggleWidget(range, references, false));
});
}
});
// use NEW command
CommandsRegistry.registerCommandAlias('editor.action.showReferences', 'editor.action.peekLocations');
//#endregion