| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260 |
- /*---------------------------------------------------------------------------------------------
- * Copyright (c) Microsoft Corporation. All rights reserved.
- * Licensed under the MIT License. See License.txt in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
- var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
- return c > 3 && r && Object.defineProperty(target, key, r), r;
- };
- var __param = (this && this.__param) || function (paramIndex, decorator) {
- return function (target, key) { decorator(target, key, paramIndex); }
- };
- import { createCancelablePromise } from '../../../../../base/common/async.js';
- import { onUnexpectedError } from '../../../../../base/common/errors.js';
- import { MarkdownString } from '../../../../../base/common/htmlContent.js';
- import { DisposableStore } from '../../../../../base/common/lifecycle.js';
- import { withNullAsUndefined } from '../../../../../base/common/types.js';
- import './goToDefinitionAtPosition.css';
- import { EditorState } from '../../../editorState/browser/editorState.js';
- import { registerEditorContribution } from '../../../../browser/editorExtensions.js';
- import { Range } from '../../../../common/core/range.js';
- import { ILanguageService } from '../../../../common/languages/language.js';
- import { ITextModelService } from '../../../../common/services/resolverService.js';
- import { ClickLinkGesture } from './clickLinkGesture.js';
- import { PeekContext } from '../../../peekView/browser/peekView.js';
- import * as nls from '../../../../../nls.js';
- import { IContextKeyService } from '../../../../../platform/contextkey/common/contextkey.js';
- import { editorActiveLinkForeground } from '../../../../../platform/theme/common/colorRegistry.js';
- import { registerThemingParticipant } from '../../../../../platform/theme/common/themeService.js';
- import { DefinitionAction } from '../goToCommands.js';
- import { getDefinitionsAtPosition } from '../goToSymbol.js';
- import { ILanguageFeaturesService } from '../../../../common/services/languageFeatures.js';
- let GotoDefinitionAtPositionEditorContribution = class GotoDefinitionAtPositionEditorContribution {
- constructor(editor, textModelResolverService, languageService, languageFeaturesService) {
- this.textModelResolverService = textModelResolverService;
- this.languageService = languageService;
- this.languageFeaturesService = languageFeaturesService;
- this.toUnhook = new DisposableStore();
- this.toUnhookForKeyboard = new DisposableStore();
- this.currentWordAtPosition = null;
- this.previousPromise = null;
- this.editor = editor;
- this.linkDecorations = this.editor.createDecorationsCollection();
- const linkGesture = new ClickLinkGesture(editor);
- this.toUnhook.add(linkGesture);
- this.toUnhook.add(linkGesture.onMouseMoveOrRelevantKeyDown(([mouseEvent, keyboardEvent]) => {
- this.startFindDefinitionFromMouse(mouseEvent, withNullAsUndefined(keyboardEvent));
- }));
- this.toUnhook.add(linkGesture.onExecute((mouseEvent) => {
- if (this.isEnabled(mouseEvent)) {
- this.gotoDefinition(mouseEvent.target.position, mouseEvent.hasSideBySideModifier).then(() => {
- this.removeLinkDecorations();
- }, (error) => {
- this.removeLinkDecorations();
- onUnexpectedError(error);
- });
- }
- }));
- this.toUnhook.add(linkGesture.onCancel(() => {
- this.removeLinkDecorations();
- this.currentWordAtPosition = null;
- }));
- }
- static get(editor) {
- return editor.getContribution(GotoDefinitionAtPositionEditorContribution.ID);
- }
- startFindDefinitionFromCursor(position) {
- // For issue: https://github.com/microsoft/vscode/issues/46257
- // equivalent to mouse move with meta/ctrl key
- // First find the definition and add decorations
- // to the editor to be shown with the content hover widget
- return this.startFindDefinition(position).then(() => {
- // Add listeners for editor cursor move and key down events
- // Dismiss the "extended" editor decorations when the user hides
- // the hover widget. There is no event for the widget itself so these
- // serve as a best effort. After removing the link decorations, the hover
- // widget is clean and will only show declarations per next request.
- this.toUnhookForKeyboard.add(this.editor.onDidChangeCursorPosition(() => {
- this.currentWordAtPosition = null;
- this.removeLinkDecorations();
- this.toUnhookForKeyboard.clear();
- }));
- this.toUnhookForKeyboard.add(this.editor.onKeyDown((e) => {
- if (e) {
- this.currentWordAtPosition = null;
- this.removeLinkDecorations();
- this.toUnhookForKeyboard.clear();
- }
- }));
- });
- }
- startFindDefinitionFromMouse(mouseEvent, withKey) {
- // check if we are active and on a content widget
- if (mouseEvent.target.type === 9 /* MouseTargetType.CONTENT_WIDGET */ && this.linkDecorations.length > 0) {
- return;
- }
- if (!this.editor.hasModel() || !this.isEnabled(mouseEvent, withKey)) {
- this.currentWordAtPosition = null;
- this.removeLinkDecorations();
- return;
- }
- const position = mouseEvent.target.position;
- this.startFindDefinition(position);
- }
- startFindDefinition(position) {
- var _a;
- // Dispose listeners for updating decorations when using keyboard to show definition hover
- this.toUnhookForKeyboard.clear();
- // Find word at mouse position
- const word = position ? (_a = this.editor.getModel()) === null || _a === void 0 ? void 0 : _a.getWordAtPosition(position) : null;
- if (!word) {
- this.currentWordAtPosition = null;
- this.removeLinkDecorations();
- return Promise.resolve(0);
- }
- // Return early if word at position is still the same
- if (this.currentWordAtPosition && this.currentWordAtPosition.startColumn === word.startColumn && this.currentWordAtPosition.endColumn === word.endColumn && this.currentWordAtPosition.word === word.word) {
- return Promise.resolve(0);
- }
- this.currentWordAtPosition = word;
- // Find definition and decorate word if found
- const state = new EditorState(this.editor, 4 /* CodeEditorStateFlag.Position */ | 1 /* CodeEditorStateFlag.Value */ | 2 /* CodeEditorStateFlag.Selection */ | 8 /* CodeEditorStateFlag.Scroll */);
- if (this.previousPromise) {
- this.previousPromise.cancel();
- this.previousPromise = null;
- }
- this.previousPromise = createCancelablePromise(token => this.findDefinition(position, token));
- return this.previousPromise.then(results => {
- if (!results || !results.length || !state.validate(this.editor)) {
- this.removeLinkDecorations();
- return;
- }
- // Multiple results
- if (results.length > 1) {
- this.addDecoration(new Range(position.lineNumber, word.startColumn, position.lineNumber, word.endColumn), new MarkdownString().appendText(nls.localize('multipleResults', "Click to show {0} definitions.", results.length)));
- }
- // Single result
- else {
- const result = results[0];
- if (!result.uri) {
- return;
- }
- this.textModelResolverService.createModelReference(result.uri).then(ref => {
- if (!ref.object || !ref.object.textEditorModel) {
- ref.dispose();
- return;
- }
- const { object: { textEditorModel } } = ref;
- const { startLineNumber } = result.range;
- if (startLineNumber < 1 || startLineNumber > textEditorModel.getLineCount()) {
- // invalid range
- ref.dispose();
- return;
- }
- const previewValue = this.getPreviewValue(textEditorModel, startLineNumber, result);
- let wordRange;
- if (result.originSelectionRange) {
- wordRange = Range.lift(result.originSelectionRange);
- }
- else {
- wordRange = new Range(position.lineNumber, word.startColumn, position.lineNumber, word.endColumn);
- }
- const languageId = this.languageService.guessLanguageIdByFilepathOrFirstLine(textEditorModel.uri);
- this.addDecoration(wordRange, new MarkdownString().appendCodeblock(languageId ? languageId : '', previewValue));
- ref.dispose();
- });
- }
- }).then(undefined, onUnexpectedError);
- }
- getPreviewValue(textEditorModel, startLineNumber, result) {
- let rangeToUse = result.range;
- const numberOfLinesInRange = rangeToUse.endLineNumber - rangeToUse.startLineNumber;
- if (numberOfLinesInRange >= GotoDefinitionAtPositionEditorContribution.MAX_SOURCE_PREVIEW_LINES) {
- rangeToUse = this.getPreviewRangeBasedOnIndentation(textEditorModel, startLineNumber);
- }
- const previewValue = this.stripIndentationFromPreviewRange(textEditorModel, startLineNumber, rangeToUse);
- return previewValue;
- }
- stripIndentationFromPreviewRange(textEditorModel, startLineNumber, previewRange) {
- const startIndent = textEditorModel.getLineFirstNonWhitespaceColumn(startLineNumber);
- let minIndent = startIndent;
- for (let endLineNumber = startLineNumber + 1; endLineNumber < previewRange.endLineNumber; endLineNumber++) {
- const endIndent = textEditorModel.getLineFirstNonWhitespaceColumn(endLineNumber);
- minIndent = Math.min(minIndent, endIndent);
- }
- const previewValue = textEditorModel.getValueInRange(previewRange).replace(new RegExp(`^\\s{${minIndent - 1}}`, 'gm'), '').trim();
- return previewValue;
- }
- getPreviewRangeBasedOnIndentation(textEditorModel, startLineNumber) {
- const startIndent = textEditorModel.getLineFirstNonWhitespaceColumn(startLineNumber);
- const maxLineNumber = Math.min(textEditorModel.getLineCount(), startLineNumber + GotoDefinitionAtPositionEditorContribution.MAX_SOURCE_PREVIEW_LINES);
- let endLineNumber = startLineNumber + 1;
- for (; endLineNumber < maxLineNumber; endLineNumber++) {
- const endIndent = textEditorModel.getLineFirstNonWhitespaceColumn(endLineNumber);
- if (startIndent === endIndent) {
- break;
- }
- }
- return new Range(startLineNumber, 1, endLineNumber + 1, 1);
- }
- addDecoration(range, hoverMessage) {
- const newDecorations = {
- range: range,
- options: {
- description: 'goto-definition-link',
- inlineClassName: 'goto-definition-link',
- hoverMessage
- }
- };
- this.linkDecorations.set([newDecorations]);
- }
- removeLinkDecorations() {
- this.linkDecorations.clear();
- }
- isEnabled(mouseEvent, withKey) {
- return this.editor.hasModel() &&
- mouseEvent.isNoneOrSingleMouseDown &&
- (mouseEvent.target.type === 6 /* MouseTargetType.CONTENT_TEXT */) &&
- (mouseEvent.hasTriggerModifier || (withKey ? withKey.keyCodeIsTriggerKey : false)) &&
- this.languageFeaturesService.definitionProvider.has(this.editor.getModel());
- }
- findDefinition(position, token) {
- const model = this.editor.getModel();
- if (!model) {
- return Promise.resolve(null);
- }
- return getDefinitionsAtPosition(this.languageFeaturesService.definitionProvider, model, position, token);
- }
- gotoDefinition(position, openToSide) {
- this.editor.setPosition(position);
- return this.editor.invokeWithinContext((accessor) => {
- const canPeek = !openToSide && this.editor.getOption(80 /* EditorOption.definitionLinkOpensInPeek */) && !this.isInPeekEditor(accessor);
- const action = new DefinitionAction({ openToSide, openInPeek: canPeek, muteMessage: true }, { alias: '', label: '', id: '', precondition: undefined });
- return action.run(accessor, this.editor);
- });
- }
- isInPeekEditor(accessor) {
- const contextKeyService = accessor.get(IContextKeyService);
- return PeekContext.inPeekEditor.getValue(contextKeyService);
- }
- dispose() {
- this.toUnhook.dispose();
- }
- };
- GotoDefinitionAtPositionEditorContribution.ID = 'editor.contrib.gotodefinitionatposition';
- GotoDefinitionAtPositionEditorContribution.MAX_SOURCE_PREVIEW_LINES = 8;
- GotoDefinitionAtPositionEditorContribution = __decorate([
- __param(1, ITextModelService),
- __param(2, ILanguageService),
- __param(3, ILanguageFeaturesService)
- ], GotoDefinitionAtPositionEditorContribution);
- export { GotoDefinitionAtPositionEditorContribution };
- registerEditorContribution(GotoDefinitionAtPositionEditorContribution.ID, GotoDefinitionAtPositionEditorContribution);
- registerThemingParticipant((theme, collector) => {
- const activeLinkForeground = theme.getColor(editorActiveLinkForeground);
- if (activeLinkForeground) {
- collector.addRule(`.monaco-editor .goto-definition-link { color: ${activeLinkForeground} !important; }`);
- }
- });
|