Skip to content

Commit 38549a6

Browse files
committed
Allow link on Diagnostic#code for microsoft#11847
Squashed commit of the following: commit 76689c23011bf960f5ba3e199659e8180455466d Author: Pine Wu <octref@gmail.com> Date: Fri Jan 24 10:19:44 2020 +0100 Clarify API commit 88d772d62da5d912b54285aa52dc6d6a108ca587 Author: Pine Wu <octref@gmail.com> Date: Fri Jan 24 10:17:28 2020 +0100 Tooltip commit 11ef8012ae3e560d6db6fff26ba3c258e7eae4a6 Author: Pine Wu <octref@gmail.com> Date: Thu Jan 23 16:50:28 2020 +0100 Hover to show link color and use cmd/alt click commit 38655a70b3eed56b99e8018fb5c79bd41b6c4f56 Author: Pine Wu <octref@gmail.com> Date: Thu Jan 23 15:21:13 2020 +0100 Add hack to always render underline a bit below commit 959f6b13bf81885cc370f6099e5123142089599e Author: Pine Wu <octref@gmail.com> Date: Thu Jan 23 11:32:37 2020 +0100 Fix compile error commit b5c50e872935e74503451bd2801227f82b8410f4 Author: Pine Wu <octref@gmail.com> Date: Thu Jan 23 11:19:52 2020 +0100 Bring code link everywhere for Diagnostics commit f88cd4cc4e2064fd96853373e26c12670161bf60 Author: Pine Wu <octref@gmail.com> Date: Wed Jan 22 17:24:54 2020 +0100 Add Diagnostic#code2 and render it in hover/inline/panel commit 2a13e3e4f62fd3707f2c03c1e814a8fdc557c367 Author: Pine Wu <octref@gmail.com> Date: Wed Jan 22 13:49:42 2020 +0100 WIP
1 parent e4eec1d commit 38549a6

13 files changed

Lines changed: 372 additions & 37 deletions

File tree

src/vs/editor/contrib/gotoError/gotoError.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ import { MenuRegistry, MenuId } from 'vs/platform/actions/common/actions';
2727
import { Action } from 'vs/base/common/actions';
2828
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
2929
import { isEqual } from 'vs/base/common/resources';
30+
import { IOpenerService } from 'vs/platform/opener/common/opener';
31+
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
3032

