Skip to content

Commit 3aa0a3d

Browse files
committed
pimp up glyph hover
1 parent dbbadcd commit 3aa0a3d

3 files changed

Lines changed: 65 additions & 39 deletions

File tree

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ class ModesHoverController implements editorCommon.IEditorContribution {
6060
}));
6161

6262
this._contentWidget = new ModesContentHoverWidget(editor, openerService, modeService);
63-
this._glyphWidget = new ModesGlyphHoverWidget(editor);
63+
this._glyphWidget = new ModesGlyphHoverWidget(editor, openerService, modeService);
6464
}
6565
}
6666

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

Lines changed: 38 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -156,8 +156,8 @@ export class GlyphHoverWidget extends Widget implements editorBrowser.IOverlayWi
156156

157157
private _id: string;
158158
protected _editor: editorBrowser.ICodeEditor;
159-
protected _isVisible: boolean;
160-
protected _domNode: HTMLElement;
159+
private _isVisible: boolean;
160+
private _domNode: HTMLElement;
161161
protected _showAtLineNumber: number;
162162

163163
constructor(id: string, editor: editorBrowser.ICodeEditor) {
@@ -167,23 +167,30 @@ export class GlyphHoverWidget extends Widget implements editorBrowser.IOverlayWi
167167
this._isVisible = false;
168168

169169
this._domNode = document.createElement('div');
170-
this._domNode.className = 'monaco-editor-hover monaco-editor-background';
171-
this._domNode.style.display = 'none';
170+
this._domNode.className = 'monaco-editor-hover hidden';
172171
this._domNode.setAttribute('aria-hidden', 'true');
173172
this._domNode.setAttribute('role', 'presentation');
174173

175174
this._showAtLineNumber = -1;
176175

177-
this._editor.applyFontInfo(this._domNode);
178176
this._register(this._editor.onDidChangeConfiguration((e:IConfigurationChangedEvent) => {
179177
if (e.fontInfo) {
180-
this._editor.applyFontInfo(this._domNode);
178+
this.updateFont();
181179
}
182180
}));
183181

184182
this._editor.addOverlayWidget(this);
185183
}
186184

