diff --git a/src/vs/editor/browser/controller/mouseTarget.ts b/src/vs/editor/browser/controller/mouseTarget.ts index 0e21b9588b5f6..436f7a969676e 100644 --- a/src/vs/editor/browser/controller/mouseTarget.ts +++ b/src/vs/editor/browser/controller/mouseTarget.ts @@ -364,7 +364,7 @@ abstract class BareHitTestRequest { this.mouseVerticalOffset = Math.max(0, ctx.getCurrentScrollTop() + pos.y - editorPos.y); this.mouseContentHorizontalOffset = ctx.getCurrentScrollLeft() + pos.x - editorPos.x - ctx.layoutInfo.contentLeft; - this.isInMarginArea = (pos.x - editorPos.x < ctx.layoutInfo.contentLeft); + this.isInMarginArea = (pos.x - editorPos.x < ctx.layoutInfo.contentLeft && pos.x - editorPos.x >= ctx.layoutInfo.glyphMarginLeft); this.isInContentArea = !this.isInMarginArea; this.mouseColumn = Math.max(0, MouseTargetFactory._getMouseColumn(this.mouseContentHorizontalOffset, ctx.typicalHalfwidthCharacterWidth)); } @@ -587,6 +587,8 @@ export class MouseTargetFactory { offsetX: offset }; + offset -= ctx.layoutInfo.glyphMarginLeft; + if (offset <= ctx.layoutInfo.glyphMarginWidth) { // On the glyph margin return request.fulfill(MouseTargetType.GUTTER_GLYPH_MARGIN, pos, res.range, detail); diff --git a/src/vs/editor/browser/viewParts/editorScrollbar/editorScrollbar.ts b/src/vs/editor/browser/viewParts/editorScrollbar/editorScrollbar.ts index 73ae56f5e380c..ed1121cfcdd72 100644 --- a/src/vs/editor/browser/viewParts/editorScrollbar/editorScrollbar.ts +++ b/src/vs/editor/browser/viewParts/editorScrollbar/editorScrollbar.ts @@ -99,7 +99,13 @@ export class EditorScrollbar extends ViewPart { const layoutInfo = this._context.configuration.editor.layoutInfo; this.scrollbarDomNode.setLeft(layoutInfo.contentLeft); - this.scrollbarDomNode.setWidth(layoutInfo.contentWidth + layoutInfo.minimapWidth); + + const side = this._context.configuration.editor.viewInfo.minimap.side; + if (side === 'right') { + this.scrollbarDomNode.setWidth(layoutInfo.contentWidth + layoutInfo.minimapWidth); + } else { + this.scrollbarDomNode.setWidth(layoutInfo.contentWidth); + } this.scrollbarDomNode.setHeight(layoutInfo.contentHeight); } diff --git a/src/vs/editor/browser/viewParts/minimap/minimap.ts b/src/vs/editor/browser/viewParts/minimap/minimap.ts index 62c2629841d34..b1da0a53ed606 100644 --- a/src/vs/editor/browser/viewParts/minimap/minimap.ts +++ b/src/vs/editor/browser/viewParts/minimap/minimap.ts @@ -82,6 +82,10 @@ class MinimapOptions { public readonly lineHeight: number; + /** + * container dom node left position (in CSS px) + */ + public readonly minimapLeft: number; /** * container dom node width (in CSS px) */ @@ -121,6 +125,7 @@ class MinimapOptions { this.pixelRatio = pixelRatio; this.typicalHalfwidthCharacterWidth = fontInfo.typicalHalfwidthCharacterWidth; this.lineHeight = configuration.editor.lineHeight; + this.minimapLeft = layoutInfo.minimapLeft; this.minimapWidth = layoutInfo.minimapWidth; this.minimapHeight = layoutInfo.height; @@ -138,6 +143,7 @@ class MinimapOptions { && this.pixelRatio === other.pixelRatio && this.typicalHalfwidthCharacterWidth === other.typicalHalfwidthCharacterWidth && this.lineHeight === other.lineHeight + && this.minimapLeft === other.minimapLeft && this.minimapWidth === other.minimapWidth && this.minimapHeight === other.minimapHeight && this.canvasInnerWidth === other.canvasInnerWidth @@ -456,7 +462,6 @@ export class Minimap extends ViewPart { this._domNode.setPosition('absolute'); this._domNode.setAttribute('role', 'presentation'); this._domNode.setAttribute('aria-hidden', 'true'); - this._domNode.setRight(this._context.configuration.editor.layoutInfo.verticalScrollbarWidth); this._shadow = createFastDomNode(document.createElement('div')); this._shadow.setClassName('minimap-shadow-hidden'); @@ -563,6 +568,7 @@ export class Minimap extends ViewPart { } private _applyLayout(): void { + this._domNode.setLeft(this._options.minimapLeft); this._domNode.setWidth(this._options.minimapWidth); this._domNode.setHeight(this._options.minimapHeight); this._shadow.setHeight(this._options.minimapHeight); diff --git a/src/vs/editor/common/config/commonEditorConfig.ts b/src/vs/editor/common/config/commonEditorConfig.ts index a51f6df0ba1c3..6f6f9040b52db 100644 --- a/src/vs/editor/common/config/commonEditorConfig.ts +++ b/src/vs/editor/common/config/commonEditorConfig.ts @@ -264,6 +264,12 @@ const editorConfiguration: IConfigurationNode = { 'default': EDITOR_DEFAULTS.viewInfo.minimap.enabled, 'description': nls.localize('minimap.enabled', "Controls if the minimap is shown") }, + 'editor.minimap.side': { + 'type': 'string', + 'enum': ['left', 'right'], + 'default': EDITOR_DEFAULTS.viewInfo.minimap.side, + 'description': nls.localize('minimap.side', "Controls the side where to render the minimap. Possible values are \'right\' and \'left\'") + }, 'editor.minimap.showSlider': { 'type': 'string', 'enum': ['always', 'mouseover'], diff --git a/src/vs/editor/common/config/editorOptions.ts b/src/vs/editor/common/config/editorOptions.ts index c230f0088e2a1..442d8e9cff782 100644 --- a/src/vs/editor/common/config/editorOptions.ts +++ b/src/vs/editor/common/config/editorOptions.ts @@ -102,6 +102,11 @@ export interface IEditorMinimapOptions { * Defaults to false. */ enabled?: boolean; + /** + * Control the side of the minimap in editor. + * Defaults to 'right'. + */ + side?: 'right' | 'left'; /** * Control the rendering of the minimap slider. * Defaults to 'mouseover'. @@ -740,6 +745,7 @@ export interface InternalEditorScrollbarOptions { export interface InternalEditorMinimapOptions { readonly enabled: boolean; + readonly side: 'right' | 'left'; readonly showSlider: 'always' | 'mouseover'; readonly renderCharacters: boolean; readonly maxColumn: number; @@ -1019,6 +1025,7 @@ export class InternalEditorOptions { && a.contentWidth === b.contentWidth && a.contentHeight === b.contentHeight && a.renderMinimap === b.renderMinimap + && a.minimapLeft === b.minimapLeft && a.minimapWidth === b.minimapWidth && a.viewportColumn === b.viewportColumn && a.verticalScrollbarWidth === b.verticalScrollbarWidth @@ -1101,6 +1108,7 @@ export class InternalEditorOptions { private static _equalsMinimapOptions(a: InternalEditorMinimapOptions, b: InternalEditorMinimapOptions): boolean { return ( a.enabled === b.enabled + && a.side === b.side && a.showSlider === b.showSlider && a.renderCharacters === b.renderCharacters && a.maxColumn === b.maxColumn @@ -1288,6 +1296,10 @@ export interface EditorLayoutInfo { */ readonly contentHeight: number; + /** + * The position for the minimap + */ + readonly minimapLeft: number; /** * The width of the minimap */ @@ -1553,6 +1565,7 @@ export class EditorOptionsValidator { } return { enabled: _boolean(opts.enabled, defaults.enabled), + side: _stringSet<'right' | 'left'>(opts.side, defaults.side, ['right', 'left']), showSlider: _stringSet<'always' | 'mouseover'>(opts.showSlider, defaults.showSlider, ['always', 'mouseover']), renderCharacters: _boolean(opts.renderCharacters, defaults.renderCharacters), maxColumn: _clampedInt(opts.maxColumn, defaults.maxColumn, 1, 10000), @@ -1769,6 +1782,7 @@ export class InternalEditorOptionsFactory { scrollbar: opts.viewInfo.scrollbar, minimap: { enabled: (accessibilityIsOn ? false : opts.viewInfo.minimap.enabled), // DISABLED WHEN SCREEN READER IS ATTACHED + side: opts.viewInfo.minimap.side, renderCharacters: opts.viewInfo.minimap.renderCharacters, showSlider: opts.viewInfo.minimap.showSlider, maxColumn: opts.viewInfo.minimap.maxColumn @@ -1850,6 +1864,7 @@ export class InternalEditorOptionsFactory { scrollbarArrowSize: opts.viewInfo.scrollbar.arrowSize, verticalScrollbarHasArrows: opts.viewInfo.scrollbar.verticalHasArrows, minimap: opts.viewInfo.minimap.enabled, + minimapSide: opts.viewInfo.minimap.side, minimapRenderCharacters: opts.viewInfo.minimap.renderCharacters, minimapMaxColumn: opts.viewInfo.minimap.maxColumn, pixelRatio: env.pixelRatio @@ -1982,6 +1997,7 @@ export interface IEditorLayoutProviderOpts { horizontalScrollbarHeight: number; minimap: boolean; + minimapSide: string; minimapRenderCharacters: boolean; minimapMaxColumn: number; pixelRatio: number; @@ -2007,6 +2023,7 @@ export class EditorLayoutProvider { const scrollbarArrowSize = _opts.scrollbarArrowSize | 0; const horizontalScrollbarHeight = _opts.horizontalScrollbarHeight | 0; const minimap = _opts.minimap; + const minimapSide = _opts.minimapSide; const minimapRenderCharacters = _opts.minimapRenderCharacters; const minimapMaxColumn = _opts.minimapMaxColumn | 0; const pixelRatio = _opts.pixelRatio; @@ -2022,17 +2039,19 @@ export class EditorLayoutProvider { glyphMarginWidth = lineHeight; } - const glyphMarginLeft = 0; - const lineNumbersLeft = glyphMarginLeft + glyphMarginWidth; - const decorationsLeft = lineNumbersLeft + lineNumbersWidth; - const contentLeft = decorationsLeft + lineDecorationsWidth; + let glyphMarginLeft = 0; + let lineNumbersLeft = glyphMarginLeft + glyphMarginWidth; + let decorationsLeft = lineNumbersLeft + lineNumbersWidth; + let contentLeft = decorationsLeft + lineDecorationsWidth; const remainingWidth = outerWidth - glyphMarginWidth - lineNumbersWidth - lineDecorationsWidth; let renderMinimap: RenderMinimap; + let minimapLeft: number; let minimapWidth: number; let contentWidth: number; if (!minimap) { + minimapLeft = 0; minimapWidth = 0; renderMinimap = RenderMinimap.None; contentWidth = remainingWidth; @@ -2064,6 +2083,16 @@ export class EditorLayoutProvider { minimapWidth = Math.floor(minimapMaxColumn * minimapCharWidth); } contentWidth = remainingWidth - minimapWidth; + + if (minimapSide === 'left') { + minimapLeft = 0; + glyphMarginLeft += minimapWidth; + lineNumbersLeft += minimapWidth; + decorationsLeft += minimapWidth; + contentLeft += minimapWidth; + } else { + minimapLeft = outerWidth - minimapWidth - verticalScrollbarWidth; + } } const viewportColumn = Math.max(1, Math.floor((contentWidth - verticalScrollbarWidth) / typicalHalfwidthCharacterWidth)); @@ -2091,6 +2120,7 @@ export class EditorLayoutProvider { contentHeight: outerHeight, renderMinimap: renderMinimap, + minimapLeft: minimapLeft, minimapWidth: minimapWidth, viewportColumn: viewportColumn, @@ -2206,6 +2236,7 @@ export const EDITOR_DEFAULTS: IValidatedEditorOptions = { }, minimap: { enabled: true, + side: 'right', showSlider: 'mouseover', renderCharacters: true, maxColumn: 120 diff --git a/src/vs/editor/test/common/viewLayout/editorLayoutProvider.test.ts b/src/vs/editor/test/common/viewLayout/editorLayoutProvider.test.ts index 53ac8d481a61b..eddae34ccc27b 100644 --- a/src/vs/editor/test/common/viewLayout/editorLayoutProvider.test.ts +++ b/src/vs/editor/test/common/viewLayout/editorLayoutProvider.test.ts @@ -31,6 +31,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { scrollbarArrowSize: 0, verticalScrollbarHasArrows: false, minimap: false, + minimapSide: 'right', minimapRenderCharacters: true, minimapMaxColumn: 150, pixelRatio: 1, @@ -55,6 +56,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { contentHeight: 800, renderMinimap: RenderMinimap.None, + minimapLeft: 0, minimapWidth: 0, viewportColumn: 99, @@ -87,6 +89,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { scrollbarArrowSize: 13, verticalScrollbarHasArrows: true, minimap: false, + minimapSide: 'right', minimapRenderCharacters: true, minimapMaxColumn: 150, pixelRatio: 1, @@ -111,6 +114,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { contentHeight: 800, renderMinimap: RenderMinimap.None, + minimapLeft: 0, minimapWidth: 0, viewportColumn: 97, @@ -143,6 +147,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { scrollbarArrowSize: 0, verticalScrollbarHasArrows: false, minimap: false, + minimapSide: 'right', minimapRenderCharacters: true, minimapMaxColumn: 150, pixelRatio: 1, @@ -167,6 +172,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { contentHeight: 800, renderMinimap: RenderMinimap.None, + minimapLeft: 0, minimapWidth: 0, viewportColumn: 89, @@ -199,6 +205,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { scrollbarArrowSize: 0, verticalScrollbarHasArrows: false, minimap: false, + minimapSide: 'right', minimapRenderCharacters: true, minimapMaxColumn: 150, pixelRatio: 1, @@ -223,6 +230,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { contentHeight: 900, renderMinimap: RenderMinimap.None, + minimapLeft: 0, minimapWidth: 0, viewportColumn: 89, @@ -255,6 +263,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { scrollbarArrowSize: 0, verticalScrollbarHasArrows: false, minimap: false, + minimapSide: 'right', minimapRenderCharacters: true, minimapMaxColumn: 150, pixelRatio: 1, @@ -279,6 +288,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { contentHeight: 900, renderMinimap: RenderMinimap.None, + minimapLeft: 0, minimapWidth: 0, viewportColumn: 89, @@ -311,6 +321,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { scrollbarArrowSize: 0, verticalScrollbarHasArrows: false, minimap: false, + minimapSide: 'right', minimapRenderCharacters: true, minimapMaxColumn: 150, pixelRatio: 1, @@ -335,6 +346,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { contentHeight: 900, renderMinimap: RenderMinimap.None, + minimapLeft: 0, minimapWidth: 0, viewportColumn: 84, @@ -367,6 +379,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { scrollbarArrowSize: 0, verticalScrollbarHasArrows: false, minimap: false, + minimapSide: 'right', minimapRenderCharacters: true, minimapMaxColumn: 150, pixelRatio: 1, @@ -391,6 +404,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { contentHeight: 900, renderMinimap: RenderMinimap.None, + minimapLeft: 0, minimapWidth: 0, viewportColumn: 84, @@ -423,6 +437,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { scrollbarArrowSize: 0, verticalScrollbarHasArrows: false, minimap: false, + minimapSide: 'right', minimapRenderCharacters: true, minimapMaxColumn: 150, pixelRatio: 1, @@ -447,6 +462,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { contentHeight: 900, renderMinimap: RenderMinimap.None, + minimapLeft: 0, minimapWidth: 0, viewportColumn: 83, @@ -479,6 +495,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { scrollbarArrowSize: 0, verticalScrollbarHasArrows: false, minimap: false, + minimapSide: 'right', minimapRenderCharacters: true, minimapMaxColumn: 150, pixelRatio: 1, @@ -503,6 +520,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { contentHeight: 900, renderMinimap: RenderMinimap.None, + minimapLeft: 0, minimapWidth: 0, viewportColumn: 172, @@ -535,6 +553,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { scrollbarArrowSize: 0, verticalScrollbarHasArrows: false, minimap: false, + minimapSide: 'right', minimapRenderCharacters: true, minimapMaxColumn: 150, pixelRatio: 1, @@ -559,6 +578,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { contentHeight: 900, renderMinimap: RenderMinimap.None, + minimapLeft: 0, minimapWidth: 0, viewportColumn: 170, @@ -591,6 +611,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { scrollbarArrowSize: 0, verticalScrollbarHasArrows: false, minimap: true, + minimapSide: 'right', minimapRenderCharacters: true, minimapMaxColumn: 150, pixelRatio: 1, @@ -615,6 +636,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { contentHeight: 800, renderMinimap: RenderMinimap.Small, + minimapLeft: 910, minimapWidth: 90, viewportColumn: 90, @@ -647,6 +669,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { scrollbarArrowSize: 0, verticalScrollbarHasArrows: false, minimap: true, + minimapSide: 'right', minimapRenderCharacters: true, minimapMaxColumn: 150, pixelRatio: 2, @@ -671,6 +694,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { contentHeight: 800, renderMinimap: RenderMinimap.Large, + minimapLeft: 910, minimapWidth: 90, viewportColumn: 90, @@ -703,6 +727,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { scrollbarArrowSize: 0, verticalScrollbarHasArrows: false, minimap: true, + minimapSide: 'right', minimapRenderCharacters: true, minimapMaxColumn: 150, pixelRatio: 4, @@ -727,6 +752,65 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { contentHeight: 800, renderMinimap: RenderMinimap.Large, + minimapLeft: 953, + minimapWidth: 47, + viewportColumn: 94, + + verticalScrollbarWidth: 0, + horizontalScrollbarHeight: 0, + + overviewRuler: { + top: 0, + width: 0, + height: 800, + right: 0 + } + }); + }); + + test('EditorLayoutProvider 10 - render minimap to left', () => { + doTest({ + outerWidth: 1000, + outerHeight: 800, + showGlyphMargin: false, + lineHeight: 16, + showLineNumbers: false, + lineNumbersMinChars: 0, + lineNumbersDigitCount: 1, + lineDecorationsWidth: 10, + typicalHalfwidthCharacterWidth: 10, + maxDigitWidth: 10, + verticalScrollbarWidth: 0, + horizontalScrollbarHeight: 0, + scrollbarArrowSize: 0, + verticalScrollbarHasArrows: false, + minimap: true, + minimapSide: 'left', + minimapRenderCharacters: true, + minimapMaxColumn: 150, + pixelRatio: 4, + }, { + width: 1000, + height: 800, + + glyphMarginLeft: 47, + glyphMarginWidth: 0, + glyphMarginHeight: 800, + + lineNumbersLeft: 47, + lineNumbersWidth: 0, + lineNumbersHeight: 800, + + decorationsLeft: 47, + decorationsWidth: 10, + decorationsHeight: 800, + + contentLeft: 57, + contentWidth: 943, + contentHeight: 800, + + renderMinimap: RenderMinimap.Large, + minimapLeft: 0, minimapWidth: 47, viewportColumn: 94, diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index fcaccb90a61ab..2bf4f6caafb55 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -2395,6 +2395,11 @@ declare module monaco.editor { * Defaults to false. */ enabled?: boolean; + /** + * Control the side of the minimap in editor. + * Defaults to 'right'. + */ + side?: 'right' | 'left'; /** * Control the rendering of the minimap slider. * Defaults to 'mouseover'. @@ -2961,6 +2966,7 @@ declare module monaco.editor { export interface InternalEditorMinimapOptions { readonly enabled: boolean; + readonly side: 'right' | 'left'; readonly showSlider: 'always' | 'mouseover'; readonly renderCharacters: boolean; readonly maxColumn: number; @@ -3162,6 +3168,10 @@ declare module monaco.editor { * The height of the content (actual height) */ readonly contentHeight: number; + /** + * The position for the minimap + */ + readonly minimapLeft: number; /** * The width of the minimap */ diff --git a/src/vs/platform/telemetry/common/telemetryUtils.ts b/src/vs/platform/telemetry/common/telemetryUtils.ts index 41c3db8d63fd5..1b3b0233b7b60 100644 --- a/src/vs/platform/telemetry/common/telemetryUtils.ts +++ b/src/vs/platform/telemetry/common/telemetryUtils.ts @@ -75,6 +75,7 @@ const configurationValueWhitelist = [ 'editor.roundedSelection', 'editor.scrollBeyondLastLine', 'editor.minimap.enabled', + 'editor.minimap.side', 'editor.minimap.renderCharacters', 'editor.minimap.maxColumn', 'editor.find.seedSearchStringFromSelection',