Skip to content

Commit

Permalink
introduce MarkdownRenderer to avoid code duplication and to have the …
Browse files Browse the repository at this point in the history
…one place for keeping the renderer options, #11877
  • Loading branch information
jrieken committed Sep 8, 2017
1 parent 9dd403e commit 48bc6f1
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 54 deletions.
2 changes: 1 addition & 1 deletion src/vs/base/browser/htmlContentRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export function renderFormattedText(formattedText: string, options: RenderOption
* @param content a html element description
* @param actionCallback a callback function for any action links in the string. Argument is the zero-based index of the clicked action.
*/
export function renderMarkdown(markdown: IMarkdownString, options: RenderOptions = {}): Node {
export function renderMarkdown(markdown: IMarkdownString, options: RenderOptions = {}): HTMLElement {
const element = createElement(options);

const { codeBlockRenderer, actionCallback } = options;
Expand Down
7 changes: 4 additions & 3 deletions src/vs/editor/contrib/hover/browser/hover.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { registerThemingParticipant } from 'vs/platform/theme/common/themeService';
import { editorHoverHighlight, editorHoverBackground, editorHoverBorder, textLinkForeground, textCodeBlockBackground } from 'vs/platform/theme/common/colorRegistry';
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
import { MarkdownRenderer } from 'vs/editor/contrib/markdown/browser/markdownRenderer';

@editorContribution
export class ModesHoverController implements editorCommon.IEditorContribution {
Expand Down Expand Up @@ -64,9 +65,9 @@ export class ModesHoverController implements editorCommon.IEditorContribution {
this._hideWidgets();
}
}));

this._contentWidget = new ModesContentHoverWidget(editor, openerService, modeService);
this._glyphWidget = new ModesGlyphHoverWidget(editor, openerService, modeService);
const renderer = new MarkdownRenderer(editor, modeService, openerService);
this._contentWidget = new ModesContentHoverWidget(editor, renderer);
this._glyphWidget = new ModesGlyphHoverWidget(editor, renderer);
}
}

Expand Down
34 changes: 5 additions & 29 deletions src/vs/editor/contrib/hover/browser/modesContentHover.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,17 @@
'use strict';

