Skip to content

Commit

Permalink
#67076 Improvements to error hover
Browse files Browse the repository at this point in the history
  • Loading branch information
sandy081 committed Feb 18, 2019
1 parent d415060 commit 03f9b48
Show file tree
Hide file tree
Showing 5 changed files with 130 additions and 19 deletions.
18 changes: 17 additions & 1 deletion src/vs/editor/contrib/gotoError/gotoError.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,17 @@ class MarkerModel {
return this.canNavigate() ? this._markers[this._nextIdx] : undefined;
}

set currentMarker(marker: IMarker | undefined) {
const idx = this._nextIdx;
this._nextIdx = -1;
if (marker) {
this._nextIdx = this.indexOf(marker);
}
if (this._nextIdx !== idx) {
this._onCurrentMarkerChanged.fire(marker);
}
}

public move(fwd: boolean, inCircles: boolean): boolean {
if (!this.canNavigate()) {
this._onCurrentMarkerChanged.fire(undefined);
Expand Down Expand Up @@ -181,7 +192,7 @@ class MarkerModel {
}
}

class MarkerController implements editorCommon.IEditorContribution {
export class MarkerController implements editorCommon.IEditorContribution {

private static readonly ID = 'editor.contrib.markerController';

Expand Down Expand Up @@ -280,6 +291,11 @@ class MarkerController implements editorCommon.IEditorContribution {
}
}

public show(marker: IMarker): void {
const model = this.getOrCreateModel();
model.currentMarker = marker;
}

private _onMarkerChanged(changedResources: URI[]): void {
let editorModel = this._editor.getModel();
if (!editorModel) {
Expand Down
43 changes: 38 additions & 5 deletions src/vs/editor/contrib/hover/hover.css
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,8 @@
display: none;
}

.monaco-editor-hover .monaco-editor-hover-content {
max-width: 500px;
}

.monaco-editor-hover .hover-row {
padding: 4px 5px;
padding: 4px 8px;
}

.monaco-editor-hover p,
Expand Down Expand Up @@ -75,3 +71,40 @@
white-space: pre-wrap;
word-break: break-all;
}

.monaco-editor-hover .marker-hover {
display: flex;
}

.monaco-editor-hover .marker-hover > .marker {
flex: 1;
}

.monaco-editor-hover .marker-hover > .actions {
padding-left: 12px;
display: flex;
}

.monaco-editor-hover .marker-hover > .actions > .icon {
width: 16px;
height: 16px;
}

.monaco-editor-hover .marker-hover > .actions .action {
cursor: pointer;
padding-left: 4px;
}

.monaco-editor-hover .marker-hover > .actions > .peek-marker {
font-size: large;
vertical-align: middle;
}

.monaco-editor-hover .marker-hover > .actions > .light-bulb {
background: url('../codeAction/lightbulb.svg') center center no-repeat;
}

.hc-black .monaco-editor-hover .marker-hover > .actions > .light-bulb,
.vs-dark .monaco-editor-hover .marker-hover > .actions > .light-bulb {
background: url('../codeAction/lightbulb-dark.svg') center center no-repeat;
}
8 changes: 7 additions & 1 deletion src/vs/editor/contrib/hover/hover.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ import { IOpenerService } from 'vs/platform/opener/common/opener';
import { editorHoverBackground, editorHoverBorder, editorHoverHighlight, textCodeBlockBackground, textLinkForeground } from 'vs/platform/theme/common/colorRegistry';
import { IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
import { IMarkerDecorationsService } from 'vs/editor/common/services/markersDecorationService';
import { IBulkEditService } from 'vs/editor/browser/services/bulkEditService';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';

export class ModesHoverController implements IEditorContribution {

Expand Down Expand Up @@ -62,6 +65,9 @@ export class ModesHoverController implements IEditorContribution {

constructor(private readonly _editor: ICodeEditor,
@IOpenerService private readonly _openerService: IOpenerService,
@IContextMenuService private readonly _contextMenuService: IContextMenuService,
@IBulkEditService private readonly _bulkEditService: IBulkEditService,
@ICommandService private readonly _commandService: ICommandService,
@IModeService private readonly _modeService: IModeService,
@IMarkerDecorationsService private readonly _markerDecorationsService: IMarkerDecorationsService,
@IThemeService private readonly _themeService: IThemeService
Expand Down Expand Up @@ -207,7 +213,7 @@ export class ModesHoverController implements IEditorContribution {

private _createHoverWidget() {
const renderer = new MarkdownRenderer(this._editor, this._modeService, this._openerService);
this._contentWidget = new ModesContentHoverWidget(this._editor, renderer, this._markerDecorationsService, this._themeService, this._openerService);
this._contentWidget = new ModesContentHoverWidget(this._editor, renderer, this._markerDecorationsService, this._themeService, this._contextMenuService, this._bulkEditService, this._commandService, this._openerService);
this._glyphWidget = new ModesGlyphHoverWidget(this._editor, renderer);
}

Expand Down
7 changes: 4 additions & 3 deletions src/vs/editor/contrib/hover/hoverWidgets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,9 @@ export class ContentHoverWidget extends Widget implements editorBrowser.IContent
}
}));

this._editor.onDidLayoutChange(e => this.updateMaxHeight());
this._editor.onDidLayoutChange(e => this.layout());

this.updateMaxHeight();
this.layout();
this._editor.addContentWidget(this);
this._showAtPosition = null;
this._showAtRange = null;
Expand Down Expand Up @@ -151,13 +151,14 @@ export class ContentHoverWidget extends Widget implements editorBrowser.IContent
this.scrollbar.scanDomNode();
}

private updateMaxHeight(): void {
private layout(): void {
const height = Math.max(this._editor.getLayoutInfo().height / 4, 250);
const { fontSize, lineHeight } = this._editor.getConfiguration().fontInfo;

this._domNode.style.fontSize = `${fontSize}px`;
this._domNode.style.lineHeight = `${lineHeight}px`;
this._domNode.style.maxHeight = `${height}px`;
this._domNode.style.maxWidth = `${Math.max(this._editor.getLayoutInfo().width - 50, 500)}px`;
}
}

Expand Down
73 changes: 64 additions & 9 deletions src/vs/editor/contrib/hover/modesContentHover.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import * as dom from 'vs/base/browser/dom';
import { CancellationToken } from 'vs/base/common/cancellation';
import { Color, RGBA } from 'vs/base/common/color';
import { IMarkdownString, MarkdownString, isEmptyMarkdownString, markedStringsEquals } from 'vs/base/common/htmlContent';
import { Disposable, IDisposable, combinedDisposable } from 'vs/base/common/lifecycle';
import { Disposable, IDisposable, combinedDisposable, toDisposable } from 'vs/base/common/lifecycle';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { Position } from 'vs/editor/common/core/position';
import { IRange, Range } from 'vs/editor/common/core/range';
Expand All @@ -29,6 +29,15 @@ import { basename } from 'vs/base/common/resources';
import { IMarkerDecorationsService } from 'vs/editor/common/services/markersDecorationService';
import { onUnexpectedError } from 'vs/base/common/errors';
import { IOpenerService, NullOpenerService } from 'vs/platform/opener/common/opener';
import { MarkerController } from 'vs/editor/contrib/gotoError/gotoError';
import { getCodeActions } from 'vs/editor/contrib/codeAction/codeAction';
import { CodeActionKind } from 'vs/editor/contrib/codeAction/codeActionTrigger';
import { Action } from 'vs/base/common/actions';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { applyCodeAction } from 'vs/editor/contrib/codeAction/codeActionCommands';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { IBulkEditService } from 'vs/editor/browser/services/bulkEditService';
import { CancelablePromise, createCancelablePromise } from 'vs/base/common/async';

const $ = dom.$;

Expand Down Expand Up @@ -206,6 +215,9 @@ export class ModesContentHoverWidget extends ContentHoverWidget {
markdownRenderer: MarkdownRenderer,
markerDecorationsService: IMarkerDecorationsService,
private readonly _themeService: IThemeService,
private readonly _contextMenuService: IContextMenuService,
private readonly _bulkEditService: IBulkEditService,
private readonly _commandService: ICommandService,
private readonly _openerService: IOpenerService | null = NullOpenerService,
) {
super(ModesContentHoverWidget.ID, editor);
Expand Down Expand Up @@ -468,26 +480,26 @@ export class ModesContentHoverWidget extends ContentHoverWidget {
}

private renderMarkerHover(markerHover: MarkerHover): HTMLElement {
const hoverElement = $('div');
const hoverElement = $('div.marker-hover');
const markerElement = dom.append(hoverElement, $('div.marker'));
const { source, message, code, relatedInformation } = markerHover.marker;

const messageElement = dom.append(hoverElement, $('span'));
const messageElement = dom.append(markerElement, $('span'));
messageElement.style.whiteSpace = 'pre-wrap';
messageElement.innerText = message;
this._editor.applyFontInfo(messageElement);

if (source || code) {
const detailsElement = dom.append(hoverElement, $('span'));
const detailsElement = dom.append(markerElement, $('span'));
detailsElement.style.opacity = '0.6';
detailsElement.style.paddingLeft = '6px';
detailsElement.innerText = source && code ? `${source}(${code})` : `(${code})`;
}

if (isNonEmptyArray(relatedInformation)) {
const listElement = dom.append(hoverElement, $('ul'));
for (const { message, resource, startLineNumber, startColumn } of relatedInformation) {
const item = dom.append(listElement, $('li'));
const a = dom.append(item, $('a'));
const relatedInfoContainer = dom.append(markerElement, $('div'));
relatedInfoContainer.style.marginTop = '8px';
const a = dom.append(relatedInfoContainer, $('a'));
a.innerText = `${basename(resource)}(${startLineNumber}, ${startColumn})`;
a.style.cursor = 'pointer';
a.onclick = e => {
Expand All @@ -497,13 +509,56 @@ export class ModesContentHoverWidget extends ContentHoverWidget {
this._openerService.open(resource.with({ fragment: `${startLineNumber},${startColumn}` })).catch(onUnexpectedError);
}
};
const messageElement = dom.append<HTMLAnchorElement>(item, $('span'));
const messageElement = dom.append<HTMLAnchorElement>(relatedInfoContainer, $('span'));
messageElement.innerText = `: ${message}`;
}
}

const actionsElement = dom.append(hoverElement, $('div.actions'));
const showCodeActions = dom.append(actionsElement, $('a.action.icon.light-bulb', { title: nls.localize('code actions', "Show Fixes...") }));
const disposables: IDisposable[] = [];
disposables.push(dom.addDisposableListener(showCodeActions, dom.EventType.CLICK, async e => {
e.stopPropagation();
e.preventDefault();
const codeActionsPromise = this.getCodeActions(markerHover.marker);
disposables.push(toDisposable(() => codeActionsPromise.cancel()));
const actions = await codeActionsPromise;
const elementPosition = dom.getDomNodePagePosition(showCodeActions);
this._contextMenuService.showContextMenu({
getAnchor: () => ({ x: elementPosition.left + 6, y: elementPosition.top + elementPosition.height + 6 }),
getActions: () => actions
});
}));
const peekMarkerAction = dom.append(actionsElement, $('a.action.icon.peek-marker', { title: nls.localize('go to problem', "Go to Problem") }));
peekMarkerAction.textContent = '↪';
disposables.push(dom.addDisposableListener(peekMarkerAction, dom.EventType.CLICK, e => {
e.stopPropagation();
e.preventDefault();
this.hide();
MarkerController.get(this._editor).show(markerHover.marker);
this._editor.focus();
}));
this.renderDisposable = combinedDisposable(disposables);
return hoverElement;
}

private getCodeActions(marker: IMarker): CancelablePromise<Action[]> {
return createCancelablePromise(async cancellationToken => {
const codeActions = await getCodeActions(this._editor.getModel()!, new Range(marker.startLineNumber, marker.startColumn, marker.endLineNumber, marker.endColumn), { type: 'manual', filter: { kind: CodeActionKind.QuickFix } }, cancellationToken);
if (codeActions.length) {
return codeActions.map(codeAction => new Action(
codeAction.command ? codeAction.command.id : codeAction.title,
codeAction.title,
undefined,
true,
() => applyCodeAction(codeAction, this._bulkEditService, this._commandService)));
}
return [
new Action('', nls.localize('editor.action.quickFix.noneMessage', "No code actions available"))
];
});
}

private static readonly _DECORATION_OPTIONS = ModelDecorationOptions.register({
className: 'hoverHighlight'
});
Expand Down

0 comments on commit 03f9b48

Please sign in to comment.