mirror of
https://github.com/microsoft/vscode.git
synced 2026-04-28 20:43:31 +01:00
introduce MarkdownRenderer to avoid code duplication and to have the one place for keeping the renderer options, #11877
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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';
|
||||
@@ -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,
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
@@ -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(
|
||||
@@ -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));
|
||||
});
|
||||
|
||||
|
||||
54
src/vs/editor/contrib/markdown/browser/markdownRenderer.ts
Normal file
54
src/vs/editor/contrib/markdown/browser/markdownRenderer.ts
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user