3133
class MarkerModel {
3234

@@ -209,7 +211,9 @@ export class MarkerController implements IEditorContribution {
209211
@IContextKeyService private readonly _contextKeyService: IContextKeyService,
210212
@IThemeService private readonly _themeService: IThemeService,
211213
@ICodeEditorService private readonly _editorService: ICodeEditorService,
212-
@IKeybindingService private readonly _keybindingService: IKeybindingService
214+
@IKeybindingService private readonly _keybindingService: IKeybindingService,
215+
@IOpenerService private readonly _openerService: IOpenerService,
216+
@IConfigurationService private readonly _configurationService: IConfigurationService
213217
) {
214218
this._editor = editor;
215219
this._widgetVisible = CONTEXT_MARKERS_NAVIGATION_VISIBLE.bindTo(this._contextKeyService);
@@ -243,7 +247,7 @@ export class MarkerController implements IEditorContribution {
243247
new Action(NextMarkerAction.ID, NextMarkerAction.LABEL + (nextMarkerKeybinding ? ` (${nextMarkerKeybinding.getLabel()})` : ''), 'show-next-problem codicon-chevron-down', this._model.canNavigate(), async () => { if (this._model) { this._model.move(true, true); } }),
244248
new Action(PrevMarkerAction.ID, PrevMarkerAction.LABEL + (prevMarkerKeybinding ? ` (${prevMarkerKeybinding.getLabel()})` : ''), 'show-previous-problem codicon-chevron-up', this._model.canNavigate(), async () => { if (this._model) { this._model.move(false, true); } })
245249
];
246-
this._widget = new MarkerNavigationWidget(this._editor, actions, this._themeService);
250+
this._widget = new MarkerNavigationWidget(this._editor, actions, this._themeService, this._openerService, this._configurationService);
247251
this._widgetVisible.set(true);
248252
this._widget.onDidClose(() => this.closeMarkersNavigation(), this, this._disposeOnClose);
249253

src/vs/editor/contrib/gotoError/gotoErrorWidget.ts

Lines changed: 89 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ import { IAction } from 'vs/base/common/actions';
2626
import { IActionBarOptions, ActionsOrientation } from 'vs/base/browser/ui/actionbar/actionbar';
2727
import { SeverityIcon } from 'vs/platform/severityIcon/common/severityIcon';
2828
import { 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

3035
class 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

166241
export 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
329406
export const editorMarkerNavigationBackground = registerColor('editorMarkerNavigation.background', { dark: '#2D2D30', light: Color.white, hc: '#0C141F' }, nls.localize('editorMarkerNavigationBackground', 'Editor marker navigation widget background.'));
330407

331408
registerThemingParticipant((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
});

src/vs/editor/contrib/gotoError/media/gotoErrorWidget.css

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,27 @@
4545
}
4646

4747
.monaco-editor .marker-widget .descriptioncontainer .message .source,
48-
.monaco-editor .marker-widget .descriptioncontainer .message .code {
48+
.monaco-editor .marker-widget .descriptioncontainer .message span.code {
4949
opacity: 0.6;
5050
}
5151

52+
.monaco-editor .marker-widget .descriptioncontainer .message a.code-link {
53+
opacity: 0.6;
54+
color: inherit;
55+
}
56+
.monaco-editor .marker-widget .descriptioncontainer .message a.code-link:before {
57+
content: '(';
58+
}
59+
.monaco-editor .marker-widget .descriptioncontainer .message a.code-link:after {
60+
content: ')';
61+
}
62+
.monaco-editor .marker-widget .descriptioncontainer .message a.code-link > span {
63+
text-decoration: underline;
64+
/** Hack to force underline to show **/
65+
border-bottom: 1px solid transparent;
66+
text-underline-position: under;
67+
}
68+
5269
.monaco-editor .marker-widget .descriptioncontainer .filename {
5370
cursor: pointer;
5471
}

src/vs/editor/contrib/hover/hover.css

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,3 +110,20 @@
110110
font-size: inherit;
111111
vertical-align: middle;
112112
}
113+
114+
.monaco-editor-hover .hover-contents a.code-link:before {
115+
content: '(';
116+
}
117+
.monaco-editor-hover .hover-contents a.code-link:after {
118+
content: ')';
119+
}
120+
121+
.monaco-editor-hover .hover-contents a.code-link {
122+
color: inherit;
123+
}
124+
.monaco-editor-hover .hover-contents a.code-link > span {
125+
text-decoration: underline;
126+
/** Hack to force underline to show **/
127+
border-bottom: 1px solid transparent;
128+
text-underline-position: under;
129+
}

src/vs/editor/contrib/hover/hover.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import { IMarkerDecorationsService } from 'vs/editor/common/services/markersDeco
2727
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
2828
import { AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility';
2929
import { GotoDefinitionAtPositionEditorContribution } from 'vs/editor/contrib/gotoSymbol/link/goToDefinitionAtPosition';
30+
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
3031

3132
export class ModesHoverController implements IEditorContribution {
3233

@@ -66,7 +67,8 @@ export class ModesHoverController implements IEditorContribution {
6667
@IModeService private readonly _modeService: IModeService,
6768
@IMarkerDecorationsService private readonly _markerDecorationsService: IMarkerDecorationsService,
6869
@IKeybindingService private readonly _keybindingService: IKeybindingService,
69-
@IThemeService private readonly _themeService: IThemeService
70+
@IThemeService private readonly _themeService: IThemeService,
71+
@IConfigurationService private readonly _configurationService: IConfigurationService
7072
) {
7173
this._isMouseDown = false;
7274
this._hoverClicked = false;
@@ -205,7 +207,7 @@ export class ModesHoverController implements IEditorContribution {
205207
}
206208

207209
private _createHoverWidgets() {
208-
this._contentWidget.value = new ModesContentHoverWidget(this._editor, this._markerDecorationsService, this._themeService, this._keybindingService, this._modeService, this._openerService);
210+
this._contentWidget.value = new ModesContentHoverWidget(this._editor, this._markerDecorationsService, this._themeService, this._keybindingService, this._modeService, this._openerService, this._configurationService);
209211
this._glyphWidget.value = new ModesGlyphHoverWidget(this._editor, this._modeService, this._openerService);
210212
}
211213

0 commit comments

Comments
 (0)