@@ -26,6 +26,11 @@ import { IAction } from 'vs/base/common/actions';
2626import { IActionBarOptions , ActionsOrientation } from 'vs/base/browser/ui/actionbar/actionbar' ;
2727import { SeverityIcon } from 'vs/platform/severityIcon/common/severityIcon' ;
2828import { EditorOption } from 'vs/editor/common/config/editorOptions' ;
29+ import { IOpenerService } from 'vs/platform/opener/common/opener' ;
30+ import { IConfigurationService } from 'vs/platform/configuration/common/configuration' ;
31+ import { OperatingSystem , OS } from 'vs/base/common/platform' ;
32+
33+ type ModifierKey = 'meta' | 'ctrl' | 'alt' ;
2934
3035class MessageWidget {
3136
@@ -39,7 +44,16 @@ class MessageWidget {
3944 private readonly _relatedDiagnostics = new WeakMap < HTMLElement , IRelatedInformation > ( ) ;
4045 private readonly _disposables : DisposableStore = new DisposableStore ( ) ;
4146
42- constructor ( parent : HTMLElement , editor : ICodeEditor , onRelatedInformation : ( related : IRelatedInformation ) => void ) {
47+ private _clickModifierKey : ModifierKey ;
48+ private _codeLink ?: HTMLElement ;
49+
50+ constructor (
51+ parent : HTMLElement ,
52+ editor : ICodeEditor ,
53+ onRelatedInformation : ( related : IRelatedInformation ) => void ,
54+ private readonly _openerService : IOpenerService ,
55+ private readonly _configurationService : IConfigurationService
56+ ) {
4357 this . _editor = editor ;
4458
4559 const domNode = document . createElement ( 'div' ) ;
@@ -74,19 +88,37 @@ class MessageWidget {
7488 domNode . style . top = `-${ e . scrollTop } px` ;
7589 } ) ) ;
7690 this . _disposables . add ( this . _scrollable ) ;
91+
92+ this . _clickModifierKey = this . _getClickModifierKey ( ) ;
93+ this . _disposables . add ( this . _configurationService . onDidChangeConfiguration ( e => {
94+ if ( e . affectsConfiguration ( 'editor.multiCursorModifier' ) ) {
95+ this . _clickModifierKey = this . _getClickModifierKey ( ) ;
96+ if ( this . _codeLink ) {
97+ this . _codeLink . setAttribute ( 'title' , this . _getCodelinkTooltip ( ) ) ;
98+ }
99+ }
100+ } ) ) ;
77101 }
78102
79103 dispose ( ) : void {
80104 dispose ( this . _disposables ) ;
81105 }
82106
83107 update ( { source, message, relatedInformation, code } : IMarker ) : void {
108+ let sourceAndCodeLength = ( source ?. length || 0 ) + '()' . length ;
109+ if ( code ) {
110+ if ( typeof code === 'string' ) {
111+ sourceAndCodeLength += code . length ;
112+ } else {
113+ sourceAndCodeLength += code . value . length ;
114+ }
115+ }
84116
85117 const lines = message . split ( / \r \n | \r | \n / g) ;
86118 this . _lines = lines . length ;
87119 this . _longestLineLength = 0 ;
88120 for ( const line of lines ) {
89- this . _longestLineLength = Math . max ( line . length , this . _longestLineLength ) ;
121+ this . _longestLineLength = Math . max ( line . length + sourceAndCodeLength , this . _longestLineLength ) ;
90122 }
91123
92124 dom . clearNode ( this . _messageBlock ) ;
@@ -111,10 +143,28 @@ class MessageWidget {
111143 detailsElement . appendChild ( sourceElement ) ;
112144 }
113145 if ( code ) {
114- const codeElement = document . createElement ( 'span' ) ;
115- codeElement . innerText = `(${ code } )` ;
116- dom . addClass ( codeElement , 'code' ) ;
117- detailsElement . appendChild ( codeElement ) ;
146+ if ( typeof code === 'string' ) {
147+ const codeElement = document . createElement ( 'span' ) ;
148+ codeElement . innerText = `(${ code } )` ;
149+ dom . addClass ( codeElement , 'code' ) ;
150+ detailsElement . appendChild ( codeElement ) ;
151+ } else {
152+ this . _codeLink = dom . $ ( 'a.code-link' ) ;
153+ this . _codeLink . setAttribute ( 'title' , this . _getCodelinkTooltip ( ) ) ;
154+ this . _codeLink . setAttribute ( 'href' , `${ code . link . toString ( ) } ` ) ;
155+
156+ this . _codeLink . onclick = ( e ) => {
157+ e . preventDefault ( ) ;
158+ if ( ( this . _clickModifierKey === 'meta' && e . metaKey ) || ( this . _clickModifierKey === 'ctrl' && e . ctrlKey ) || ( this . _clickModifierKey === 'alt' && e . altKey ) ) {
159+ this . _openerService . open ( code . link ) ;
160+ e . stopPropagation ( ) ;
161+ }
162+ } ;
163+
164+ const codeElement = dom . append ( this . _codeLink , dom . $ ( 'span' ) ) ;
165+ codeElement . innerText = code . value ;
166+ detailsElement . appendChild ( this . _codeLink ) ;
167+ }
118168 }
119169 }
120170
@@ -161,6 +211,31 @@ class MessageWidget {
161211 getHeightInLines ( ) : number {
162212 return Math . min ( 17 , this . _lines ) ;
163213 }
214+
215+ private _getClickModifierKey ( ) : ModifierKey {
216+ const value = this . _configurationService . getValue < 'ctrlCmd' | 'alt' > ( 'editor.multiCursorModifier' ) ;
217+ if ( value === 'ctrlCmd' ) {
218+ return 'alt' ;
219+ } else {
220+ if ( OS === OperatingSystem . Macintosh ) {
221+ return 'meta' ;
222+ } else {
223+ return 'ctrl' ;
224+ }
225+ }
226+ }
227+
228+ private _getCodelinkTooltip ( ) : string {
229+ const tooltipLabel = nls . localize ( 'links.navigate.follow' , 'Follow link' ) ;
230+ const tooltipKeybinding = this . _clickModifierKey === 'ctrl'
231+ ? nls . localize ( 'links.navigate.kb.meta' , 'ctrl + click' )
232+ :
233+ this . _clickModifierKey === 'meta'
234+ ? OS === OperatingSystem . Macintosh ? nls . localize ( 'links.navigate.kb.meta.mac' , 'cmd + click' ) : nls . localize ( 'links.navigate.kb.meta' , 'ctrl + click' )
235+ : OS === OperatingSystem . Macintosh ? nls . localize ( 'links.navigate.kb.alt.mac' , 'option + click' ) : nls . localize ( 'links.navigate.kb.alt' , 'alt + click' ) ;
236+
237+ return `${ tooltipLabel } (${ tooltipKeybinding } )` ;
238+ }
164239}
165240
166241export class MarkerNavigationWidget extends PeekViewWidget {
@@ -180,7 +255,9 @@ export class MarkerNavigationWidget extends PeekViewWidget {
180255 constructor (
181256 editor : ICodeEditor ,
182257 private readonly actions : ReadonlyArray < IAction > ,
183- private readonly _themeService : IThemeService
258+ private readonly _themeService : IThemeService ,
259+ private readonly _openerService : IOpenerService ,
260+ private readonly _configurationService : IConfigurationService
184261 ) {
185262 super ( editor , { showArrow : true , showFrame : true , isAccessible : true } ) ;
186263 this . _severity = MarkerSeverity . Warning ;
@@ -250,7 +327,7 @@ export class MarkerNavigationWidget extends PeekViewWidget {
250327 this . _container = document . createElement ( 'div' ) ;
251328 container . appendChild ( this . _container ) ;
252329
253- this . _message = new MessageWidget ( this . _container , this . editor , related => this . _onDidSelectRelatedInformation . fire ( related ) ) ;
330+ this . _message = new MessageWidget ( this . _container , this . editor , related => this . _onDidSelectRelatedInformation . fire ( related ) , this . _openerService , this . _configurationService ) ;
254331 this . _disposables . add ( this . _message ) ;
255332 }
256333
@@ -329,8 +406,9 @@ export const editorMarkerNavigationInfo = registerColor('editorMarkerNavigationI
329406export const editorMarkerNavigationBackground = registerColor ( 'editorMarkerNavigation.background' , { dark : '#2D2D30' , light : Color . white , hc : '#0C141F' } , nls . localize ( 'editorMarkerNavigationBackground' , 'Editor marker navigation widget background.' ) ) ;
330407
331408registerThemingParticipant ( ( theme , collector ) => {
332- const link = theme . getColor ( textLinkForeground ) ;
333- if ( link ) {
334- collector . addRule ( `.monaco-editor .marker-widget a { color: ${ link } ; }` ) ;
409+ const linkFg = theme . getColor ( textLinkForeground ) ;
410+ if ( linkFg ) {
411+ collector . addRule ( `.monaco-editor .marker-widget a { color: ${ linkFg } ; }` ) ;
412+ collector . addRule ( `.monaco-editor .marker-widget a.code-link span:hover { color: ${ linkFg } ; }` ) ;
335413 }
336414} ) ;
0 commit comments