diff --git a/src/vs/editor/browser/viewParts/minimap/minimap.ts b/src/vs/editor/browser/viewParts/minimap/minimap.ts index 65a8f43f5bb..93f2a8da00f 100644 --- a/src/vs/editor/browser/viewParts/minimap/minimap.ts +++ b/src/vs/editor/browser/viewParts/minimap/minimap.ts @@ -28,7 +28,30 @@ import * as viewEvents from 'vs/editor/common/view/viewEvents'; const enum RenderMinimap { None = 0, Small = 1, - Large = 2 + Large = 2, + Blocks = 3, +} + +function getMinimapLineHeight(renderMinimap: RenderMinimap): number { + if (renderMinimap === RenderMinimap.Large) { + return Constants.x2_CHAR_HEIGHT; + } + if (renderMinimap === RenderMinimap.Small) { + return Constants.x1_CHAR_HEIGHT; + } + // RenderMinimap.Blocks + return 3; +} + +function getMinimapCharWidth(renderMinimap: RenderMinimap): number { + if (renderMinimap === RenderMinimap.Large) { + return Constants.x2_CHAR_WIDTH; + } + if (renderMinimap === RenderMinimap.Small) { + return Constants.x1_CHAR_WIDTH; + } + // RenderMinimap.Blocks + return 1; } class MinimapOptions { @@ -127,7 +150,7 @@ class MinimapLayout { scrollbarSliderCenter: number ) { const pixelRatio = options.pixelRatio; - const minimapLineHeight = (options.renderMinimap === RenderMinimap.Large ? Constants.x2_CHAR_HEIGHT : Constants.x1_CHAR_HEIGHT); + const minimapLineHeight = getMinimapLineHeight(options.renderMinimap); const minimapLinesFitting = Math.floor(options.canvasInnerHeight / minimapLineHeight); const lineHeight = options.lineHeight; @@ -419,7 +442,7 @@ export class Minimap extends ViewPart { if (!this._lastRenderData) { return; } - const minimapLineHeight = (renderMinimap === RenderMinimap.Large ? Constants.x2_CHAR_HEIGHT : Constants.x1_CHAR_HEIGHT); + const minimapLineHeight = getMinimapLineHeight(renderMinimap); const internalOffsetY = this._options.pixelRatio * e.browserEvent.offsetY; const lineIndex = Math.floor(internalOffsetY / minimapLineHeight); @@ -550,7 +573,7 @@ export class Minimap extends ViewPart { const startLineNumber = layout.startLineNumber; const endLineNumber = layout.endLineNumber; - const minimapLineHeight = (renderMinimap === RenderMinimap.Large ? Constants.x2_CHAR_HEIGHT : Constants.x1_CHAR_HEIGHT); + const minimapLineHeight = getMinimapLineHeight(renderMinimap); const imageData = this._getBuffer(); @@ -693,7 +716,7 @@ export class Minimap extends ViewPart { ): void { const content = lineData.content; const tokens = lineData.tokens; - const charWidth = (renderMinimap === RenderMinimap.Large ? Constants.x2_CHAR_WIDTH : Constants.x1_CHAR_WIDTH); + const charWidth = getMinimapCharWidth(renderMinimap); const maxDx = target.width - charWidth; let dx = 0; @@ -724,8 +747,10 @@ export class Minimap extends ViewPart { } else { if (renderMinimap === RenderMinimap.Large) { minimapCharRenderer.x2RenderChar(target, dx, dy, charCode, tokenColor, backgroundColor, useLighterFont); - } else { + } else if (renderMinimap === RenderMinimap.Small) { minimapCharRenderer.x1RenderChar(target, dx, dy, charCode, tokenColor, backgroundColor, useLighterFont); + } else { + minimapCharRenderer.blockRenderChar(target, dx, dy, tokenColor, backgroundColor, useLighterFont); } dx += charWidth; } diff --git a/src/vs/editor/common/config/commonEditorConfig.ts b/src/vs/editor/common/config/commonEditorConfig.ts index 4fbcff01a72..dba1ab9a982 100644 --- a/src/vs/editor/common/config/commonEditorConfig.ts +++ b/src/vs/editor/common/config/commonEditorConfig.ts @@ -185,6 +185,7 @@ class InternalEditorOptionsHelper { scrollbarArrowSize: scrollbar.arrowSize, verticalScrollbarHasArrows: scrollbar.verticalHasArrows, minimap: minimap.enabled, + minimapRenderText: minimap.renderText, pixelRatio: pixelRatio }); @@ -371,7 +372,8 @@ class InternalEditorOptionsHelper { private static _sanitizeMinimapOpts(raw: editorCommon.IEditorMinimapOptions): editorCommon.InternalEditorMinimapOptions { return new editorCommon.InternalEditorMinimapOptions({ - enabled: toBooleanWithDefault(raw.enabled, false) + enabled: toBooleanWithDefault(raw.enabled, false), + renderText: toBooleanWithDefault(raw.renderText, true), }); } } @@ -670,6 +672,11 @@ const editorConfiguration: IConfigurationNode = { 'default': DefaultConfig.editor.minimap.enabled, 'description': nls.localize('minimap.enabled', "Controls if the minimap is shown") }, + 'editor.minimap.renderText': { + 'type': 'boolean', + 'default': DefaultConfig.editor.minimap.renderText, + 'description': nls.localize('minimap.renderText', "Render the actual text on a line (as opposed to color blocks)") + }, 'editor.wordWrap': { 'type': 'string', 'enum': ['off', 'on', 'fixed', 'clamped'], diff --git a/src/vs/editor/common/config/defaultConfig.ts b/src/vs/editor/common/config/defaultConfig.ts index 963fab4e64c..184c8f9780b 100644 --- a/src/vs/editor/common/config/defaultConfig.ts +++ b/src/vs/editor/common/config/defaultConfig.ts @@ -57,7 +57,8 @@ class ConfigClass implements IConfiguration { horizontalHasArrows: false }, minimap: { - enabled: false + enabled: false, + renderText: true }, fixedOverflowWidgets: false, overviewRulerLanes: 2, diff --git a/src/vs/editor/common/editorCommon.ts b/src/vs/editor/common/editorCommon.ts index 6e8c09956c0..d5e2af6718c 100644 --- a/src/vs/editor/common/editorCommon.ts +++ b/src/vs/editor/common/editorCommon.ts @@ -163,6 +163,11 @@ export interface IEditorMinimapOptions { * Defaults to false. */ enabled?: boolean; + /** + * Render the actual text on a line (as opposed to color blocks). + * Defaults to true. + */ + renderText?: boolean; } /** @@ -642,14 +647,17 @@ export class InternalEditorMinimapOptions { readonly _internalEditorMinimapOptionsBrand: void; readonly enabled: boolean; + readonly renderText: boolean; /** * @internal */ constructor(source: { enabled: boolean; + renderText: boolean; }) { this.enabled = Boolean(source.enabled); + this.renderText = Boolean(source.renderText); } /** @@ -658,6 +666,7 @@ export class InternalEditorMinimapOptions { public equals(other: InternalEditorMinimapOptions): boolean { return ( this.enabled === other.enabled + && this.renderText === other.renderText ); } @@ -2815,7 +2824,8 @@ export class OverviewRulerPosition { export enum RenderMinimap { None = 0, Small = 1, - Large = 2 + Large = 2, + Blocks = 3, } /** diff --git a/src/vs/editor/common/view/minimapCharRenderer.ts b/src/vs/editor/common/view/minimapCharRenderer.ts index e829cc911c2..eb244dad094 100644 --- a/src/vs/editor/common/view/minimapCharRenderer.ts +++ b/src/vs/editor/common/view/minimapCharRenderer.ts @@ -34,6 +34,11 @@ export class MinimapTokensColorTracker { private _updateColorMap(): void { const colorMap = TokenizationRegistry.getColorMap(); + if (!colorMap) { + this._colors = [null]; + this._backgroundIsLight = true; + return; + } this._colors = [null]; for (let colorId = 1; colorId < colorMap.length; colorId++) { this._colors[colorId] = colorMap[colorId].toRGBA(); @@ -229,4 +234,43 @@ export class MinimapCharRenderer { dest[destOffset + 2] = backgroundB + deltaB * c; } } + + public blockRenderChar(target: ImageData, dx: number, dy: number, color: RGBA, backgroundColor: RGBA, useLighterFont: boolean): void { + if (dx + Constants.x1_CHAR_WIDTH > target.width || dy + Constants.x1_CHAR_HEIGHT > target.height) { + console.warn('bad render request outside image data'); + return; + } + + const outWidth = target.width * Constants.RGBA_CHANNELS_CNT; + + const c = 0.5; + + const backgroundR = backgroundColor.r; + const backgroundG = backgroundColor.g; + const backgroundB = backgroundColor.b; + + const deltaR = color.r - backgroundR; + const deltaG = color.g - backgroundG; + const deltaB = color.b - backgroundB; + + const colorR = backgroundR + deltaR * c;; + const colorG = backgroundG + deltaG * c; + const colorB = backgroundB + deltaB * c; + + const dest = target.data; + + let destOffset = dy * outWidth + dx * Constants.RGBA_CHANNELS_CNT; + { + dest[destOffset + 0] = colorR; + dest[destOffset + 1] = colorG; + dest[destOffset + 2] = colorB; + } + + destOffset += outWidth; + { + dest[destOffset + 0] = colorR; + dest[destOffset + 1] = colorG; + dest[destOffset + 2] = colorB; + } + } } diff --git a/src/vs/editor/common/viewLayout/editorLayoutProvider.ts b/src/vs/editor/common/viewLayout/editorLayoutProvider.ts index 033fb70539d..23c3621f531 100644 --- a/src/vs/editor/common/viewLayout/editorLayoutProvider.ts +++ b/src/vs/editor/common/viewLayout/editorLayoutProvider.ts @@ -28,6 +28,7 @@ export interface IEditorLayoutProviderOpts { horizontalScrollbarHeight: number; minimap: boolean; + minimapRenderText: boolean; pixelRatio: number; } @@ -48,6 +49,7 @@ export class EditorLayoutProvider { const scrollbarArrowSize = _opts.scrollbarArrowSize | 0; const horizontalScrollbarHeight = _opts.horizontalScrollbarHeight | 0; const minimap = Boolean(_opts.minimap); + const minimapRenderText = Boolean(_opts.minimapRenderText); const pixelRatio = Number(_opts.pixelRatio); let lineNumbersWidth = 0; @@ -77,11 +79,16 @@ export class EditorLayoutProvider { contentWidth = remainingWidth; } else { let minimapCharWidth: number; - if (pixelRatio >= 2) { - renderMinimap = RenderMinimap.Large; - minimapCharWidth = 2 / pixelRatio; + if (minimapRenderText) { + if (pixelRatio >= 2) { + renderMinimap = RenderMinimap.Large; + minimapCharWidth = 2 / pixelRatio; + } else { + renderMinimap = RenderMinimap.Small; + minimapCharWidth = 1 / pixelRatio; + } } else { - renderMinimap = RenderMinimap.Small; + renderMinimap = RenderMinimap.Blocks; minimapCharWidth = 1 / pixelRatio; } diff --git a/src/vs/editor/test/common/viewLayout/editorLayoutProvider.test.ts b/src/vs/editor/test/common/viewLayout/editorLayoutProvider.test.ts index 3e67f31cfe8..f9936e7d48f 100644 --- a/src/vs/editor/test/common/viewLayout/editorLayoutProvider.test.ts +++ b/src/vs/editor/test/common/viewLayout/editorLayoutProvider.test.ts @@ -32,6 +32,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { scrollbarArrowSize: 0, verticalScrollbarHasArrows: false, minimap: false, + minimapRenderText: true, pixelRatio: 1, }, new EditorLayoutInfo({ width: 1000, @@ -86,6 +87,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { scrollbarArrowSize: 13, verticalScrollbarHasArrows: true, minimap: false, + minimapRenderText: true, pixelRatio: 1, }, new EditorLayoutInfo({ width: 1000, @@ -140,6 +142,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { scrollbarArrowSize: 0, verticalScrollbarHasArrows: false, minimap: false, + minimapRenderText: true, pixelRatio: 1, }, new EditorLayoutInfo({ width: 900, @@ -194,6 +197,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { scrollbarArrowSize: 0, verticalScrollbarHasArrows: false, minimap: false, + minimapRenderText: true, pixelRatio: 1, }, new EditorLayoutInfo({ width: 900, @@ -248,6 +252,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { scrollbarArrowSize: 0, verticalScrollbarHasArrows: false, minimap: false, + minimapRenderText: true, pixelRatio: 1, }, new EditorLayoutInfo({ width: 900, @@ -302,6 +307,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { scrollbarArrowSize: 0, verticalScrollbarHasArrows: false, minimap: false, + minimapRenderText: true, pixelRatio: 1, }, new EditorLayoutInfo({ width: 900, @@ -356,6 +362,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { scrollbarArrowSize: 0, verticalScrollbarHasArrows: false, minimap: false, + minimapRenderText: true, pixelRatio: 1, }, new EditorLayoutInfo({ width: 900, @@ -410,6 +417,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { scrollbarArrowSize: 0, verticalScrollbarHasArrows: false, minimap: false, + minimapRenderText: true, pixelRatio: 1, }, new EditorLayoutInfo({ width: 900, @@ -464,6 +472,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { scrollbarArrowSize: 0, verticalScrollbarHasArrows: false, minimap: false, + minimapRenderText: true, pixelRatio: 1, }, new EditorLayoutInfo({ width: 900, @@ -518,6 +527,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { scrollbarArrowSize: 0, verticalScrollbarHasArrows: false, minimap: false, + minimapRenderText: true, pixelRatio: 1, }, new EditorLayoutInfo({ width: 900, @@ -572,6 +582,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { scrollbarArrowSize: 0, verticalScrollbarHasArrows: false, minimap: true, + minimapRenderText: true, pixelRatio: 1, }, new EditorLayoutInfo({ width: 1000, @@ -626,6 +637,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { scrollbarArrowSize: 0, verticalScrollbarHasArrows: false, minimap: true, + minimapRenderText: true, pixelRatio: 2, }, new EditorLayoutInfo({ width: 1000, @@ -680,6 +692,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { scrollbarArrowSize: 0, verticalScrollbarHasArrows: false, minimap: true, + minimapRenderText: true, pixelRatio: 4, }, new EditorLayoutInfo({ width: 1000, diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index 474cffa240d..067d41398b6 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -1085,6 +1085,11 @@ declare module monaco.editor { * Defaults to false. */ enabled?: boolean; + /** + * Render the actual text on a line (as opposed to color blocks). + * Defaults to true. + */ + renderText?: boolean; } /** @@ -1498,6 +1503,7 @@ declare module monaco.editor { export class InternalEditorMinimapOptions { readonly _internalEditorMinimapOptionsBrand: void; readonly enabled: boolean; + readonly renderText: boolean; } export class EditorWrappingInfo { @@ -2590,6 +2596,7 @@ declare module monaco.editor { None = 0, Small = 1, Large = 2, + Blocks = 3, } /**