import * as nls from 'vs/nls';
import URI from 'vs/base/common/uri';
import { onUnexpectedError } from 'vs/base/common/errors';
import * as dom from 'vs/base/browser/dom';
import { TPromise } from 'vs/base/common/winjs.base';
import { renderMarkdown } from 'vs/base/browser/htmlContentRenderer';
import { IOpenerService, NullOpenerService } from 'vs/platform/opener/common/opener';
import { IModeService } from 'vs/editor/common/services/modeService';
import { IRange, Range } from 'vs/editor/common/core/range';
import { Position } from 'vs/editor/common/core/position';
import { HoverProviderRegistry, Hover, IColor, IColorFormatter } from 'vs/editor/common/modes';
import { tokenizeToString } from 'vs/editor/common/modes/textToHtmlTokenizer';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { getHover } from '../common/hover';
import { HoverOperation, IHoverComputer } from './hoverOperation';
import { ContentHoverWidget } from './hoverWidgets';
import { IMarkdownString, MarkdownString, isEmptyMarkdownString } from 'vs/base/common/htmlContent';
import { MarkdownRenderer } from 'vs/editor/contrib/markdown/browser/markdownRenderer';
import { ModelDecorationOptions } from 'vs/editor/common/model/textModelWithDecorations';
import { ColorPickerModel } from 'vs/editor/contrib/colorPicker/browser/colorPickerModel';
import { ColorPickerWidget } from 'vs/editor/contrib/colorPicker/browser/colorPickerWidget';
Expand Down Expand Up @@ -166,22 +161,20 @@ export class ModesContentHoverWidget extends ContentHoverWidget {
private _hoverOperation: HoverOperation<HoverPart[]>;
private _highlightDecorations: string[];
private _isChangingDecorations: boolean;
private _openerService: IOpenerService;
private _modeService: IModeService;
private _markdownRenderer: MarkdownRenderer;
private _shouldFocus: boolean;
private _colorPicker: ColorPickerWidget;

private renderDisposable: IDisposable = EmptyDisposable;
private toDispose: IDisposable[];

constructor(editor: ICodeEditor, openerService: IOpenerService, modeService: IModeService) {
constructor(editor: ICodeEditor, markdownRenderner: MarkdownRenderer) {
super(ModesContentHoverWidget.ID, editor);

this._computer = new ModesContentComputer(this._editor);
this._highlightDecorations = [];
this._isChangingDecorations = false;
this._openerService = openerService || NullOpenerService;
this._modeService = modeService;
this._markdownRenderer = markdownRenderner;

this._hoverOperation = new HoverOperation(
this._computer,
Expand Down Expand Up @@ -312,24 +305,7 @@ export class ModesContentHoverWidget extends ContentHoverWidget {
msg.contents
.filter(contents => !isEmptyMarkdownString(contents))
.forEach(contents => {
const renderedContents = renderMarkdown(contents, {
actionCallback: (content) => {
this._openerService.open(URI.parse(content)).then(void 0, onUnexpectedError);
},
codeBlockRenderer: (languageAlias, value): string | TPromise<string> => {
// In markdown,
// it is possible that we stumble upon language aliases (e.g.js instead of javascript)
// it is possible no alias is given in which case we fall back to the current editor lang
const modeId = languageAlias
? this._modeService.getModeIdForLanguageName(languageAlias)
: this._editor.getModel().getLanguageIdentifier().language;

return this._modeService.getOrCreateMode(modeId).then(_ => {
return tokenizeToString(value, modeId);
});
}
});

const renderedContents = this._markdownRenderer.render(contents);
fragment.appendChild($('div.hover-row', null, renderedContents));
});
} else {
Expand Down
26 changes: 5 additions & 21 deletions src/vs/editor/contrib/hover/browser/modesGlyphHover.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,7 @@ import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { HoverOperation, IHoverComputer } from './hoverOperation';
import { GlyphHoverWidget } from './hoverWidgets';
import { $ } from 'vs/base/browser/dom';
import { renderMarkdown } from 'vs/base/browser/htmlContentRenderer';
import { IOpenerService, NullOpenerService } from 'vs/platform/opener/common/opener';
import URI from 'vs/base/common/uri';
import { onUnexpectedError } from 'vs/base/common/errors';
import { TPromise } from 'vs/base/common/winjs.base';
import { IModeService } from 'vs/editor/common/services/modeService';
import { tokenizeToString } from 'vs/editor/common/modes/textToHtmlTokenizer';
import { MarkdownRenderer } from 'vs/editor/contrib/markdown/browser/markdownRenderer';
import { IMarkdownString, isEmptyMarkdownString } from 'vs/base/common/htmlContent';

export interface IHoverMessage {
Expand Down Expand Up @@ -94,16 +88,16 @@ export class ModesGlyphHoverWidget extends GlyphHoverWidget {
private _messages: IHoverMessage[];
private _lastLineNumber: number;

private _markdownRenderer: MarkdownRenderer;
private _computer: MarginComputer;
private _hoverOperation: HoverOperation<IHoverMessage[]>;

constructor(editor: ICodeEditor, private openerService: IOpenerService, private modeService: IModeService) {
constructor(editor: ICodeEditor, markdownRenderer: MarkdownRenderer) {
super(ModesGlyphHoverWidget.ID, editor);

this.openerService = openerService || NullOpenerService;

this._lastLineNumber = -1;

this._markdownRenderer = markdownRenderer;
this._computer = new MarginComputer(this._editor);

this._hoverOperation = new HoverOperation(
Expand Down Expand Up @@ -166,17 +160,7 @@ export class ModesGlyphHoverWidget extends GlyphHoverWidget {
const fragment = document.createDocumentFragment();

messages.forEach((msg) => {
const renderedContents = renderMarkdown(msg.value, {
actionCallback: content => this.openerService.open(URI.parse(content)).then(undefined, onUnexpectedError),
codeBlockRenderer: (languageAlias, value): string | TPromise<string> => {
// In markdown, it is possible that we stumble upon language aliases (e.g. js instead of javascript)
const modeId = this.modeService.getModeIdForLanguageName(languageAlias);
return this.modeService.getOrCreateMode(modeId).then(_ => {
return tokenizeToString(value, modeId);
});
}
});

const renderedContents = this._markdownRenderer.render(msg.value);
fragment.appendChild($('div.hover-row', null, renderedContents));
});

Expand Down
54 changes: 54 additions & 0 deletions src/vs/editor/contrib/markdown/browser/markdownRenderer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

'use strict';

import { TPromise } from 'vs/base/common/winjs.base';
import { IMarkdownString } from 'vs/base/common/htmlContent';
import { renderMarkdown, RenderOptions } from 'vs/base/browser/htmlContentRenderer';
import { IOpenerService, NullOpenerService } from 'vs/platform/opener/common/opener';
import { IModeService } from 'vs/editor/common/services/modeService';
import URI from 'vs/base/common/uri';
import { onUnexpectedError } from 'vs/base/common/errors';
import { tokenizeToString } from 'vs/editor/common/modes/textToHtmlTokenizer';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { optional } from 'vs/platform/instantiation/common/instantiation';

export class MarkdownRenderer {

private readonly _options: RenderOptions;

constructor(
editor: ICodeEditor,
@IModeService private readonly _modeService: IModeService,
@optional(IOpenerService) private readonly _openerService: IOpenerService = NullOpenerService,
) {
this._options = {
actionCallback: (content) => {
this._openerService.open(URI.parse(content)).then(void 0, onUnexpectedError);
},
codeBlockRenderer: (languageAlias, value): string | TPromise<string> => {
// In markdown,
// it is possible that we stumble upon language aliases (e.g.js instead of javascript)
// it is possible no alias is given in which case we fall back to the current editor lang
const modeId = languageAlias
? this._modeService.getModeIdForLanguageName(languageAlias)
: editor.getModel().getLanguageIdentifier().language;

return this._modeService.getOrCreateMode(modeId).then(_ => {
return tokenizeToString(value, modeId);
});
}
};
}

render(markdown: IMarkdownString, options?: RenderOptions): HTMLElement {
if (options) {
return renderMarkdown(markdown, { ...options, ...this._options });
} else {
return renderMarkdown(markdown, this._options);
}
}
}

0 comments on commit 48bc6f1

Please sign in to comment.