@@ -13,7 +13,7 @@ import { IModeService } from 'vs/editor/common/services/modeService';
1313import { Range , IRange } from 'vs/editor/common/core/range' ;
1414import * as editorCommon from 'vs/editor/common/editorCommon' ;
1515import { DefinitionProviderRegistry , LocationLink } from 'vs/editor/common/modes' ;
16- import { ICodeEditor , IMouseTarget , MouseTargetType } from 'vs/editor/browser/editorBrowser' ;
16+ import { ICodeEditor , MouseTargetType } from 'vs/editor/browser/editorBrowser' ;
1717import { registerEditorContribution } from 'vs/editor/browser/editorExtensions' ;
1818import { getDefinitionsAtPosition } from './goToDefinition' ;
1919import { DisposableStore } from 'vs/base/common/lifecycle' ;
@@ -26,16 +26,19 @@ import { ClickLinkGesture, ClickLinkMouseEvent, ClickLinkKeyboardEvent } from 'v
2626import { IWordAtPosition , IModelDeltaDecoration , ITextModel , IFoundBracket } from 'vs/editor/common/model' ;
2727import { Position } from 'vs/editor/common/core/position' ;
2828import { withNullAsUndefined } from 'vs/base/common/types' ;
29+ import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent' ;
30+ import { KeyCode } from 'vs/base/common/keyCodes' ;
2931
30- class GotoDefinitionWithMouseEditorContribution implements editorCommon . IEditorContribution {
32+ export class GotoDefinitionAtPositionEditorContribution implements editorCommon . IEditorContribution {
3133
3234 public static readonly ID = 'editor.contrib.gotodefinitionwithmouse' ;
3335 static readonly MAX_SOURCE_PREVIEW_LINES = 8 ;
3436
3537 private readonly editor : ICodeEditor ;
3638 private readonly toUnhook = new DisposableStore ( ) ;
37- private decorations : string [ ] = [ ] ;
38- private currentWordUnderMouse : IWordAtPosition | null = null ;
39+ private readonly toUnhookForKeyboard = new DisposableStore ( ) ;
40+ private linkDecorations : string [ ] = [ ] ;
41+ private currentWordAtPosition : IWordAtPosition | null = null ;
3942 private previousPromise : CancelablePromise < LocationLink [ ] | null > | null = null ;
4043
4144 constructor (
@@ -49,55 +52,96 @@ class GotoDefinitionWithMouseEditorContribution implements editorCommon.IEditorC
4952 this . toUnhook . add ( linkGesture ) ;
5053
5154 this . toUnhook . add ( linkGesture . onMouseMoveOrRelevantKeyDown ( ( [ mouseEvent , keyboardEvent ] ) => {
52- this . startFindDefinition ( mouseEvent , withNullAsUndefined ( keyboardEvent ) ) ;
55+ this . startFindDefinitionFromMouse ( mouseEvent , withNullAsUndefined ( keyboardEvent ) ) ;
5356 } ) ) ;
5457
5558 this . toUnhook . add ( linkGesture . onExecute ( ( mouseEvent : ClickLinkMouseEvent ) => {
5659 if ( this . isEnabled ( mouseEvent ) ) {
57- this . gotoDefinition ( mouseEvent . target , mouseEvent . hasSideBySideModifier ) . then ( ( ) => {
58- this . removeDecorations ( ) ;
60+ this . gotoDefinition ( mouseEvent . target . position ! , mouseEvent . hasSideBySideModifier ) . then ( ( ) => {
61+ this . removeLinkDecorations ( ) ;
5962 } , ( error : Error ) => {
60- this . removeDecorations ( ) ;
63+ this . removeLinkDecorations ( ) ;
6164 onUnexpectedError ( error ) ;
6265 } ) ;
6366 }
6467 } ) ) ;
6568
6669 this . toUnhook . add ( linkGesture . onCancel ( ( ) => {
67- this . removeDecorations ( ) ;
68- this . currentWordUnderMouse = null ;
70+ this . removeLinkDecorations ( ) ;
71+ this . currentWordAtPosition = null ;
6972 } ) ) ;
73+ }
74+
75+ static get ( editor : ICodeEditor ) : GotoDefinitionAtPositionEditorContribution {
76+ return editor . getContribution < GotoDefinitionAtPositionEditorContribution > ( GotoDefinitionAtPositionEditorContribution . ID ) ;
77+ }
7078
79+ startFindDefinitionFromCursor ( position : Position ) {
80+ // For issue: https://github.com/microsoft/vscode/issues/46257
81+ // equivalent to mouse move with meta/ctrl key
82+
83+ // First find the definition and add decorations
84+ // to the editor to be shown with the content hover widget
85+ return this . startFindDefinition ( position ) . then ( ( ) => {
86+
87+ // Add listeners for editor cursor move and key down events
88+ // Dismiss the "extended" editor decorations when the user hides
89+ // the hover widget. There is no event for the widget itself so these
90+ // serve as a best effort. After removing the link decorations, the hover
91+ // widget is clean and will only show declarations per next request.
92+ this . toUnhookForKeyboard . add ( this . editor . onDidChangeCursorPosition ( ( ) => {
93+ this . currentWordAtPosition = null ;
94+ this . removeLinkDecorations ( ) ;
95+ this . toUnhookForKeyboard . clear ( ) ;
96+ } ) ) ;
97+
98+ this . toUnhookForKeyboard . add ( this . editor . onKeyDown ( ( e : IKeyboardEvent ) => {
99+ if ( e ) {
100+ this . currentWordAtPosition = null ;
101+ this . removeLinkDecorations ( ) ;
102+ this . toUnhookForKeyboard . clear ( ) ;
103+ }
104+ } ) ) ;
105+ } ) ;
71106 }
72107
73- private startFindDefinition ( mouseEvent : ClickLinkMouseEvent , withKey ?: ClickLinkKeyboardEvent ) : void {
108+ private startFindDefinitionFromMouse ( mouseEvent : ClickLinkMouseEvent , withKey ?: ClickLinkKeyboardEvent ) : void {
74109
75110 // check if we are active and on a content widget
76- if ( mouseEvent . target . type === MouseTargetType . CONTENT_WIDGET && this . decorations . length > 0 ) {
111+ if ( mouseEvent . target . type === MouseTargetType . CONTENT_WIDGET && this . linkDecorations . length > 0 ) {
77112 return ;
78113 }
79114
80115 if ( ! this . editor . hasModel ( ) || ! this . isEnabled ( mouseEvent , withKey ) ) {
81- this . currentWordUnderMouse = null ;
82- this . removeDecorations ( ) ;
116+ this . currentWordAtPosition = null ;
117+ this . removeLinkDecorations ( ) ;
83118 return ;
84119 }
85120
121+ const position = mouseEvent . target . position ! ;
122+
123+ this . startFindDefinition ( position ) ;
124+ }
125+
126+ private startFindDefinition ( position : Position ) : Promise < number | undefined > {
127+
128+ // Dispose listeners for updating decorations when using keyboard to show definition hover
129+ this . toUnhookForKeyboard . clear ( ) ;
130+
86131 // Find word at mouse position
87- const word = mouseEvent . target . position ? this . editor . getModel ( ) . getWordAtPosition ( mouseEvent . target . position ) : null ;
132+ const word = position ? this . editor . getModel ( ) ? .getWordAtPosition ( position ) : null ;
88133 if ( ! word ) {
89- this . currentWordUnderMouse = null ;
90- this . removeDecorations ( ) ;
91- return ;
134+ this . currentWordAtPosition = null ;
135+ this . removeLinkDecorations ( ) ;
136+ return Promise . resolve ( 0 ) ;
92137 }
93- const position = mouseEvent . target . position ! ;
94138
95139 // Return early if word at position is still the same
96- if ( this . currentWordUnderMouse && this . currentWordUnderMouse . startColumn === word . startColumn && this . currentWordUnderMouse . endColumn === word . endColumn && this . currentWordUnderMouse . word === word . word ) {
97- return ;
140+ if ( this . currentWordAtPosition && this . currentWordAtPosition . startColumn === word . startColumn && this . currentWordAtPosition . endColumn === word . endColumn && this . currentWordAtPosition . word === word . word ) {
141+ return Promise . resolve ( 0 ) ;
98142 }
99143
100- this . currentWordUnderMouse = word ;
144+ this . currentWordAtPosition = word ;
101145
102146 // Find definition and decorate word if found
103147 let state = new EditorState ( this . editor , CodeEditorStateFlag . Position | CodeEditorStateFlag . Value | CodeEditorStateFlag . Selection | CodeEditorStateFlag . Scroll ) ;
@@ -107,11 +151,11 @@ class GotoDefinitionWithMouseEditorContribution implements editorCommon.IEditorC
107151 this . previousPromise = null ;
108152 }
109153
110- this . previousPromise = createCancelablePromise ( token => this . findDefinition ( mouseEvent . target , token ) ) ;
154+ this . previousPromise = createCancelablePromise ( token => this . findDefinition ( position , token ) ) ;
111155
112- this . previousPromise . then ( results => {
156+ return this . previousPromise . then ( results => {
113157 if ( ! results || ! results . length || ! state . validate ( this . editor ) ) {
114- this . removeDecorations ( ) ;
158+ this . removeLinkDecorations ( ) ;
115159 return ;
116160 }
117161
@@ -170,7 +214,7 @@ class GotoDefinitionWithMouseEditorContribution implements editorCommon.IEditorC
170214 private getPreviewValue ( textEditorModel : ITextModel , startLineNumber : number , result : LocationLink ) {
171215 let rangeToUse = result . targetSelectionRange ? result . range : this . getPreviewRangeBasedOnBrackets ( textEditorModel , startLineNumber ) ;
172216 const numberOfLinesInRange = rangeToUse . endLineNumber - rangeToUse . startLineNumber ;
173- if ( numberOfLinesInRange >= GotoDefinitionWithMouseEditorContribution . MAX_SOURCE_PREVIEW_LINES ) {
217+ if ( numberOfLinesInRange >= GotoDefinitionAtPositionEditorContribution . MAX_SOURCE_PREVIEW_LINES ) {
174218 rangeToUse = this . getPreviewRangeBasedOnIndentation ( textEditorModel , startLineNumber ) ;
175219 }
176220
@@ -193,7 +237,7 @@ class GotoDefinitionWithMouseEditorContribution implements editorCommon.IEditorC
193237
194238 private getPreviewRangeBasedOnIndentation ( textEditorModel : ITextModel , startLineNumber : number ) {
195239 const startIndent = textEditorModel . getLineFirstNonWhitespaceColumn ( startLineNumber ) ;
196- const maxLineNumber = Math . min ( textEditorModel . getLineCount ( ) , startLineNumber + GotoDefinitionWithMouseEditorContribution . MAX_SOURCE_PREVIEW_LINES ) ;
240+ const maxLineNumber = Math . min ( textEditorModel . getLineCount ( ) , startLineNumber + GotoDefinitionAtPositionEditorContribution . MAX_SOURCE_PREVIEW_LINES ) ;
197241 let endLineNumber = startLineNumber + 1 ;
198242
199243 for ( ; endLineNumber < maxLineNumber ; endLineNumber ++ ) {
@@ -208,7 +252,7 @@ class GotoDefinitionWithMouseEditorContribution implements editorCommon.IEditorC
208252 }
209253
210254 private getPreviewRangeBasedOnBrackets ( textEditorModel : ITextModel , startLineNumber : number ) {
211- const maxLineNumber = Math . min ( textEditorModel . getLineCount ( ) , startLineNumber + GotoDefinitionWithMouseEditorContribution . MAX_SOURCE_PREVIEW_LINES ) ;
255+ const maxLineNumber = Math . min ( textEditorModel . getLineCount ( ) , startLineNumber + GotoDefinitionAtPositionEditorContribution . MAX_SOURCE_PREVIEW_LINES ) ;
212256
213257 const brackets : IFoundBracket [ ] = [ ] ;
214258
@@ -263,12 +307,12 @@ class GotoDefinitionWithMouseEditorContribution implements editorCommon.IEditorC
263307 }
264308 } ;
265309
266- this . decorations = this . editor . deltaDecorations ( this . decorations , [ newDecorations ] ) ;
310+ this . linkDecorations = this . editor . deltaDecorations ( this . linkDecorations , [ newDecorations ] ) ;
267311 }
268312
269- private removeDecorations ( ) : void {
270- if ( this . decorations . length > 0 ) {
271- this . decorations = this . editor . deltaDecorations ( this . decorations , [ ] ) ;
313+ private removeLinkDecorations ( ) : void {
314+ if ( this . linkDecorations . length > 0 ) {
315+ this . linkDecorations = this . editor . deltaDecorations ( this . linkDecorations , [ ] ) ;
272316 }
273317 }
274318
@@ -280,17 +324,17 @@ class GotoDefinitionWithMouseEditorContribution implements editorCommon.IEditorC
280324 DefinitionProviderRegistry . has ( this . editor . getModel ( ) ) ;
281325 }
282326
283- private findDefinition ( target : IMouseTarget , token : CancellationToken ) : Promise < LocationLink [ ] | null > {
327+ private findDefinition ( position : Position , token : CancellationToken ) : Promise < LocationLink [ ] | null > {
284328 const model = this . editor . getModel ( ) ;
285329 if ( ! model ) {
286330 return Promise . resolve ( null ) ;
287331 }
288332
289- return getDefinitionsAtPosition ( model , target . position ! , token ) ;
333+ return getDefinitionsAtPosition ( model , position , token ) ;
290334 }
291335
292- private gotoDefinition ( target : IMouseTarget , sideBySide : boolean ) : Promise < any > {
293- this . editor . setPosition ( target . position ! ) ;
336+ private gotoDefinition ( position : Position , sideBySide : boolean ) : Promise < any > {
337+ this . editor . setPosition ( position ) ;
294338 const action = new DefinitionAction ( new DefinitionActionConfig ( sideBySide , false , true , false ) , { alias : '' , label : '' , id : '' , precondition : undefined } ) ;
295339 return this . editor . invokeWithinContext ( accessor => action . run ( accessor , this . editor ) ) ;
296340 }
@@ -300,7 +344,7 @@ class GotoDefinitionWithMouseEditorContribution implements editorCommon.IEditorC
300344 }
301345}
302346
303- registerEditorContribution ( GotoDefinitionWithMouseEditorContribution . ID , GotoDefinitionWithMouseEditorContribution ) ;
347+ registerEditorContribution ( GotoDefinitionAtPositionEditorContribution . ID , GotoDefinitionAtPositionEditorContribution ) ;
304348
305349registerThemingParticipant ( ( theme , collector ) => {
306350 const activeLinkForeground = theme . getColor ( editorActiveLinkForeground ) ;
0 commit comments