diff --git a/src/vs/editor/browser/services/codeEditorServiceImpl.ts b/src/vs/editor/browser/services/codeEditorServiceImpl.ts index 9169bfce8f5..f5826bda6ed 100644 --- a/src/vs/editor/browser/services/codeEditorServiceImpl.ts +++ b/src/vs/editor/browser/services/codeEditorServiceImpl.ts @@ -323,8 +323,9 @@ class DecorationRenderHelper { public static getCSSTextForModelDecorationGlyphMarginClassName(opts:IThemeDecorationRenderOptions): string { let cssTextArr = []; - if (typeof opts.gutterIconPath !== 'undefined') { - cssTextArr.push(strings.format(this._CSS_MAP.gutterIconPath, URI.parse(opts.gutterIconPath).toString())); + if (typeof opts.gutterIconUrl !== 'undefined') { + // escape at least the single quote, see https://www.w3.org/TR/CSS1/#url + cssTextArr.push(strings.format(this._CSS_MAP.gutterIconPath, opts.gutterIconUrl.replace(/'/g, '\\\''))); if (typeof opts.gutterIconSize !== 'undefined') { cssTextArr.push(strings.format(this._CSS_MAP.gutterIconSize, opts.gutterIconSize)); } diff --git a/src/vs/editor/common/editorCommon.ts b/src/vs/editor/common/editorCommon.ts index 3dac506d42b..793c91b1c23 100644 --- a/src/vs/editor/common/editorCommon.ts +++ b/src/vs/editor/common/editorCommon.ts @@ -3788,7 +3788,7 @@ export interface IThemeDecorationRenderOptions { color?: string; letterSpacing?: string; - gutterIconPath?: string; + gutterIconUrl?: string; gutterIconSize?: string; overviewRulerColor?: string; diff --git a/src/vs/editor/test/browser/services/decorationRenderOptions.test.ts b/src/vs/editor/test/browser/services/decorationRenderOptions.test.ts index 3d009c2647f..c67cb1d53c0 100644 --- a/src/vs/editor/test/browser/services/decorationRenderOptions.test.ts +++ b/src/vs/editor/test/browser/services/decorationRenderOptions.test.ts @@ -11,7 +11,7 @@ import {IDecorationRenderOptions} from 'vs/editor/common/editorCommon'; suite('Browser Services - EditorLayoutProvider', () => { var options: IDecorationRenderOptions = { - gutterIconPath: 'https://github.com/Microsoft/vscode/blob/master/resources/linux/code.png', + gutterIconUrl: 'https://github.com/Microsoft/vscode/blob/master/resources/linux/code.png', gutterIconSize: 'contain', backgroundColor: 'red', borderColor: 'yellow' diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index a737c7c87af..b3b5164c49f 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -782,9 +782,9 @@ declare namespace vscode { letterSpacing?: string; /** - * An **absolute path** to an image to be rendered in the gutterIconPath. + * An **absolute path** to an image or an URI to be rendered in the gutter. */ - gutterIconPath?: string; + gutterIconPath?: string | Uri; /** * Specifies the size of the gutter icon. diff --git a/src/vs/workbench/api/node/extHostEditors.ts b/src/vs/workbench/api/node/extHostEditors.ts index 98e20ebfd63..500276ded61 100644 --- a/src/vs/workbench/api/node/extHostEditors.ts +++ b/src/vs/workbench/api/node/extHostEditors.ts @@ -163,7 +163,7 @@ class TextEditorDecorationType implements vscode.TextEditorDecorationType { constructor(proxy: MainThreadEditorsShape, options: vscode.DecorationRenderOptions) { this.key = TextEditorDecorationType._Keys.nextId(); this._proxy = proxy; - this._proxy.$registerTextEditorDecorationType(this.key, options); + this._proxy.$registerTextEditorDecorationType(this.key, TypeConverters.fromDecorationRenderOptions(options)); } public dispose(): void { diff --git a/src/vs/workbench/api/node/extHostTypeConverters.ts b/src/vs/workbench/api/node/extHostTypeConverters.ts index 9aebafecfb2..7d2bc3ce463 100644 --- a/src/vs/workbench/api/node/extHostTypeConverters.ts +++ b/src/vs/workbench/api/node/extHostTypeConverters.ts @@ -12,7 +12,7 @@ import { stringDiff } from 'vs/base/common/diff/diff'; import * as modes from 'vs/editor/common/modes'; import * as types from './extHostTypes'; import { Position as EditorPosition } from 'vs/platform/editor/common/editor'; -import { IPosition, ISelection, IRange, IDecorationOptions, ISingleEditOperation } from 'vs/editor/common/editorCommon'; +import { IPosition, ISelection, IRange, IDecorationOptions, IDecorationRenderOptions, ISingleEditOperation } from 'vs/editor/common/editorCommon'; import { IWorkspaceSymbol } from 'vs/workbench/parts/search/common/search'; import * as vscode from 'vscode'; import URI from 'vs/base/common/uri'; @@ -155,6 +155,43 @@ export function fromRangeOrRangeWithMessage(ranges: vscode.Range[] | vscode.Deco } } +export function fromDecorationRenderOptions(options: vscode.DecorationRenderOptions): IDecorationRenderOptions { + + const { + after, + backgroundColor, before, border, borderColor, borderRadius, borderSpacing, borderStyle, borderWidth, + color, cursor, + dark, + gutterIconPath, gutterIconSize, + isWholeLine, + letterSpacing, light, + outline, outlineColor, outlineStyle, outlineWidth, overviewRulerColor, overviewRulerLane, + textDecoration + } = options; + + // properly convert the gutterIconPath to an url + let gutterIconUrl: string; + if (typeof gutterIconPath === 'string') { + gutterIconUrl = URI.file(gutterIconPath).toString(); + } else if (gutterIconPath) { + // don't escape scheme-sensitive and there better don't + // escape at all, it would break http/data/etc links + gutterIconUrl = gutterIconPath.toString(true); + } + + return { + after, + backgroundColor, before, border, borderColor, borderRadius, borderSpacing, borderStyle, borderWidth, + color, cursor, + dark, + gutterIconUrl, gutterIconSize, + isWholeLine, + letterSpacing, light, + outline, outlineColor, outlineStyle, outlineWidth, overviewRulerColor, overviewRulerLane, + textDecoration + }; +} + export const TextEdit = { minimalEditOperations(edits: vscode.TextEdit[], document: vscode.TextDocument, beforeDocumentVersion: number): ISingleEditOperation[] {