UNPKG

monaco-editor

Version:
671 lines (670 loc) • 34.9 kB
/*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ var __extends = (this && this.__extends) || (function () { var extendStatics = function (d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; return extendStatics(d, b); } return function (d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); import './minimap.css'; import * as dom from '../../../../base/browser/dom.js'; import { createFastDomNode } from '../../../../base/browser/fastDomNode.js'; import { GlobalMouseMoveMonitor, standardMouseMoveMerger } from '../../../../base/browser/globalMouseMoveMonitor.js'; import * as platform from '../../../../base/common/platform.js'; import * as strings from '../../../../base/common/strings.js'; import { RenderedLinesCollection } from '../../view/viewLayer.js'; import { PartFingerprints, ViewPart } from '../../view/viewPart.js'; import { Range } from '../../../common/core/range.js'; import { MinimapTokensColorTracker } from '../../../common/view/minimapCharRenderer.js'; import { getOrCreateMinimapCharRenderer } from '../../../common/view/runtimeMinimapCharRenderer.js'; import * as viewEvents from '../../../common/view/viewEvents.js'; import { scrollbarShadow, scrollbarSliderActiveBackground, scrollbarSliderBackground, scrollbarSliderHoverBackground } from '../../../../platform/theme/common/colorRegistry.js'; import { registerThemingParticipant } from '../../../../platform/theme/common/themeService.js'; function getMinimapLineHeight(renderMinimap) { if (renderMinimap === 2 /* Large */) { return 4 /* x2_CHAR_HEIGHT */; } if (renderMinimap === 4 /* LargeBlocks */) { return 4 /* x2_CHAR_HEIGHT */ + 2; } if (renderMinimap === 1 /* Small */) { return 2 /* x1_CHAR_HEIGHT */; } // RenderMinimap.SmallBlocks return 2 /* x1_CHAR_HEIGHT */ + 1; } function getMinimapCharWidth(renderMinimap) { if (renderMinimap === 2 /* Large */) { return 2 /* x2_CHAR_WIDTH */; } if (renderMinimap === 4 /* LargeBlocks */) { return 2 /* x2_CHAR_WIDTH */; } if (renderMinimap === 1 /* Small */) { return 1 /* x1_CHAR_WIDTH */; } // RenderMinimap.SmallBlocks return 1 /* x1_CHAR_WIDTH */; } /** * The orthogonal distance to the slider at which dragging "resets". This implements "snapping" */ var MOUSE_DRAG_RESET_DISTANCE = 140; var MinimapOptions = /** @class */ (function () { function MinimapOptions(configuration) { var pixelRatio = configuration.editor.pixelRatio; var layoutInfo = configuration.editor.layoutInfo; var viewInfo = configuration.editor.viewInfo; var fontInfo = configuration.editor.fontInfo; this.renderMinimap = layoutInfo.renderMinimap | 0; this.scrollBeyondLastLine = viewInfo.scrollBeyondLastLine; this.showSlider = viewInfo.minimap.showSlider; this.pixelRatio = pixelRatio; this.typicalHalfwidthCharacterWidth = fontInfo.typicalHalfwidthCharacterWidth; this.lineHeight = configuration.editor.lineHeight; this.minimapLeft = layoutInfo.minimapLeft; this.minimapWidth = layoutInfo.minimapWidth; this.minimapHeight = layoutInfo.height; this.canvasInnerWidth = Math.max(1, Math.floor(pixelRatio * this.minimapWidth)); this.canvasInnerHeight = Math.max(1, Math.floor(pixelRatio * this.minimapHeight)); this.canvasOuterWidth = this.canvasInnerWidth / pixelRatio; this.canvasOuterHeight = this.canvasInnerHeight / pixelRatio; } MinimapOptions.prototype.equals = function (other) { return (this.renderMinimap === other.renderMinimap && this.scrollBeyondLastLine === other.scrollBeyondLastLine && this.showSlider === other.showSlider && 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 && this.canvasInnerHeight === other.canvasInnerHeight && this.canvasOuterWidth === other.canvasOuterWidth && this.canvasOuterHeight === other.canvasOuterHeight); }; return MinimapOptions; }()); var MinimapLayout = /** @class */ (function () { function MinimapLayout(scrollTop, scrollHeight, computedSliderRatio, sliderTop, sliderHeight, startLineNumber, endLineNumber) { this.scrollTop = scrollTop; this.scrollHeight = scrollHeight; this._computedSliderRatio = computedSliderRatio; this.sliderTop = sliderTop; this.sliderHeight = sliderHeight; this.startLineNumber = startLineNumber; this.endLineNumber = endLineNumber; } /** * Compute a desired `scrollPosition` such that the slider moves by `delta`. */ MinimapLayout.prototype.getDesiredScrollTopFromDelta = function (delta) { var desiredSliderPosition = this.sliderTop + delta; return Math.round(desiredSliderPosition / this._computedSliderRatio); }; MinimapLayout.create = function (options, viewportStartLineNumber, viewportEndLineNumber, viewportHeight, viewportContainsWhitespaceGaps, lineCount, scrollTop, scrollHeight, previousLayout) { var pixelRatio = options.pixelRatio; var minimapLineHeight = getMinimapLineHeight(options.renderMinimap); var minimapLinesFitting = Math.floor(options.canvasInnerHeight / minimapLineHeight); var lineHeight = options.lineHeight; // The visible line count in a viewport can change due to a number of reasons: // a) with the same viewport width, different scroll positions can result in partial lines being visible: // e.g. for a line height of 20, and a viewport height of 600 // * scrollTop = 0 => visible lines are [1, 30] // * scrollTop = 10 => visible lines are [1, 31] (with lines 1 and 31 partially visible) // * scrollTop = 20 => visible lines are [2, 31] // b) whitespace gaps might make their way in the viewport (which results in a decrease in the visible line count) // c) we could be in the scroll beyond last line case (which also results in a decrease in the visible line count, down to possibly only one line being visible) // We must first establish a desirable slider height. var sliderHeight; if (viewportContainsWhitespaceGaps && viewportEndLineNumber !== lineCount) { // case b) from above: there are whitespace gaps in the viewport. // In this case, the height of the slider directly reflects the visible line count. var viewportLineCount = viewportEndLineNumber - viewportStartLineNumber + 1; sliderHeight = Math.floor(viewportLineCount * minimapLineHeight / pixelRatio); } else { // The slider has a stable height var expectedViewportLineCount = viewportHeight / lineHeight; sliderHeight = Math.floor(expectedViewportLineCount * minimapLineHeight / pixelRatio); } var maxMinimapSliderTop; if (options.scrollBeyondLastLine) { // The minimap slider, when dragged all the way down, will contain the last line at its top maxMinimapSliderTop = (lineCount - 1) * minimapLineHeight / pixelRatio; } else { // The minimap slider, when dragged all the way down, will contain the last line at its bottom maxMinimapSliderTop = Math.max(0, lineCount * minimapLineHeight / pixelRatio - sliderHeight); } maxMinimapSliderTop = Math.min(options.minimapHeight - sliderHeight, maxMinimapSliderTop); // The slider can move from 0 to `maxMinimapSliderTop` // in the same way `scrollTop` can move from 0 to `scrollHeight` - `viewportHeight`. var computedSliderRatio = (maxMinimapSliderTop) / (scrollHeight - viewportHeight); var sliderTop = (scrollTop * computedSliderRatio); if (minimapLinesFitting >= lineCount) { // All lines fit in the minimap var startLineNumber = 1; var endLineNumber = lineCount; return new MinimapLayout(scrollTop, scrollHeight, computedSliderRatio, sliderTop, sliderHeight, startLineNumber, endLineNumber); } else { var startLineNumber = Math.max(1, Math.floor(viewportStartLineNumber - sliderTop * pixelRatio / minimapLineHeight)); // Avoid flickering caused by a partial viewport start line // by being consistent w.r.t. the previous layout decision if (previousLayout && previousLayout.scrollHeight === scrollHeight) { if (previousLayout.scrollTop > scrollTop) { // Scrolling up => never increase `startLineNumber` startLineNumber = Math.min(startLineNumber, previousLayout.startLineNumber); } if (previousLayout.scrollTop < scrollTop) { // Scrolling down => never decrease `startLineNumber` startLineNumber = Math.max(startLineNumber, previousLayout.startLineNumber); } } var endLineNumber = Math.min(lineCount, startLineNumber + minimapLinesFitting - 1); return new MinimapLayout(scrollTop, scrollHeight, computedSliderRatio, sliderTop, sliderHeight, startLineNumber, endLineNumber); } }; return MinimapLayout; }()); var MinimapLine = /** @class */ (function () { function MinimapLine(dy) { this.dy = dy; } MinimapLine.prototype.onContentChanged = function () { this.dy = -1; }; MinimapLine.prototype.onTokensChanged = function () { this.dy = -1; }; MinimapLine.INVALID = new MinimapLine(-1); return MinimapLine; }()); var RenderData = /** @class */ (function () { function RenderData(renderedLayout, imageData, lines) { this.renderedLayout = renderedLayout; this._imageData = imageData; this._renderedLines = new RenderedLinesCollection(function () { return MinimapLine.INVALID; }); this._renderedLines._set(renderedLayout.startLineNumber, lines); } /** * Check if the current RenderData matches accurately the new desired layout and no painting is needed. */ RenderData.prototype.linesEquals = function (layout) { if (this.renderedLayout.startLineNumber !== layout.startLineNumber) { return false; } if (this.renderedLayout.endLineNumber !== layout.endLineNumber) { return false; } var tmp = this._renderedLines._get(); var lines = tmp.lines; for (var i = 0, len = lines.length; i < len; i++) { if (lines[i].dy === -1) { // This line is invalid return false; } } return true; }; RenderData.prototype._get = function () { var tmp = this._renderedLines._get(); return { imageData: this._imageData, rendLineNumberStart: tmp.rendLineNumberStart, lines: tmp.lines }; }; RenderData.prototype.onLinesChanged = function (e) { return this._renderedLines.onLinesChanged(e.fromLineNumber, e.toLineNumber); }; RenderData.prototype.onLinesDeleted = function (e) { this._renderedLines.onLinesDeleted(e.fromLineNumber, e.toLineNumber); }; RenderData.prototype.onLinesInserted = function (e) { this._renderedLines.onLinesInserted(e.fromLineNumber, e.toLineNumber); }; RenderData.prototype.onTokensChanged = function (e) { return this._renderedLines.onTokensChanged(e.ranges); }; return RenderData; }()); /** * Some sort of double buffering. * * Keeps two buffers around that will be rotated for painting. * Always gives a buffer that is filled with the background color. */ var MinimapBuffers = /** @class */ (function () { function MinimapBuffers(ctx, WIDTH, HEIGHT, background) { this._backgroundFillData = MinimapBuffers._createBackgroundFillData(WIDTH, HEIGHT, background); this._buffers = [ ctx.createImageData(WIDTH, HEIGHT), ctx.createImageData(WIDTH, HEIGHT) ]; this._lastUsedBuffer = 0; } MinimapBuffers.prototype.getBuffer = function () { // rotate buffers this._lastUsedBuffer = 1 - this._lastUsedBuffer; var result = this._buffers[this._lastUsedBuffer]; // fill with background color result.data.set(this._backgroundFillData); return result; }; MinimapBuffers._createBackgroundFillData = function (WIDTH, HEIGHT, background) { var backgroundR = background.r; var backgroundG = background.g; var backgroundB = background.b; var result = new Uint8ClampedArray(WIDTH * HEIGHT * 4); var offset = 0; for (var i = 0; i < HEIGHT; i++) { for (var j = 0; j < WIDTH; j++) { result[offset] = backgroundR; result[offset + 1] = backgroundG; result[offset + 2] = backgroundB; result[offset + 3] = 255; offset += 4; } } return result; }; return MinimapBuffers; }()); var Minimap = /** @class */ (function (_super) { __extends(Minimap, _super); function Minimap(context) { var _this = _super.call(this, context) || this; _this._options = new MinimapOptions(_this._context.configuration); _this._lastRenderData = null; _this._buffers = null; _this._domNode = createFastDomNode(document.createElement('div')); PartFingerprints.write(_this._domNode, 8 /* Minimap */); _this._domNode.setClassName(_this._getMinimapDomNodeClassName()); _this._domNode.setPosition('absolute'); _this._domNode.setAttribute('role', 'presentation'); _this._domNode.setAttribute('aria-hidden', 'true'); _this._shadow = createFastDomNode(document.createElement('div')); _this._shadow.setClassName('minimap-shadow-hidden'); _this._domNode.appendChild(_this._shadow); _this._canvas = createFastDomNode(document.createElement('canvas')); _this._canvas.setPosition('absolute'); _this._canvas.setLeft(0); _this._domNode.appendChild(_this._canvas); _this._slider = createFastDomNode(document.createElement('div')); _this._slider.setPosition('absolute'); _this._slider.setClassName('minimap-slider'); _this._slider.setLayerHinting(true); _this._domNode.appendChild(_this._slider); _this._sliderHorizontal = createFastDomNode(document.createElement('div')); _this._sliderHorizontal.setPosition('absolute'); _this._sliderHorizontal.setClassName('minimap-slider-horizontal'); _this._slider.appendChild(_this._sliderHorizontal); _this._tokensColorTracker = MinimapTokensColorTracker.getInstance(); _this._applyLayout(); _this._mouseDownListener = dom.addStandardDisposableListener(_this._canvas.domNode, 'mousedown', function (e) { e.preventDefault(); var renderMinimap = _this._options.renderMinimap; if (renderMinimap === 0 /* None */) { return; } if (!_this._lastRenderData) { return; } var minimapLineHeight = getMinimapLineHeight(renderMinimap); var internalOffsetY = _this._options.pixelRatio * e.browserEvent.offsetY; var lineIndex = Math.floor(internalOffsetY / minimapLineHeight); var lineNumber = lineIndex + _this._lastRenderData.renderedLayout.startLineNumber; lineNumber = Math.min(lineNumber, _this._context.model.getLineCount()); _this._context.privateViewEventBus.emit(new viewEvents.ViewRevealRangeRequestEvent(new Range(lineNumber, 1, lineNumber, 1), 1 /* Center */, false, 0 /* Smooth */)); }); _this._sliderMouseMoveMonitor = new GlobalMouseMoveMonitor(); _this._sliderMouseDownListener = dom.addStandardDisposableListener(_this._slider.domNode, 'mousedown', function (e) { e.preventDefault(); if (e.leftButton && _this._lastRenderData) { var initialMousePosition_1 = e.posy; var initialMouseOrthogonalPosition_1 = e.posx; var initialSliderState_1 = _this._lastRenderData.renderedLayout; _this._slider.toggleClassName('active', true); _this._sliderMouseMoveMonitor.startMonitoring(standardMouseMoveMerger, function (mouseMoveData) { var mouseOrthogonalDelta = Math.abs(mouseMoveData.posx - initialMouseOrthogonalPosition_1); if (platform.isWindows && mouseOrthogonalDelta > MOUSE_DRAG_RESET_DISTANCE) { // The mouse has wondered away from the scrollbar => reset dragging _this._context.viewLayout.setScrollPositionNow({ scrollTop: initialSliderState_1.scrollTop }); return; } var mouseDelta = mouseMoveData.posy - initialMousePosition_1; _this._context.viewLayout.setScrollPositionNow({ scrollTop: initialSliderState_1.getDesiredScrollTopFromDelta(mouseDelta) }); }, function () { _this._slider.toggleClassName('active', false); }); } }); return _this; } Minimap.prototype.dispose = function () { this._mouseDownListener.dispose(); this._sliderMouseMoveMonitor.dispose(); this._sliderMouseDownListener.dispose(); _super.prototype.dispose.call(this); }; Minimap.prototype._getMinimapDomNodeClassName = function () { if (this._options.showSlider === 'always') { return 'minimap slider-always'; } return 'minimap slider-mouseover'; }; Minimap.prototype.getDomNode = function () { return this._domNode; }; Minimap.prototype._applyLayout = function () { this._domNode.setLeft(this._options.minimapLeft); this._domNode.setWidth(this._options.minimapWidth); this._domNode.setHeight(this._options.minimapHeight); this._shadow.setHeight(this._options.minimapHeight); this._canvas.setWidth(this._options.canvasOuterWidth); this._canvas.setHeight(this._options.canvasOuterHeight); this._canvas.domNode.width = this._options.canvasInnerWidth; this._canvas.domNode.height = this._options.canvasInnerHeight; this._slider.setWidth(this._options.minimapWidth); }; Minimap.prototype._getBuffer = function () { if (!this._buffers) { this._buffers = new MinimapBuffers(this._canvas.domNode.getContext('2d'), this._options.canvasInnerWidth, this._options.canvasInnerHeight, this._tokensColorTracker.getColor(2 /* DefaultBackground */)); } return this._buffers.getBuffer(); }; Minimap.prototype._onOptionsMaybeChanged = function () { var opts = new MinimapOptions(this._context.configuration); if (this._options.equals(opts)) { return false; } this._options = opts; this._lastRenderData = null; this._buffers = null; this._applyLayout(); this._domNode.setClassName(this._getMinimapDomNodeClassName()); return true; }; // ---- begin view event handlers Minimap.prototype.onConfigurationChanged = function (e) { return this._onOptionsMaybeChanged(); }; Minimap.prototype.onFlushed = function (e) { this._lastRenderData = null; return true; }; Minimap.prototype.onLinesChanged = function (e) { if (this._lastRenderData) { return this._lastRenderData.onLinesChanged(e); } return false; }; Minimap.prototype.onLinesDeleted = function (e) { if (this._lastRenderData) { this._lastRenderData.onLinesDeleted(e); } return true; }; Minimap.prototype.onLinesInserted = function (e) { if (this._lastRenderData) { this._lastRenderData.onLinesInserted(e); } return true; }; Minimap.prototype.onScrollChanged = function (e) { return true; }; Minimap.prototype.onTokensChanged = function (e) { if (this._lastRenderData) { return this._lastRenderData.onTokensChanged(e); } return false; }; Minimap.prototype.onTokensColorsChanged = function (e) { this._lastRenderData = null; this._buffers = null; return true; }; Minimap.prototype.onZonesChanged = function (e) { this._lastRenderData = null; return true; }; // --- end event handlers Minimap.prototype.prepareRender = function (ctx) { // Nothing to read }; Minimap.prototype.render = function (renderingCtx) { var renderMinimap = this._options.renderMinimap; if (renderMinimap === 0 /* None */) { this._shadow.setClassName('minimap-shadow-hidden'); this._sliderHorizontal.setWidth(0); this._sliderHorizontal.setHeight(0); return; } if (renderingCtx.scrollLeft + renderingCtx.viewportWidth >= renderingCtx.scrollWidth) { this._shadow.setClassName('minimap-shadow-hidden'); } else { this._shadow.setClassName('minimap-shadow-visible'); } var layout = MinimapLayout.create(this._options, renderingCtx.visibleRange.startLineNumber, renderingCtx.visibleRange.endLineNumber, renderingCtx.viewportHeight, (renderingCtx.viewportData.whitespaceViewportData.length > 0), this._context.model.getLineCount(), renderingCtx.scrollTop, renderingCtx.scrollHeight, this._lastRenderData ? this._lastRenderData.renderedLayout : null); this._slider.setTop(layout.sliderTop); this._slider.setHeight(layout.sliderHeight); // Compute horizontal slider coordinates var scrollLeftChars = renderingCtx.scrollLeft / this._options.typicalHalfwidthCharacterWidth; var horizontalSliderLeft = Math.min(this._options.minimapWidth, Math.round(scrollLeftChars * getMinimapCharWidth(this._options.renderMinimap) / this._options.pixelRatio)); this._sliderHorizontal.setLeft(horizontalSliderLeft); this._sliderHorizontal.setWidth(this._options.minimapWidth - horizontalSliderLeft); this._sliderHorizontal.setTop(0); this._sliderHorizontal.setHeight(layout.sliderHeight); this._lastRenderData = this.renderLines(layout); }; Minimap.prototype.renderLines = function (layout) { var renderMinimap = this._options.renderMinimap; var startLineNumber = layout.startLineNumber; var endLineNumber = layout.endLineNumber; var minimapLineHeight = getMinimapLineHeight(renderMinimap); // Check if nothing changed w.r.t. lines from last frame if (this._lastRenderData && this._lastRenderData.linesEquals(layout)) { var _lastData = this._lastRenderData._get(); // Nice!! Nothing changed from last frame return new RenderData(layout, _lastData.imageData, _lastData.lines); } // Oh well!! We need to repaint some lines... var imageData = this._getBuffer(); // Render untouched lines by using last rendered data. var _a = Minimap._renderUntouchedLines(imageData, startLineNumber, endLineNumber, minimapLineHeight, this._lastRenderData), _dirtyY1 = _a[0], _dirtyY2 = _a[1], needed = _a[2]; // Fetch rendering info from view model for rest of lines that need rendering. var lineInfo = this._context.model.getMinimapLinesRenderingData(startLineNumber, endLineNumber, needed); var tabSize = lineInfo.tabSize; var background = this._tokensColorTracker.getColor(2 /* DefaultBackground */); var useLighterFont = this._tokensColorTracker.backgroundIsLight(); // Render the rest of lines var dy = 0; var renderedLines = []; for (var lineIndex = 0, lineCount = endLineNumber - startLineNumber + 1; lineIndex < lineCount; lineIndex++) { if (needed[lineIndex]) { Minimap._renderLine(imageData, background, useLighterFont, renderMinimap, this._tokensColorTracker, getOrCreateMinimapCharRenderer(), dy, tabSize, lineInfo.data[lineIndex]); } renderedLines[lineIndex] = new MinimapLine(dy); dy += minimapLineHeight; } var dirtyY1 = (_dirtyY1 === -1 ? 0 : _dirtyY1); var dirtyY2 = (_dirtyY2 === -1 ? imageData.height : _dirtyY2); var dirtyHeight = dirtyY2 - dirtyY1; // Finally, paint to the canvas var ctx = this._canvas.domNode.getContext('2d'); ctx.putImageData(imageData, 0, 0, 0, dirtyY1, imageData.width, dirtyHeight); // Save rendered data for reuse on next frame if possible return new RenderData(layout, imageData, renderedLines); }; Minimap._renderUntouchedLines = function (target, startLineNumber, endLineNumber, minimapLineHeight, lastRenderData) { var needed = []; if (!lastRenderData) { for (var i = 0, len = endLineNumber - startLineNumber + 1; i < len; i++) { needed[i] = true; } return [-1, -1, needed]; } var _lastData = lastRenderData._get(); var lastTargetData = _lastData.imageData.data; var lastStartLineNumber = _lastData.rendLineNumberStart; var lastLines = _lastData.lines; var lastLinesLength = lastLines.length; var WIDTH = target.width; var targetData = target.data; var maxDestPixel = (endLineNumber - startLineNumber + 1) * minimapLineHeight * WIDTH * 4; var dirtyPixel1 = -1; // the pixel offset up to which all the data is equal to the prev frame var dirtyPixel2 = -1; // the pixel offset after which all the data is equal to the prev frame var copySourceStart = -1; var copySourceEnd = -1; var copyDestStart = -1; var copyDestEnd = -1; var dest_dy = 0; for (var lineNumber = startLineNumber; lineNumber <= endLineNumber; lineNumber++) { var lineIndex = lineNumber - startLineNumber; var lastLineIndex = lineNumber - lastStartLineNumber; var source_dy = (lastLineIndex >= 0 && lastLineIndex < lastLinesLength ? lastLines[lastLineIndex].dy : -1); if (source_dy === -1) { needed[lineIndex] = true; dest_dy += minimapLineHeight; continue; } var sourceStart = source_dy * WIDTH * 4; var sourceEnd = (source_dy + minimapLineHeight) * WIDTH * 4; var destStart = dest_dy * WIDTH * 4; var destEnd = (dest_dy + minimapLineHeight) * WIDTH * 4; if (copySourceEnd === sourceStart && copyDestEnd === destStart) { // contiguous zone => extend copy request copySourceEnd = sourceEnd; copyDestEnd = destEnd; } else { if (copySourceStart !== -1) { // flush existing copy request targetData.set(lastTargetData.subarray(copySourceStart, copySourceEnd), copyDestStart); if (dirtyPixel1 === -1 && copySourceStart === 0 && copySourceStart === copyDestStart) { dirtyPixel1 = copySourceEnd; } if (dirtyPixel2 === -1 && copySourceEnd === maxDestPixel && copySourceStart === copyDestStart) { dirtyPixel2 = copySourceStart; } } copySourceStart = sourceStart; copySourceEnd = sourceEnd; copyDestStart = destStart; copyDestEnd = destEnd; } needed[lineIndex] = false; dest_dy += minimapLineHeight; } if (copySourceStart !== -1) { // flush existing copy request targetData.set(lastTargetData.subarray(copySourceStart, copySourceEnd), copyDestStart); if (dirtyPixel1 === -1 && copySourceStart === 0 && copySourceStart === copyDestStart) { dirtyPixel1 = copySourceEnd; } if (dirtyPixel2 === -1 && copySourceEnd === maxDestPixel && copySourceStart === copyDestStart) { dirtyPixel2 = copySourceStart; } } var dirtyY1 = (dirtyPixel1 === -1 ? -1 : dirtyPixel1 / (WIDTH * 4)); var dirtyY2 = (dirtyPixel2 === -1 ? -1 : dirtyPixel2 / (WIDTH * 4)); return [dirtyY1, dirtyY2, needed]; }; Minimap._renderLine = function (target, backgroundColor, useLighterFont, renderMinimap, colorTracker, minimapCharRenderer, dy, tabSize, lineData) { var content = lineData.content; var tokens = lineData.tokens; var charWidth = getMinimapCharWidth(renderMinimap); var maxDx = target.width - charWidth; var dx = 0; var charIndex = 0; var tabsCharDelta = 0; for (var tokenIndex = 0, tokensLen = tokens.getCount(); tokenIndex < tokensLen; tokenIndex++) { var tokenEndIndex = tokens.getEndOffset(tokenIndex); var tokenColorId = tokens.getForeground(tokenIndex); var tokenColor = colorTracker.getColor(tokenColorId); for (; charIndex < tokenEndIndex; charIndex++) { if (dx > maxDx) { // hit edge of minimap return; } var charCode = content.charCodeAt(charIndex); if (charCode === 9 /* Tab */) { var insertSpacesCount = tabSize - (charIndex + tabsCharDelta) % tabSize; tabsCharDelta += insertSpacesCount - 1; // No need to render anything since tab is invisible dx += insertSpacesCount * charWidth; } else if (charCode === 32 /* Space */) { // No need to render anything since space is invisible dx += charWidth; } else { // Render twice for a full width character var count = strings.isFullWidthCharacter(charCode) ? 2 : 1; for (var i = 0; i < count; i++) { if (renderMinimap === 2 /* Large */) { minimapCharRenderer.x2RenderChar(target, dx, dy, charCode, tokenColor, backgroundColor, useLighterFont); } else if (renderMinimap === 1 /* Small */) { minimapCharRenderer.x1RenderChar(target, dx, dy, charCode, tokenColor, backgroundColor, useLighterFont); } else if (renderMinimap === 4 /* LargeBlocks */) { minimapCharRenderer.x2BlockRenderChar(target, dx, dy, tokenColor, backgroundColor, useLighterFont); } else { // RenderMinimap.SmallBlocks minimapCharRenderer.x1BlockRenderChar(target, dx, dy, tokenColor, backgroundColor, useLighterFont); } dx += charWidth; if (dx > maxDx) { // hit edge of minimap return; } } } } } }; return Minimap; }(ViewPart)); export { Minimap }; registerThemingParticipant(function (theme, collector) { var sliderBackground = theme.getColor(scrollbarSliderBackground); if (sliderBackground) { var halfSliderBackground = sliderBackground.transparent(0.5); collector.addRule(".monaco-editor .minimap-slider, .monaco-editor .minimap-slider .minimap-slider-horizontal { background: " + halfSliderBackground + "; }"); } var sliderHoverBackground = theme.getColor(scrollbarSliderHoverBackground); if (sliderHoverBackground) { var halfSliderHoverBackground = sliderHoverBackground.transparent(0.5); collector.addRule(".monaco-editor .minimap-slider:hover, .monaco-editor .minimap-slider:hover .minimap-slider-horizontal { background: " + halfSliderHoverBackground + "; }"); } var sliderActiveBackground = theme.getColor(scrollbarSliderActiveBackground); if (sliderActiveBackground) { var halfSliderActiveBackground = sliderActiveBackground.transparent(0.5); collector.addRule(".monaco-editor .minimap-slider.active, .monaco-editor .minimap-slider.active .minimap-slider-horizontal { background: " + halfSliderActiveBackground + "; }"); } var shadow = theme.getColor(scrollbarShadow); if (shadow) { collector.addRule(".monaco-editor .minimap-shadow-visible { box-shadow: " + shadow + " -6px 0 6px -6px inset; }"); } });