提交 9791d587 编写于 作者: J Johannes Rieken

replace MarkedString with object-type IMarkdownString, #29076

上级 f117237e
......@@ -36,7 +36,7 @@ declare module monaco {
#include(vs/base/common/cancellation): CancellationTokenSource, CancellationToken
#include(vs/base/common/uri): URI
#include(vs/editor/common/standalone/standaloneBase): KeyCode, KeyMod
#include(vs/base/common/htmlContent): MarkedString
#include(vs/base/common/htmlContent): IMarkdownString
#include(vs/base/browser/keyboardEvent): IKeyboardEvent
#include(vs/base/browser/mouseEvent): IMouseEvent
#include(vs/editor/common/editorCommon): IScrollEvent
......
......@@ -10,7 +10,7 @@ import * as DOM from 'vs/base/browser/dom';
import { defaultGenerator } from 'vs/base/common/idGenerator';
import { escape } from 'vs/base/common/strings';
import { TPromise } from 'vs/base/common/winjs.base';
import { MarkedString, removeMarkdownEscapes } from 'vs/base/common/htmlContent';
import { removeMarkdownEscapes, IMarkdownString } from 'vs/base/common/htmlContent';
import { marked } from 'vs/base/common/marked/marked';
import { IMouseEvent } from 'vs/base/browser/mouseEvent';
......@@ -30,14 +30,6 @@ function createElement(options: RenderOptions): HTMLElement {
return element;
}
export function renderMarkedString(markedString: MarkedString, options: RenderOptions = {}): Node {
// this is sort of legacy given that we have full
// support for markdown. Turn this into markdown
// and continue
return renderMarkdown(markedString, options);
}
export function renderText(text: string, options: RenderOptions = {}): Node {
const element = createElement(options);
element.textContent = text;
......@@ -56,7 +48,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: string, options: RenderOptions = {}): Node {
export function renderMarkdown(markdown: IMarkdownString, options: RenderOptions = {}): Node {
const element = createElement(options);
const { codeBlockRenderer, actionCallback } = options;
......@@ -113,7 +105,9 @@ export function renderMarkdown(markdown: string, options: RenderOptions = {}): N
if (!href || href.match(/^data:|javascript:/i)) {
return text;
} else if (href.match(/^command:/i)) {
return `<a href="#" data-href="${href}" title="${localize('hover.command', "Click to execute command")}">${text}&nbsp;<span class="octicon octicon-terminal"></span></a>`;
return markdown.enableCommands
? `<a href="#" data-href="${href}" title="${localize('hover.command', "Click to execute command")}">${text}&nbsp;<span class="octicon octicon-terminal"></span></a>`
: text;
} else {
return `<a href="#" data-href="${href}" title="${title || text}">${text}</a>`;
......@@ -161,7 +155,7 @@ export function renderMarkdown(markdown: string, options: RenderOptions = {}): N
});
}
element.innerHTML = marked(markdown, {
element.innerHTML = marked(markdown.value, {
sanitize: true,
renderer
});
......
......@@ -8,28 +8,75 @@
import { equals } from 'vs/base/common/arrays';
import { marked } from 'vs/base/common/marked/marked';
/**
* MarkedString can be used to render human readable text. It is either a markdown string
* or a code-block that provides a language and a code snippet. Note that
* markdown strings will be sanitized - that means html will be escaped.
*/
export type MarkedString = string;
export function markedStringsEquals(a: MarkedString | MarkedString[], b: MarkedString | MarkedString[]): boolean {
export interface IMarkdownString {
value: string;
enableCommands?: true;
}
export class MarkdownString implements IMarkdownString {
static isMarkdownString(thing: any): thing is IMarkdownString {
if (thing instanceof MarkdownString) {
return true;
} else if (typeof thing === 'object') {
return typeof (<IMarkdownString>thing).value === 'string'
&& (typeof (<IMarkdownString>thing).enableCommands === 'boolean' || (<IMarkdownString>thing).enableCommands === void 0);
}
return false;
}
value: string;
enableCommands?: true;
constructor(value: string = '') {
this.value = value;
}
appendText(value: string): this {
this.value += textToMarkedString(value);
return this;
}
// appendMarkdown(value: string): this {
// this.value += value;
// return this;
// }
appendCodeblock(langId: string, code: string): this {
this.value += '```';
this.value += langId;
this.value += '\n';
this.value += code;
this.value += '```\n';
return this;
}
}
export function markedStringsEquals(a: IMarkdownString | IMarkdownString[], b: IMarkdownString | IMarkdownString[]): boolean {
if (!a && !b) {
return true;
} else if (!a || !b) {
return false;
} else if (typeof a === 'string' && typeof b === 'string') {
return a === b;
} else if (Array.isArray(a) && Array.isArray(b)) {
return equals(a, b);
return equals(a, b, markdownStringEqual);
} else if (MarkdownString.isMarkdownString(a) && MarkdownString.isMarkdownString(b)) {
return markdownStringEqual(a, b);
} else {
return false;
}
}
export function textToMarkedString(text: string): MarkedString {
function markdownStringEqual(a: IMarkdownString, b: IMarkdownString): boolean {
if (a === b) {
return true;
} else if (!a || !b) {
return false;
} else {
return a.value === b.value && a.enableCommands === b.enableCommands;
}
}
export function textToMarkedString(text: string): string {
return text.replace(/[\\`*_{}[\]()#+\-.!]/g, '\\$&'); // escape markdown syntax tokens: http://daringfireball.net/projects/markdown/syntax#backslash
}
......@@ -40,7 +87,7 @@ export function removeMarkdownEscapes(text: string): string {
return text.replace(/\\([\\`*_{}[\]()#+\-.!])/g, '$1');
}
export function containsCommandLink(value: MarkedString): boolean {
export function containsCommandLink(value: string): boolean {
let uses = false;
const renderer = new marked.Renderer();
renderer.link = (href, title, text): string => {
......
......@@ -87,35 +87,35 @@ suite('HtmlContent', () => {
assert.strictEqual(result.innerHTML, '**bold**');
});
test('image rendering conforms to default', () => {
const markdown = `![image](someimageurl 'caption')`;
const markdown = { value: `![image](someimageurl 'caption')` };
const result: HTMLElement = <any>renderMarkdown(markdown);
const renderer = new marked.Renderer();
const imageFromMarked = marked(markdown, {
const imageFromMarked = marked(markdown.value, {
sanitize: true,
renderer
}).trim();
assert.strictEqual(result.innerHTML, imageFromMarked);
});
test('image rendering conforms to default without title', () => {
const markdown = `![image](someimageurl)`;
const markdown = { value: `![image](someimageurl)` };
const result: HTMLElement = <any>renderMarkdown(markdown);
const renderer = new marked.Renderer();
const imageFromMarked = marked(markdown, {
const imageFromMarked = marked(markdown.value, {
sanitize: true,
renderer
}).trim();
assert.strictEqual(result.innerHTML, imageFromMarked);
});
test('image width from title params', () => {
var result: HTMLElement = <any>renderMarkdown(`![image](someimageurl|width=100 'caption')`);
var result: HTMLElement = <any>renderMarkdown({ value: `![image](someimageurl|width=100 'caption')` });
assert.strictEqual(result.innerHTML, `<p><img src="someimageurl" alt="image" title="caption" width="100"></p>`);
});
test('image height from title params', () => {
var result: HTMLElement = <any>renderMarkdown(`![image](someimageurl|height=100 'caption')`);
var result: HTMLElement = <any>renderMarkdown({ value: `![image](someimageurl|height=100 'caption')` });
assert.strictEqual(result.innerHTML, `<p><img src="someimageurl" alt="image" title="caption" height="100"></p>`);
});
test('image width and height from title params', () => {
var result: HTMLElement = <any>renderMarkdown(`![image](someimageurl|height=200,width=100 'caption')`);
var result: HTMLElement = <any>renderMarkdown({ value: `![image](someimageurl|height=200,width=100 'caption')` });
assert.strictEqual(result.innerHTML, `<p><img src="someimageurl" alt="image" title="caption" width="100" height="200"></p>`);
});
});
\ No newline at end of file
});
......@@ -5,7 +5,7 @@
'use strict';
import { BulkListenerCallback } from 'vs/base/common/eventEmitter';
import { MarkedString } from 'vs/base/common/htmlContent';
import { IMarkdownString } from 'vs/base/common/htmlContent';
import URI from 'vs/base/common/uri';
import { TPromise } from 'vs/base/common/winjs.base';
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
......@@ -77,11 +77,11 @@ export interface IModelDecorationOptions {
/**
* Message to be rendered when hovering over the glyph margin decoration.
*/
glyphMarginHoverMessage?: MarkedString | MarkedString[];
glyphMarginHoverMessage?: IMarkdownString | IMarkdownString[];
/**
* Array of MarkedString to render as the decoration message.
* Array of MarkdownString to render as the decoration message.
*/
hoverMessage?: MarkedString | MarkedString[];
hoverMessage?: IMarkdownString | IMarkdownString[];
/**
* Should the decoration expand to encompass a whole line.
*/
......@@ -1728,7 +1728,7 @@ export interface IDecorationInstanceRenderOptions extends IThemeDecorationInstan
*/
export interface IDecorationOptions {
range: IRange;
hoverMessage?: MarkedString | MarkedString[];
hoverMessage?: IMarkdownString | IMarkdownString[];
renderOptions?: IDecorationInstanceRenderOptions;
}
......
......@@ -5,7 +5,7 @@
'use strict';
import { onUnexpectedError } from 'vs/base/common/errors';
import { MarkedString, markedStringsEquals } from 'vs/base/common/htmlContent';
import { IMarkdownString, markedStringsEquals } from 'vs/base/common/htmlContent';
import * as strings from 'vs/base/common/strings';
import { CharCode } from 'vs/base/common/charCode';
import { Range, IRange } from 'vs/editor/common/core/range';
......@@ -894,8 +894,8 @@ export class ModelDecorationOptions implements editorCommon.IModelDecorationOpti
readonly staticId: number;
readonly stickiness: editorCommon.TrackedRangeStickiness;
readonly className: string;
readonly hoverMessage: MarkedString | MarkedString[];
readonly glyphMarginHoverMessage: MarkedString | MarkedString[];
readonly hoverMessage: IMarkdownString | IMarkdownString[];
readonly glyphMarginHoverMessage: IMarkdownString | IMarkdownString[];
readonly isWholeLine: boolean;
readonly showIfCollapsed: boolean;
readonly overviewRuler: ModelDecorationOverviewRulerOptions;
......@@ -911,7 +911,7 @@ export class ModelDecorationOptions implements editorCommon.IModelDecorationOpti
this.stickiness = options.stickiness || editorCommon.TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges;
this.className = options.className ? cleanClassName(options.className) : strings.empty;
this.hoverMessage = options.hoverMessage || [];
this.glyphMarginHoverMessage = options.glyphMarginHoverMessage || strings.empty;
this.glyphMarginHoverMessage = options.glyphMarginHoverMessage || [];
this.isWholeLine = options.isWholeLine || false;
this.showIfCollapsed = options.showIfCollapsed || false;
this.overviewRuler = new ModelDecorationOverviewRulerOptions(options.overviewRuler);
......
......@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import { MarkedString } from 'vs/base/common/htmlContent';
import { IMarkdownString } from 'vs/base/common/htmlContent';
import { IDisposable } from 'vs/base/common/lifecycle';
import URI from 'vs/base/common/uri';
import * as editorCommon from 'vs/editor/common/editorCommon';
......@@ -160,7 +160,7 @@ export interface Hover {
/**
* The contents of this hover.
*/
contents: MarkedString[];
contents: IMarkdownString[];
/**
* The range to which this hover applies. When missing, the
......
......@@ -8,7 +8,7 @@ import * as nls from 'vs/nls';
import network = require('vs/base/common/network');
import Event, { Emitter } from 'vs/base/common/event';
import { EmitterEvent } from 'vs/base/common/eventEmitter';
import { MarkedString } from 'vs/base/common/htmlContent';
import { IMarkdownString } from 'vs/base/common/htmlContent';
import { IDisposable } from 'vs/base/common/lifecycle';
import Severity from 'vs/base/common/severity';
import URI from 'vs/base/common/uri';
......@@ -136,7 +136,7 @@ class ModelMarkerHandler {
break;
}
let hoverMessage: MarkedString[] = null;
let hoverMessage: IMarkdownString = null;
let { message, source } = marker;
if (typeof message === 'string') {
......@@ -150,7 +150,7 @@ class ModelMarkerHandler {
}
}
hoverMessage = ['```_\n' + message + '\n```'];
hoverMessage = { value: '```_\n' + message + '\n```' };
}
return {
......
......@@ -9,7 +9,7 @@ import 'vs/css!./goToDeclarationMouse';
import * as nls from 'vs/nls';
import { Throttler } from 'vs/base/common/async';
import { onUnexpectedError } from 'vs/base/common/errors';
import { MarkedString } from 'vs/base/common/htmlContent';
import { MarkdownString } from 'vs/base/common/htmlContent';
import { TPromise } from 'vs/base/common/winjs.base';
import { IModeService } from 'vs/editor/common/services/modeService';
import { Range } from 'vs/editor/common/core/range';
......@@ -112,7 +112,10 @@ class GotoDefinitionWithMouseEditorContribution implements editorCommon.IEditorC
// Multiple results
if (results.length > 1) {
this.addDecoration(new Range(position.lineNumber, word.startColumn, position.lineNumber, word.endColumn), nls.localize('multipleResults', "Click to show {0} definitions.", results.length));
this.addDecoration(
new Range(position.lineNumber, word.startColumn, position.lineNumber, word.endColumn),
new MarkdownString().appendText(nls.localize('multipleResults', "Click to show {0} definitions.", results.length))
);
}
// Single result
......@@ -156,7 +159,7 @@ class GotoDefinitionWithMouseEditorContribution implements editorCommon.IEditorC
this.addDecoration(
new Range(position.lineNumber, word.startColumn, position.lineNumber, word.endColumn),
'```' + this.modeService.getModeIdByFilenameOrFirstLine(textEditorModel.uri.fsPath) + '\n' + value + '\n```'
new MarkdownString().appendCodeblock(this.modeService.getModeIdByFilenameOrFirstLine(textEditorModel.uri.fsPath), value)
);
ref.dispose();
});
......@@ -164,7 +167,7 @@ class GotoDefinitionWithMouseEditorContribution implements editorCommon.IEditorC
}).done(undefined, onUnexpectedError);
}
private addDecoration(range: Range, hoverMessage: MarkedString): void {
private addDecoration(range: Range, hoverMessage: MarkdownString): void {
const newDecorations: editorCommon.IModelDeltaDecoration = {
range: range,
......
......@@ -9,7 +9,7 @@ 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 { renderMarkedString } from 'vs/base/browser/htmlContentRenderer';
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';
......@@ -20,7 +20,7 @@ import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { getHover } from '../common/hover';
import { HoverOperation, IHoverComputer } from './hoverOperation';
import { ContentHoverWidget } from './hoverWidgets';
import { textToMarkedString, MarkedString } from 'vs/base/common/htmlContent';
import { IMarkdownString, MarkdownString } from 'vs/base/common/htmlContent';
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';
......@@ -81,8 +81,8 @@ class ModesContentComputer implements IHoverComputer<HoverPart[]> {
return [];
}
const hasHoverContent = (contents: MarkedString | MarkedString[]) => {
return contents && (!Array.isArray(contents) || (<MarkedString[]>contents).length > 0);
const hasHoverContent = (contents: IMarkdownString | IMarkdownString[]) => {
return contents && (!Array.isArray(contents) || (<IMarkdownString[]>contents).length > 0);
};
const colorDetector = ColorDetector.get(this._editor);
......@@ -111,7 +111,7 @@ class ModesContentComputer implements IHoverComputer<HoverPart[]> {
return null;
}
let contents: MarkedString[];
let contents: IMarkdownString[];
if (d.options.hoverMessage) {
if (Array.isArray(d.options.hoverMessage)) {
......@@ -155,7 +155,7 @@ class ModesContentComputer implements IHoverComputer<HoverPart[]> {
private _getLoadingMessage(): HoverPart {
return {
range: this._range,
contents: [textToMarkedString(nls.localize('modesContentHover.loading', "Loading..."))]
contents: [new MarkdownString().appendText(nls.localize('modesContentHover.loading', "Loading..."))]
};
}
}
......@@ -316,7 +316,7 @@ export class ModesContentHoverWidget extends ContentHoverWidget {
msg.contents
.filter(contents => !!contents)
.forEach(contents => {
const renderedContents = renderMarkedString(contents, {
const renderedContents = renderMarkdown(contents, {
actionCallback: (content) => {
this._openerService.open(URI.parse(content)).then(void 0, onUnexpectedError);
},
......
......@@ -8,17 +8,17 @@ import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { HoverOperation, IHoverComputer } from './hoverOperation';
import { GlyphHoverWidget } from './hoverWidgets';
import { $ } from 'vs/base/browser/dom';
import { renderMarkedString } from 'vs/base/browser/htmlContentRenderer';
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 { MarkedString } from 'vs/base/common/htmlContent';
import { IMarkdownString } from 'vs/base/common/htmlContent';
export interface IHoverMessage {
value: MarkedString;
value: IMarkdownString;
}
class MarginComputer implements IHoverComputer<IHoverMessage[]> {
......@@ -42,10 +42,10 @@ class MarginComputer implements IHoverComputer<IHoverMessage[]> {
}
public computeSync(): IHoverMessage[] {
const hasHoverContent = (contents: MarkedString | MarkedString[]) => {
return contents && (!Array.isArray(contents) || (<MarkedString[]>contents).length > 0);
const hasHoverContent = (contents: IMarkdownString | IMarkdownString[]) => {
return contents && (!Array.isArray(contents) || (<IMarkdownString[]>contents).length > 0);
};
const toHoverMessage = (contents: MarkedString): IHoverMessage => {
const toHoverMessage = (contents: IMarkdownString): IHoverMessage => {
return {
value: contents
};
......@@ -168,7 +168,7 @@ export class ModesGlyphHoverWidget extends GlyphHoverWidget {
const fragment = document.createDocumentFragment();
messages.forEach((msg) => {
const renderedContents = renderMarkedString(msg.value, {
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)
......@@ -185,4 +185,4 @@ export class ModesGlyphHoverWidget extends GlyphHoverWidget {
this.updateContents(fragment);
this.showAt(lineNumber);
}
}
\ No newline at end of file
}
......@@ -26,21 +26,22 @@ import { editorActiveLinkForeground } from 'vs/platform/theme/common/colorRegist
import { Position } from 'vs/editor/common/core/position';
import { ModelDecorationOptions } from 'vs/editor/common/model/textModelWithDecorations';
import { ClickLinkGesture, ClickLinkMouseEvent, ClickLinkKeyboardEvent } from 'vs/editor/contrib/goToDeclaration/browser/clickLinkGesture';
import { MarkdownString } from 'vs/base/common/htmlContent';
const HOVER_MESSAGE_GENERAL_META = (
const HOVER_MESSAGE_GENERAL_META = new MarkdownString().appendText(
platform.isMacintosh
? nls.localize('links.navigate.mac', "Cmd + click to follow link")
: nls.localize('links.navigate', "Ctrl + click to follow link")
);
const HOVER_MESSAGE_COMMAND_META = (
const HOVER_MESSAGE_COMMAND_META = new MarkdownString().appendText(
platform.isMacintosh
? nls.localize('links.command.mac', "Cmd + click to execute command")
: nls.localize('links.command', "Ctrl + click to execute command")
);
const HOVER_MESSAGE_GENERAL_ALT = nls.localize('links.navigate.al', "Alt + click to follow link");
const HOVER_MESSAGE_COMMAND_ALT = nls.localize('links.command.al', "Alt + click to execute command");
const HOVER_MESSAGE_GENERAL_ALT = new MarkdownString().appendText(nls.localize('links.navigate.al', "Alt + click to follow link"));
const HOVER_MESSAGE_COMMAND_ALT = new MarkdownString().appendText(nls.localize('links.command.al', "Alt + click to execute command"));
const decoration = {
meta: ModelDecorationOptions.register({
......
......@@ -12,13 +12,14 @@ import * as dom from 'vs/base/browser/dom';
import { TrackedRangeStickiness } from 'vs/editor/common/editorCommon';
import { ICodeEditor, MouseTargetType } from 'vs/editor/browser/editorBrowser';
import { QuickFixComputeEvent } from './quickFixModel';
import { IMarkdownString } from 'vs/base/common/htmlContent';
export class LightBulbWidget implements IDisposable {
private readonly _options = {
stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,
glyphMarginClassName: 'lightbulb-glyph',
glyphMarginHoverMessage: <string>undefined
glyphMarginHoverMessage: <IMarkdownString>undefined
};
private readonly _editor: ICodeEditor;
......@@ -90,7 +91,7 @@ export class LightBulbWidget implements IDisposable {
}
get title() {
return this._options.glyphMarginHoverMessage;
return this._options.glyphMarginHoverMessage && this._options.glyphMarginHoverMessage.value;
}
show(e: QuickFixComputeEvent): void {
......
......@@ -542,7 +542,7 @@ suite('deltaDecorations', () => {
endColumn: 1
},
options: {
hoverMessage: 'hello1'
hoverMessage: { value: 'hello1' }
}
}]);
......@@ -554,13 +554,13 @@ suite('deltaDecorations', () => {
endColumn: 1
},
options: {
hoverMessage: 'hello2'
hoverMessage: { value: 'hello2' }
}
}]);
let actualDecoration = model.getDecorationOptions(ids[0]);
assert.equal(actualDecoration.hoverMessage, 'hello2');
assert.deepEqual(actualDecoration.hoverMessage, { value: 'hello2' });
model.dispose();
});
......
......@@ -353,12 +353,10 @@ declare module monaco {
static readonly WinCtrl: number;
static chord(firstPart: number, secondPart: number): number;
}
/**
* MarkedString can be used to render human readable text. It is either a markdown string
* or a code-block that provides a language and a code snippet. Note that
* markdown strings will be sanitized - that means html will be escaped.
*/
export type MarkedString = string;
export interface IMarkdownString {
value: string;
enableCommands?: true;
}
export interface IKeyboardEvent {
readonly browserEvent: KeyboardEvent;
......@@ -1115,11 +1113,11 @@ declare module monaco.editor {
/**
* Message to be rendered when hovering over the glyph margin decoration.
*/
glyphMarginHoverMessage?: MarkedString | MarkedString[];
glyphMarginHoverMessage?: IMarkdownString | IMarkdownString[];
/**
* Array of MarkedString to render as the decoration message.
* Array of MarkdownString to render as the decoration message.
*/
hoverMessage?: MarkedString | MarkedString[];
hoverMessage?: IMarkdownString | IMarkdownString[];
/**
* Should the decoration expand to encompass a whole line.
*/
......@@ -4410,7 +4408,7 @@ declare module monaco.languages {
/**
* The contents of this hover.
*/
contents: MarkedString[];
contents: IMarkdownString[];
/**
* The range to which this hover applies. When missing, the
* editor will use the range at the current position or the
......
......@@ -204,7 +204,7 @@ class HoverAdapter {
// we wanna know which extension uses command links
// because that is a potential trick-attack on users
if (result.contents.some(containsCommandLink)) {
if (result.contents.some(h => containsCommandLink(h.value))) {
this._telemetryLog('usesCommandLink', { from: 'hover' });
}
return result;
......
......@@ -16,6 +16,7 @@ import { SaveReason } from 'vs/workbench/services/textfile/common/textfiles';
import { IPosition } from 'vs/editor/common/core/position';
import { IRange } from 'vs/editor/common/core/range';
import { ISelection } from 'vs/editor/common/core/selection';
import { IMarkdownString } from 'vs/base/common/htmlContent';
export interface PositionLike {
line: number;
......@@ -144,14 +145,17 @@ function isDecorationOptionsArr(something: vscode.Range[] | vscode.DecorationOpt
}
export namespace MarkedString {
export function from(markup: vscode.MarkedString): string {
export function from(markup: vscode.MarkedString): IMarkdownString {
if (typeof markup === 'string' || !markup) {
return <string>markup;
return { value: <string>markup, enableCommands: true };
} else {
const { language, value } = markup;
return '```' + language + '\n' + value + '\n```';
return { value: '```' + language + '\n' + value + '\n```' };
}
}
export function to(value: IMarkdownString): vscode.MarkedString {
return value.value;
}
}
export function fromRangeOrRangeWithMessage(ranges: vscode.Range[] | vscode.DecorationOptions[]): IDecorationOptions[] {
......@@ -272,7 +276,7 @@ export function fromHover(hover: vscode.Hover): modes.Hover {
}
export function toHover(info: modes.Hover): types.Hover {
return new types.Hover(info.contents, toRange(info.range));
return new types.Hover(info.contents.map(MarkedString.to), toRange(info.range));
}
export function toDocumentHighlight(occurrence: modes.DocumentHighlight): types.DocumentHighlight {
......
......@@ -14,6 +14,7 @@ import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
import { IDebugService, IBreakpoint, IRawBreakpoint, State } from 'vs/workbench/parts/debug/common/debug';
import { IModelService } from 'vs/editor/common/services/modelService';
import { IModelDecorationsChangedEvent } from 'vs/editor/common/model/textModelEvents';
import { MarkdownString } from 'vs/base/common/htmlContent';
interface IDebugEditorModelData {
model: IModel;
......@@ -284,7 +285,7 @@ export class DebugEditorModelManager implements IWorkbenchContribution {
if (result) {
result = objects.clone(result);
if (breakpoint.message) {
result.glyphMarginHoverMessage = breakpoint.message;
result.glyphMarginHoverMessage = new MarkdownString().appendText(breakpoint.message);
}
if (breakpoint.column) {
result.beforeContentClassName = `debug-breakpoint-column ${result.glyphMarginClassName}-column`;
......@@ -305,7 +306,7 @@ export class DebugEditorModelManager implements IWorkbenchContribution {
} else {
condition = breakpoint.condition ? breakpoint.condition : breakpoint.hitCondition;
}
const glyphMarginHoverMessage = `\`\`\`${modeId}\n${condition}\`\`\``;
const glyphMarginHoverMessage = new MarkdownString().appendCodeblock(modeId, condition);
const glyphMarginClassName = 'debug-breakpoint-conditional-glyph';
const beforeContentClassName = breakpoint.column ? `debug-breakpoint-column ${glyphMarginClassName}-column` : undefined;
......@@ -326,25 +327,25 @@ export class DebugEditorModelManager implements IWorkbenchContribution {
private static BREAKPOINT_DISABLED_DECORATION: IModelDecorationOptions = {
glyphMarginClassName: 'debug-breakpoint-disabled-glyph',
glyphMarginHoverMessage: nls.localize('breakpointDisabledHover', "Disabled Breakpoint"),
glyphMarginHoverMessage: new MarkdownString().appendText(nls.localize('breakpointDisabledHover', "Disabled Breakpoint")),
stickiness
};
private static BREAKPOINT_UNVERIFIED_DECORATION: IModelDecorationOptions = {
glyphMarginClassName: 'debug-breakpoint-unverified-glyph',
glyphMarginHoverMessage: nls.localize('breakpointUnverifieddHover', "Unverified Breakpoint"),
glyphMarginHoverMessage: new MarkdownString().appendText(nls.localize('breakpointUnverifieddHover', "Unverified Breakpoint")),
stickiness
};
private static BREAKPOINT_DIRTY_DECORATION: IModelDecorationOptions = {
glyphMarginClassName: 'debug-breakpoint-unverified-glyph',
glyphMarginHoverMessage: nls.localize('breakpointDirtydHover', "Unverified breakpoint. File is modified, please restart debug session."),
glyphMarginHoverMessage: new MarkdownString().appendText(nls.localize('breakpointDirtydHover', "Unverified breakpoint. File is modified, please restart debug session.")),
stickiness
};
private static BREAKPOINT_UNSUPPORTED_DECORATION: IModelDecorationOptions = {
glyphMarginClassName: 'debug-breakpoint-unsupported-glyph',
glyphMarginHoverMessage: nls.localize('breakpointUnsupported', "Conditional breakpoints not supported by this debug type"),
glyphMarginHoverMessage: new MarkdownString().appendText(nls.localize('breakpointUnsupported', "Conditional breakpoints not supported by this debug type")),
stickiness
};
......
......@@ -7,7 +7,7 @@
import * as nls from 'vs/nls';
import { RunOnceScheduler } from 'vs/base/common/async';
import { MarkedString } from 'vs/base/common/htmlContent';
import { MarkdownString } from 'vs/base/common/htmlContent';
import { KeyCode, KeyMod, KeyChord, SimpleKeybinding } from 'vs/base/common/keyCodes';
import { Disposable } from 'vs/base/common/lifecycle';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
......@@ -289,21 +289,21 @@ export class KeybindingEditorDecorationsRenderer extends Disposable {
}
private _createDecoration(isError: boolean, uiLabel: string, usLabel: string, model: editorCommon.IModel, keyNode: Node): editorCommon.IModelDeltaDecoration {
let msg: MarkedString[];
let msg: MarkdownString;
let className: string;
let beforeContentClassName: string;
let overviewRulerColor: string;
if (isError) {
// this is the error case
msg = [NLS_KB_LAYOUT_ERROR_MESSAGE];
msg = new MarkdownString().appendText(NLS_KB_LAYOUT_ERROR_MESSAGE);
className = 'keybindingError';
beforeContentClassName = 'inlineKeybindingError';
overviewRulerColor = 'rgba(250, 100, 100, 0.6)';
} else {
// this is the info case
if (usLabel && uiLabel !== usLabel) {
msg = [
msg = new MarkdownString(
nls.localize({
key: 'defineKeybinding.kbLayoutLocalAndUSMessage',
comment: [
......@@ -311,9 +311,9 @@ export class KeybindingEditorDecorationsRenderer extends Disposable {
'The placeholders will contain a keyboard combination e.g. Ctrl+Shift+/'
]
}, "**{0}** for your current keyboard layout (**{1}** for US standard).", uiLabel, usLabel)
];
);
} else {
msg = [
msg = new MarkdownString(
nls.localize({
key: 'defineKeybinding.kbLayoutLocalMessage',
comment: [
......@@ -321,7 +321,7 @@ export class KeybindingEditorDecorationsRenderer extends Disposable {
'The placeholder will contain a keyboard combination e.g. Ctrl+Shift+/'
]
}, "**{0}** for your current keyboard layout.", uiLabel)
];
);
}
className = 'keybindingInfo';
beforeContentClassName = 'inlineKeybindingInfo';
......
......@@ -32,6 +32,7 @@ import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/edi
import { ICursorPositionChangedEvent } from 'vs/editor/common/controller/cursorEvents';
import { ModelDecorationOptions } from 'vs/editor/common/model/textModelWithDecorations';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { MarkdownString } from 'vs/base/common/htmlContent';
export interface IPreferencesRenderer<T> extends IDisposable {
preferencesModel: IPreferencesEditorModel<T>;
......@@ -1022,7 +1023,7 @@ class UnsupportedWorkbenchSettingsRenderer extends Disposable {
stickiness: editorCommon.TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,
inlineClassName: 'dim-configuration',
beforeContentClassName: 'unsupportedWorkbenhSettingInfo',
hoverMessage: nls.localize('unsupportedWorkbenchSetting', "This setting cannot be applied now. It will be applied when you open this folder directly.")
hoverMessage: new MarkdownString().appendText(nls.localize('unsupportedWorkbenchSetting', "This setting cannot be applied now. It will be applied when you open this folder directly."))
});
private createDecoration(range: IRange, model: editorCommon.IModel): editorCommon.IModelDeltaDecoration {
......@@ -1097,4 +1098,4 @@ class WorkspaceConfigurationRenderer extends Disposable {
}
super.dispose();
}
}
\ No newline at end of file
}
......@@ -34,6 +34,7 @@ import { Color } from 'vs/base/common/color';
import { SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme';
import { ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing';
import { IMouseEvent } from 'vs/base/browser/mouseEvent';
import { MarkdownString } from 'vs/base/common/htmlContent';
export class SettingsHeaderWidget extends Widget implements IViewZone {
......@@ -621,7 +622,7 @@ export class EditPreferenceWidget<T> extends Disposable {
newDecoration.push({
options: {
glyphMarginClassName: EditPreferenceWidget.GLYPH_MARGIN_CLASS_NAME,
glyphMarginHoverMessage: hoverMessage,
glyphMarginHoverMessage: new MarkdownString().appendText(hoverMessage),
stickiness: editorCommon.TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,
},
range: {
......@@ -646,4 +647,4 @@ export class EditPreferenceWidget<T> extends Disposable {
this.hide();
super.dispose();
}
}
\ No newline at end of file
}
......@@ -446,8 +446,8 @@ suite('ExtHostLanguageFeatures', function () {
return getHover(model, new EditorPosition(1, 1)).then(value => {
assert.equal(value.length, 2);
let [first, second] = value as Hover[];
assert.equal(first.contents[0], 'registered second');
assert.equal(second.contents[0], 'registered first');
assert.equal(first.contents[0].value, 'registered second');
assert.equal(second.contents[0].value, 'registered first');
});
});
});
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册