185+
protected get isVisible(): boolean {
186+
return this._isVisible;
187+
}
188+
189+
protected set isVisible(value: boolean) {
190+
this._isVisible = value;
191+
toggleClass(this._domNode, 'hidden', !this._isVisible);
192+
}
193+
187194
public getId(): string {
188195
return this._id;
189196
}
@@ -195,25 +202,26 @@ export class GlyphHoverWidget extends Widget implements editorBrowser.IOverlayWi
195202
public showAt(lineNumber: number): void {
196203
this._showAtLineNumber = lineNumber;
197204

198-
if (!this._isVisible) {
199-
this._isVisible = true;
200-
this._domNode.style.display = 'block';
205+
if (!this.isVisible) {
206+
this.isVisible = true;
201207
}
202208

203-
let editorLayout = this._editor.getLayoutInfo();
204-
let topForLineNumber = this._editor.getTopForLineNumber(this._showAtLineNumber);
205-
let editorScrollTop = this._editor.getScrollTop();
209+
const editorLayout = this._editor.getLayoutInfo();
210+
const topForLineNumber = this._editor.getTopForLineNumber(this._showAtLineNumber);
211+
const editorScrollTop = this._editor.getScrollTop();
212+
const lineHeight = this._editor.getConfiguration().lineHeight;
213+
const nodeHeight = this._domNode.clientHeight;
214+
const top = topForLineNumber - editorScrollTop - ((nodeHeight - lineHeight) / 2);
206215

207-
this._domNode.style.left = (editorLayout.glyphMarginLeft + editorLayout.glyphMarginWidth) + 'px';
208-
this._domNode.style.top = (topForLineNumber - editorScrollTop) + 'px';
216+
this._domNode.style.left = `${ editorLayout.glyphMarginLeft + editorLayout.glyphMarginWidth }px`;
217+
this._domNode.style.top = `${ Math.max(Math.round(top), 0) }px`;
209218
}
210219

211220
public hide(): void {
212-
if (!this._isVisible) {
221+
if (!this.isVisible) {
213222
return;
214223
}
215-
this._isVisible = false;
216-
this._domNode.style.display = 'none';
224+
this.isVisible = false;
217225
}
218226

219227
public getPosition():editorBrowser.IOverlayWidgetPosition {
@@ -224,4 +232,17 @@ export class GlyphHoverWidget extends Widget implements editorBrowser.IOverlayWi
224232
this._editor.removeOverlayWidget(this);
225233
super.dispose();
226234
}
235+
236+
private updateFont(): void {
237+
const codeTags: HTMLPhraseElement[] = Array.prototype.slice.call(this._domNode.getElementsByTagName('code'));
238+
const codeClasses: HTMLElement[] = Array.prototype.slice.call(this._domNode.getElementsByClassName('code'));
239+
240+
[...codeTags, ...codeClasses].forEach(node => this._editor.applyFontInfo(node));
241+
}
242+
243+
protected updateContents(node: Node): void {
244+
this._domNode.textContent = '';
245+
this._domNode.appendChild(node);
246+
this.updateFont();
247+
}
227248
}

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

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,13 @@ import {IModelDecoration, IRange} from 'vs/editor/common/editorCommon';
88
import {ICodeEditor} from 'vs/editor/browser/editorBrowser';
99
import {HoverOperation, IHoverComputer} from './hoverOperation';
1010
import {GlyphHoverWidget} from './hoverWidgets';
11+
import {$} from 'vs/base/browser/dom';
12+
import {renderMarkedString} from 'vs/base/browser/htmlContentRenderer';
13+
import {IOpenerService, NullOpenerService} from 'vs/platform/opener/common/opener';
14+
import URI from 'vs/base/common/uri';
15+
import {TPromise} from 'vs/base/common/winjs.base';
16+
import {IModeService} from 'vs/editor/common/services/modeService';
17+
import {tokenizeToString} from 'vs/editor/common/modes/textToHtmlTokenizer';
1118

1219
export interface IHoverMessage {
1320
value?: string;
@@ -77,9 +84,11 @@ export class ModesGlyphHoverWidget extends GlyphHoverWidget {
7784
private _computer: MarginComputer;
7885
private _hoverOperation: HoverOperation<IHoverMessage[]>;
7986

80-
constructor(editor: ICodeEditor) {
87+
constructor(editor: ICodeEditor, private openerService: IOpenerService, private modeService: IModeService) {
8188
super(ModesGlyphHoverWidget.ID, editor);
8289

90+
this.openerService = openerService || NullOpenerService;
91+
8392
this._lastLineNumber = -1;
8493

8594
this._computer = new MarginComputer(this._editor);
@@ -99,7 +108,7 @@ export class ModesGlyphHoverWidget extends GlyphHoverWidget {
99108
}
100109

101110
public onModelDecorationsChanged(): void {
102-
if (this._isVisible) {
111+
if (this.isVisible) {
103112
// The decorations have changed and the hover is visible,
104113
// we need to recompute the displayed text
105114
this._hoverOperation.cancel();
@@ -141,29 +150,25 @@ export class ModesGlyphHoverWidget extends GlyphHoverWidget {
141150

142151
private _renderMessages(lineNumber: number, messages: IHoverMessage[]): void {
143152

144-
var fragment = document.createDocumentFragment();
153+
const fragment = document.createDocumentFragment();
145154

146155
messages.forEach((msg) => {
147-
148-
var row:HTMLElement = document.createElement('div');
149-
var span:HTMLElement = null;
150-
151-
if (msg.className) {
152-
span = document.createElement('span');
153-
span.textContent = msg.value;
154-
span.className = msg.className;
155-
row.appendChild(span);
156-
} else {
157-
row.textContent = msg.value;
158-
}
159-
160-
fragment.appendChild(row);
156+
const renderedContents = renderMarkedString(msg.value, {
157+
actionCallback: content => this.openerService.open(URI.parse(content)),
158+
codeBlockRenderer: (modeId, value): string | TPromise<string> => {
159+
const mode = this.modeService.getMode(modeId || this._editor.getModel().getModeId());
160+
const getMode = mode => mode ? TPromise.as(mode) : this.modeService.getOrCreateMode(modeId);
161+
162+
return getMode(mode)
163+
.then(null, err => null)
164+
.then(mode => `<div class="code">${ tokenizeToString(value, mode) }</div>`);
165+
}
166+
});
167+
168+
fragment.appendChild($('div.hover-row', null, renderedContents));
161169
});
162170

163-
this._domNode.textContent = '';
164-
this._domNode.appendChild(fragment);
165-
166-
// show
171+
this.updateContents(fragment);
167172
this.showAt(lineNumber);
168173
}
169174
}

0 commit comments

Comments
 (0)