diff --git a/src/vs/editor/browser/viewParts/minimap/minimap.ts b/src/vs/editor/browser/viewParts/minimap/minimap.ts index 8301788bdc9900369550276bec42a6813b5e2b96..adc23678bfe03fc593a07366bf026803ef956d87 100644 --- a/src/vs/editor/browser/viewParts/minimap/minimap.ts +++ b/src/vs/editor/browser/viewParts/minimap/minimap.ts @@ -46,7 +46,9 @@ class MinimapOptions { public readonly renderMinimap: RenderMinimap; - public readonly entireDocument: boolean; + public readonly mode: 'actual' | 'cover' | 'contain'; + + public readonly minimapHeightIsEditorHeight: boolean; public readonly scrollBeyondLastLine: boolean; @@ -104,7 +106,8 @@ class MinimapOptions { const minimapOpts = options.get(EditorOption.minimap); this.renderMinimap = layoutInfo.renderMinimap | 0; - this.entireDocument = minimapOpts.entireDocument; + this.mode = minimapOpts.mode; + this.minimapHeightIsEditorHeight = layoutInfo.minimapHeightIsEditorHeight; this.scrollBeyondLastLine = options.get(EditorOption.scrollBeyondLastLine); this.showSlider = minimapOpts.showSlider; this.pixelRatio = pixelRatio; @@ -137,7 +140,8 @@ class MinimapOptions { public equals(other: MinimapOptions): boolean { return (this.renderMinimap === other.renderMinimap - && this.entireDocument === other.entireDocument + && this.mode === other.mode + && this.minimapHeightIsEditorHeight === other.minimapHeightIsEditorHeight && this.scrollBeyondLastLine === other.scrollBeyondLastLine && this.showSlider === other.showSlider && this.pixelRatio === other.pixelRatio @@ -237,7 +241,7 @@ class MinimapLayout { const minimapLinesFitting = Math.floor(options.canvasInnerHeight / minimapLineHeight); const lineHeight = options.lineHeight; - if (options.entireDocument) { + if (options.minimapHeightIsEditorHeight) { const logicalScrollHeight = ( realLineCount * options.lineHeight + (options.scrollBeyondLastLine ? viewportHeight - options.lineHeight : 0) @@ -291,7 +295,7 @@ class MinimapLayout { let extraLinesAtTheBottom = 0; if (options.scrollBeyondLastLine) { const expectedViewportLineCount = viewportHeight / lineHeight; - extraLinesAtTheBottom = expectedViewportLineCount; + extraLinesAtTheBottom = expectedViewportLineCount - 1; } if (minimapLinesFitting >= lineCount + extraLinesAtTheBottom) { // All lines fit in the minimap @@ -531,7 +535,7 @@ class MinimapSamplingState { const pixelRatio = options.get(EditorOption.pixelRatio); const lineHeight = options.get(EditorOption.lineHeight); const scrollBeyondLastLine = options.get(EditorOption.scrollBeyondLastLine); - const { minimapLineCount } = EditorLayoutInfoComputer.computeEntireDocumentMinimapLineCount({ + const { minimapLineCount } = EditorLayoutInfoComputer.computeContainedMinimapLineCount({ modelLineCount: modelLineCount, scrollBeyondLastLine: scrollBeyondLastLine, height: layoutInfo.height, diff --git a/src/vs/editor/common/config/editorOptions.ts b/src/vs/editor/common/config/editorOptions.ts index 2ec1caef507238b31a923fa7ce7a7982f0ecc3a1..07ccf3d6c98db861012f37851dcb78eba655cb8a 100644 --- a/src/vs/editor/common/config/editorOptions.ts +++ b/src/vs/editor/common/config/editorOptions.ts @@ -1686,6 +1686,7 @@ export interface EditorLayoutInfo { * The width of the minimap */ readonly minimapWidth: number; + readonly minimapHeightIsEditorHeight: boolean; readonly minimapIsSampling: boolean; readonly minimapScale: number; readonly minimapLineHeight: number; @@ -1758,7 +1759,7 @@ export class EditorLayoutInfoComputer extends ComputedEditorOption= 2 ? Math.round(minimap.scale * 2) : minimap.scale); const minimapMaxColumn = minimap.maxColumn | 0; - const minimapEntireDocument = minimap.entireDocument; + const minimapMode = minimap.mode; const scrollbar = options.get(EditorOption.scrollbar); const verticalScrollbarWidth = scrollbar.verticalScrollbarSize | 0; @@ -1838,6 +1839,7 @@ export class EditorLayoutInfoComputer extends ComputedEditorOption 1) { + minimapHeightIsEditorHeight = true; minimapIsSampling = true; minimapScale = 1; minimapLineHeight = 1; minimapCharWidth = minimapScale / pixelRatio; } else { - const configuredFontScale = minimapScale; - minimapLineHeight = Math.max(1, Math.floor(1 / desiredRatio)); - minimapScale = Math.min(configuredFontScale + 1, Math.max(1, Math.floor(minimapLineHeight / baseCharHeight))); - if (minimapScale > configuredFontScale) { - minimapWidthMultiplier = Math.min(2, minimapScale / configuredFontScale); + const effectiveMinimapHeight = Math.ceil((modelLineCount + extraLinesBeyondLastLine) * minimapLineHeight); + if (minimapMode === 'cover' || effectiveMinimapHeight > minimapCanvasInnerHeight) { + minimapHeightIsEditorHeight = true; + const configuredFontScale = minimapScale; + minimapLineHeight = Math.max(1, Math.floor(1 / desiredRatio)); + minimapScale = Math.min(configuredFontScale + 1, Math.max(1, Math.floor(minimapLineHeight / baseCharHeight))); + if (minimapScale > configuredFontScale) { + minimapWidthMultiplier = Math.min(2, minimapScale / configuredFontScale); + } + minimapCharWidth = minimapScale / pixelRatio / minimapWidthMultiplier; + minimapCanvasInnerHeight = Math.ceil((modelLineCount + extraLinesBeyondLastLine) * minimapLineHeight); } - minimapCharWidth = minimapScale / pixelRatio / minimapWidthMultiplier; - minimapCanvasInnerHeight = Math.ceil((modelLineCount + extraLinesBeyondLastLine) * minimapLineHeight); } } @@ -1944,6 +1951,7 @@ export class EditorLayoutInfoComputer extends ComputedEditorOption>; @@ -2084,12 +2092,12 @@ class EditorMinimap extends BaseEditorOption(input.mode, this.defaultValue.mode, ['actual', 'cover', 'contain']), side: EditorStringEnumOption.stringSet<'right' | 'left'>(input.side, this.defaultValue.side, ['right', 'left']), showSlider: EditorStringEnumOption.stringSet<'always' | 'mouseover'>(input.showSlider, this.defaultValue.showSlider, ['always', 'mouseover']), renderCharacters: EditorBooleanOption.boolean(input.renderCharacters, this.defaultValue.renderCharacters), scale: EditorIntOption.clampedInt(input.scale, 1, 1, 3), maxColumn: EditorIntOption.clampedInt(input.maxColumn, this.defaultValue.maxColumn, 1, 10000), - entireDocument: EditorBooleanOption.boolean(input.entireDocument, this.defaultValue.entireDocument), }; } } diff --git a/src/vs/editor/test/common/viewLayout/editorLayoutProvider.test.ts b/src/vs/editor/test/common/viewLayout/editorLayoutProvider.test.ts index a69efcd6a929fa3c9f3db3de0e05b81846473a12..f3c94bca5e325d8a83f61990c988de3ac979f5fd 100644 --- a/src/vs/editor/test/common/viewLayout/editorLayoutProvider.test.ts +++ b/src/vs/editor/test/common/viewLayout/editorLayoutProvider.test.ts @@ -33,7 +33,7 @@ interface IEditorLayoutProviderOpts { readonly minimapSide: 'left' | 'right'; readonly minimapRenderCharacters: boolean; readonly minimapMaxColumn: number; - minimapEntireDocument?: boolean; + minimapMode?: 'actual' | 'cover' | 'contain'; readonly pixelRatio: number; } @@ -47,12 +47,12 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { options._write(EditorOption.folding, false); const minimapOptions: EditorMinimapOptions = { enabled: input.minimap, + mode: input.minimapMode || 'actual', side: input.minimapSide, renderCharacters: input.minimapRenderCharacters, maxColumn: input.minimapMaxColumn, showSlider: 'mouseover', scale: 1, - entireDocument: input.minimapEntireDocument || false }; options._write(EditorOption.minimap, minimapOptions); const scrollbarOptions: InternalEditorScrollbarOptions = { @@ -129,6 +129,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { renderMinimap: RenderMinimap.None, minimapLeft: 0, minimapWidth: 0, + minimapHeightIsEditorHeight: false, minimapIsSampling: false, minimapScale: 1, minimapLineHeight: 1, @@ -190,6 +191,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { renderMinimap: RenderMinimap.None, minimapLeft: 0, minimapWidth: 0, + minimapHeightIsEditorHeight: false, minimapIsSampling: false, minimapScale: 1, minimapLineHeight: 1, @@ -251,6 +253,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { renderMinimap: RenderMinimap.None, minimapLeft: 0, minimapWidth: 0, + minimapHeightIsEditorHeight: false, minimapIsSampling: false, minimapScale: 1, minimapLineHeight: 1, @@ -312,6 +315,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { renderMinimap: RenderMinimap.None, minimapLeft: 0, minimapWidth: 0, + minimapHeightIsEditorHeight: false, minimapIsSampling: false, minimapScale: 1, minimapLineHeight: 1, @@ -373,6 +377,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { renderMinimap: RenderMinimap.None, minimapLeft: 0, minimapWidth: 0, + minimapHeightIsEditorHeight: false, minimapIsSampling: false, minimapScale: 1, minimapLineHeight: 1, @@ -434,6 +439,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { renderMinimap: RenderMinimap.None, minimapLeft: 0, minimapWidth: 0, + minimapHeightIsEditorHeight: false, minimapIsSampling: false, minimapScale: 1, minimapLineHeight: 1, @@ -495,6 +501,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { renderMinimap: RenderMinimap.None, minimapLeft: 0, minimapWidth: 0, + minimapHeightIsEditorHeight: false, minimapIsSampling: false, minimapScale: 1, minimapLineHeight: 1, @@ -556,6 +563,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { renderMinimap: RenderMinimap.None, minimapLeft: 0, minimapWidth: 0, + minimapHeightIsEditorHeight: false, minimapIsSampling: false, minimapScale: 1, minimapLineHeight: 1, @@ -617,6 +625,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { renderMinimap: RenderMinimap.None, minimapLeft: 0, minimapWidth: 0, + minimapHeightIsEditorHeight: false, minimapIsSampling: false, minimapScale: 1, minimapLineHeight: 1, @@ -678,6 +687,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { renderMinimap: RenderMinimap.None, minimapLeft: 0, minimapWidth: 0, + minimapHeightIsEditorHeight: false, minimapIsSampling: false, minimapScale: 1, minimapLineHeight: 1, @@ -739,6 +749,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { renderMinimap: RenderMinimap.Text, minimapLeft: 903, minimapWidth: 97, + minimapHeightIsEditorHeight: false, minimapIsSampling: false, minimapScale: 1, minimapLineHeight: 2, @@ -800,6 +811,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { renderMinimap: RenderMinimap.Text, minimapLeft: 903, minimapWidth: 97, + minimapHeightIsEditorHeight: false, minimapIsSampling: false, minimapScale: 2, minimapLineHeight: 4, @@ -861,6 +873,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { renderMinimap: RenderMinimap.Text, minimapLeft: 945, minimapWidth: 55, + minimapHeightIsEditorHeight: false, minimapIsSampling: false, minimapScale: 2, minimapLineHeight: 4, @@ -922,6 +935,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { renderMinimap: RenderMinimap.Text, minimapLeft: 0, minimapWidth: 55, + minimapHeightIsEditorHeight: false, minimapIsSampling: false, minimapScale: 2, minimapLineHeight: 4, @@ -943,7 +957,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { }); }); - test('EditorLayoutProvider 11 - render entire document in minimap without sampling', () => { + test('EditorLayoutProvider 11 - minimap mode cover without sampling', () => { doTest({ outerWidth: 1000, outerHeight: 800, @@ -964,7 +978,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { minimapSide: 'right', minimapRenderCharacters: true, minimapMaxColumn: 150, - minimapEntireDocument: true, + minimapMode: 'cover', pixelRatio: 2, }, { width: 1000, @@ -980,19 +994,148 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { decorationsWidth: 10, contentLeft: 10, - contentWidth: 818, + contentWidth: 893, renderMinimap: RenderMinimap.Text, - minimapLeft: 828, - minimapWidth: 172, + minimapLeft: 903, + minimapWidth: 97, + minimapHeightIsEditorHeight: true, minimapIsSampling: false, - minimapScale: 4, + minimapScale: 3, minimapLineHeight: 13, - minimapCanvasInnerWidth: 344, + minimapCanvasInnerWidth: 291, minimapCanvasInnerHeight: 1560, - minimapCanvasOuterWidth: 172, + minimapCanvasOuterWidth: 97, minimapCanvasOuterHeight: 800, - viewportColumn: 81, + viewportColumn: 89, + + verticalScrollbarWidth: 0, + horizontalScrollbarHeight: 0, + + overviewRuler: { + top: 0, + width: 0, + height: 800, + right: 0 + } + }); + }); + + test('EditorLayoutProvider 12 - minimap mode cover with sampling', () => { + doTest({ + outerWidth: 1000, + outerHeight: 800, + showGlyphMargin: false, + lineHeight: 16, + showLineNumbers: false, + lineNumbersMinChars: 0, + lineNumbersDigitCount: 4, + maxLineNumber: 2500, + lineDecorationsWidth: 10, + typicalHalfwidthCharacterWidth: 10, + maxDigitWidth: 10, + verticalScrollbarWidth: 0, + horizontalScrollbarHeight: 0, + scrollbarArrowSize: 0, + verticalScrollbarHasArrows: false, + minimap: true, + minimapSide: 'right', + minimapRenderCharacters: true, + minimapMaxColumn: 150, + minimapMode: 'cover', + pixelRatio: 2, + }, { + width: 1000, + height: 800, + + glyphMarginLeft: 0, + glyphMarginWidth: 0, + + lineNumbersLeft: 0, + lineNumbersWidth: 0, + + decorationsLeft: 0, + decorationsWidth: 10, + + contentLeft: 10, + contentWidth: 935, + + renderMinimap: RenderMinimap.Text, + minimapLeft: 945, + minimapWidth: 55, + minimapHeightIsEditorHeight: true, + minimapIsSampling: true, + minimapScale: 1, + minimapLineHeight: 1, + minimapCanvasInnerWidth: 110, + minimapCanvasInnerHeight: 1600, + minimapCanvasOuterWidth: 55, + minimapCanvasOuterHeight: 800, + viewportColumn: 93, + + verticalScrollbarWidth: 0, + horizontalScrollbarHeight: 0, + + overviewRuler: { + top: 0, + width: 0, + height: 800, + right: 0 + } + }); + }); + + test('EditorLayoutProvider 13 - minimap mode contain without sampling', () => { + doTest({ + outerWidth: 1000, + outerHeight: 800, + showGlyphMargin: false, + lineHeight: 16, + showLineNumbers: false, + lineNumbersMinChars: 0, + lineNumbersDigitCount: 3, + maxLineNumber: 120, + lineDecorationsWidth: 10, + typicalHalfwidthCharacterWidth: 10, + maxDigitWidth: 10, + verticalScrollbarWidth: 0, + horizontalScrollbarHeight: 0, + scrollbarArrowSize: 0, + verticalScrollbarHasArrows: false, + minimap: true, + minimapSide: 'right', + minimapRenderCharacters: true, + minimapMaxColumn: 150, + minimapMode: 'contain', + pixelRatio: 2, + }, { + width: 1000, + height: 800, + + glyphMarginLeft: 0, + glyphMarginWidth: 0, + + lineNumbersLeft: 0, + lineNumbersWidth: 0, + + decorationsLeft: 0, + decorationsWidth: 10, + + contentLeft: 10, + contentWidth: 893, + + renderMinimap: RenderMinimap.Text, + minimapLeft: 903, + minimapWidth: 97, + minimapHeightIsEditorHeight: false, + minimapIsSampling: false, + minimapScale: 2, + minimapLineHeight: 4, + minimapCanvasInnerWidth: 194, + minimapCanvasInnerHeight: 1600, + minimapCanvasOuterWidth: 97, + minimapCanvasOuterHeight: 800, + viewportColumn: 89, verticalScrollbarWidth: 0, horizontalScrollbarHeight: 0, @@ -1006,7 +1149,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { }); }); - test('EditorLayoutProvider 12 - render entire document in minimap with sampling', () => { + test('EditorLayoutProvider 14 - minimap mode contain with sampling', () => { doTest({ outerWidth: 1000, outerHeight: 800, @@ -1027,7 +1170,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { minimapSide: 'right', minimapRenderCharacters: true, minimapMaxColumn: 150, - minimapEntireDocument: true, + minimapMode: 'contain', pixelRatio: 2, }, { width: 1000, @@ -1048,6 +1191,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { renderMinimap: RenderMinimap.Text, minimapLeft: 945, minimapWidth: 55, + minimapHeightIsEditorHeight: true, minimapIsSampling: true, minimapScale: 1, minimapLineHeight: 1, @@ -1109,6 +1253,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { renderMinimap: RenderMinimap.Text, minimapLeft: 1096, minimapWidth: 91, + minimapHeightIsEditorHeight: false, minimapIsSampling: false, minimapScale: 2, minimapLineHeight: 4, diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index 105a3a08e0cecaeeb47ac51d2a16a2115a87e5b8..d5aae368b6af42cf9f69d4c1ff3aa8bab85460fa 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -3330,6 +3330,7 @@ declare namespace monaco.editor { * The width of the minimap */ readonly minimapWidth: number; + readonly minimapHeightIsEditorHeight: boolean; readonly minimapIsSampling: boolean; readonly minimapScale: number; readonly minimapLineHeight: number; @@ -3386,6 +3387,11 @@ declare namespace monaco.editor { * Defaults to 'right'. */ side?: 'right' | 'left'; + /** + * Control the minimap rendering mode. + * Defaults to 'actual'. + */ + mode?: 'actual' | 'cover' | 'contain'; /** * Control the rendering of the minimap slider. * Defaults to 'mouseover'. @@ -3405,10 +3411,6 @@ declare namespace monaco.editor { * Relative size of the font in the minimap. Defaults to 1. */ scale?: number; - /** - * Minimap covers entire document. - */ - entireDocument?: boolean; } export type EditorMinimapOptions = Readonly>;