UNPKG

monaco-editor

Version:
176 lines (173 loc) 10.4 kB
import { Range } from '../core/range.js'; import { Position } from '../core/position.js'; import { isModelDecorationVisible, ViewModelDecoration } from './viewModelDecoration.js'; /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ class InlineDecoration { constructor(range, inlineClassName, type) { this.range = range; this.inlineClassName = inlineClassName; this.type = type; } } class InlineModelDecorationsComputer { constructor(context, model, coordinatesConverter) { this.context = context; this.model = model; this.coordinatesConverter = coordinatesConverter; this._decorationsCache = Object.create(null); } getInlineDecorations(modelLineNumber) { const modelRange = new Range(modelLineNumber, 1, modelLineNumber, this.model.getLineMaxColumn(modelLineNumber)); const viewRange = this.coordinatesConverter.convertModelRangeToViewRange(modelRange); const decorationsViewportData = this.getDecorations(viewRange, false, false); return decorationsViewportData.inlineDecorations; } getDecorations(viewRange, onlyMinimapDecorations, onlyMarginDecorations) { const modelDecorations = this.context.getModelDecorations(viewRange, onlyMinimapDecorations, onlyMarginDecorations); const startLineNumber = viewRange.startLineNumber; const endLineNumber = viewRange.endLineNumber; const decorationsInViewport = []; let decorationsInViewportLen = 0; const inlineDecorations = []; const hasVariableFonts = []; for (let j = startLineNumber; j <= endLineNumber; j++) { inlineDecorations[j - startLineNumber] = []; hasVariableFonts[j - startLineNumber] = false; } for (let i = 0, len = modelDecorations.length; i < len; i++) { const modelDecoration = modelDecorations[i]; const decorationOptions = modelDecoration.options; if (!isModelDecorationVisible(this.model, modelDecoration)) { continue; } const viewModelDecoration = this._getOrCreateViewModelDecoration(modelDecoration); const viewRange = viewModelDecoration.range; decorationsInViewport[decorationsInViewportLen++] = viewModelDecoration; if (decorationOptions.inlineClassName) { const inlineDecoration = new InlineDecoration(viewRange, decorationOptions.inlineClassName, decorationOptions.inlineClassNameAffectsLetterSpacing ? 3 /* InlineDecorationType.RegularAffectingLetterSpacing */ : 0 /* InlineDecorationType.Regular */); const intersectedStartLineNumber = Math.max(startLineNumber, viewRange.startLineNumber); const intersectedEndLineNumber = Math.min(endLineNumber, viewRange.endLineNumber); for (let j = intersectedStartLineNumber; j <= intersectedEndLineNumber; j++) { inlineDecorations[j - startLineNumber].push(inlineDecoration); if (decorationOptions.affectsFont) { hasVariableFonts[j - startLineNumber] = true; } } } if (decorationOptions.beforeContentClassName) { if (startLineNumber <= viewRange.startLineNumber && viewRange.startLineNumber <= endLineNumber) { const inlineDecoration = new InlineDecoration(new Range(viewRange.startLineNumber, viewRange.startColumn, viewRange.startLineNumber, viewRange.startColumn), decorationOptions.beforeContentClassName, 1 /* InlineDecorationType.Before */); inlineDecorations[viewRange.startLineNumber - startLineNumber].push(inlineDecoration); if (decorationOptions.affectsFont) { hasVariableFonts[viewRange.startLineNumber - startLineNumber] = true; } } } if (decorationOptions.afterContentClassName) { if (startLineNumber <= viewRange.endLineNumber && viewRange.endLineNumber <= endLineNumber) { const inlineDecoration = new InlineDecoration(new Range(viewRange.endLineNumber, viewRange.endColumn, viewRange.endLineNumber, viewRange.endColumn), decorationOptions.afterContentClassName, 2 /* InlineDecorationType.After */); inlineDecorations[viewRange.endLineNumber - startLineNumber].push(inlineDecoration); if (decorationOptions.affectsFont) { hasVariableFonts[viewRange.endLineNumber - startLineNumber] = true; } } } } return { decorations: decorationsInViewport, inlineDecorations: inlineDecorations, hasVariableFonts }; } reset() { this._decorationsCache = Object.create(null); } onModelDecorationsChanged() { this.reset(); } onLineMappingChanged() { this.reset(); } _getOrCreateViewModelDecoration(modelDecoration) { const id = modelDecoration.id; let r = this._decorationsCache[id]; if (!r) { const modelRange = modelDecoration.range; const options = modelDecoration.options; let viewRange; if (options.isWholeLine) { const start = this.coordinatesConverter.convertModelPositionToViewPosition(new Position(modelRange.startLineNumber, 1), 0 /* PositionAffinity.Left */, false, true); const end = this.coordinatesConverter.convertModelPositionToViewPosition(new Position(modelRange.endLineNumber, this.model.getLineMaxColumn(modelRange.endLineNumber)), 1 /* PositionAffinity.Right */); viewRange = new Range(start.lineNumber, start.column, end.lineNumber, end.column); } else { // For backwards compatibility reasons, we want injected text before any decoration. // Thus, move decorations to the right. viewRange = this.coordinatesConverter.convertModelRangeToViewRange(modelRange, 1 /* PositionAffinity.Right */); } r = new ViewModelDecoration(viewRange, options); this._decorationsCache[id] = r; } return r; } } class InjectedTextInlineDecorationsComputer { constructor(context) { this.context = context; } getInlineDecorations(modelLineNumber) { const injectionOffsets = this.context.getInjectionOffsets(modelLineNumber); if (!injectionOffsets) { return []; } const lineInlineDecorations = []; let totalInjectedTextLengthBefore = 0; let currentInjectedOffset = 0; const injectionOptions = this.context.getInjectionOptions(modelLineNumber); const breakOffsets = this.context.getBreakOffsets(modelLineNumber); for (let outputLineIndex = 0; outputLineIndex < breakOffsets.length; outputLineIndex++) { const inlineDecorations = new Array(); lineInlineDecorations[outputLineIndex] = inlineDecorations; const lineStartOffsetInInputWithInjections = outputLineIndex > 0 ? breakOffsets[outputLineIndex - 1] : 0; const lineEndOffsetInInputWithInjections = breakOffsets[outputLineIndex]; while (currentInjectedOffset < injectionOffsets.length) { const length = injectionOptions[currentInjectedOffset].content.length; const injectedTextStartOffsetInInputWithInjections = injectionOffsets[currentInjectedOffset] + totalInjectedTextLengthBefore; const injectedTextEndOffsetInInputWithInjections = injectedTextStartOffsetInInputWithInjections + length; if (injectedTextStartOffsetInInputWithInjections > lineEndOffsetInInputWithInjections) { // Injected text only starts in later wrapped lines. break; } if (lineStartOffsetInInputWithInjections < injectedTextEndOffsetInInputWithInjections) { // Injected text ends after or in this line (but also starts in or before this line). const options = injectionOptions[currentInjectedOffset]; if (options.inlineClassName) { const wrappedTextIndentLength = this.context.getWrappedTextIndentLength(modelLineNumber); const offset = (outputLineIndex > 0 ? wrappedTextIndentLength : 0); const start = offset + Math.max(injectedTextStartOffsetInInputWithInjections - lineStartOffsetInInputWithInjections, 0); const end = offset + Math.min(injectedTextEndOffsetInInputWithInjections - lineStartOffsetInInputWithInjections, lineEndOffsetInInputWithInjections - lineStartOffsetInInputWithInjections); if (start !== end) { const viewLineNumber = this.context.getBaseViewLineNumber(modelLineNumber) + outputLineIndex; const range = new Range(viewLineNumber, start + 1, viewLineNumber, end + 1); const type = options.inlineClassNameAffectsLetterSpacing ? 3 /* InlineDecorationType.RegularAffectingLetterSpacing */ : 0 /* InlineDecorationType.Regular */; inlineDecorations.push(new InlineDecoration(range, options.inlineClassName, type)); } } } if (injectedTextEndOffsetInInputWithInjections <= lineEndOffsetInInputWithInjections) { totalInjectedTextLengthBefore += length; currentInjectedOffset++; } else { // injected text breaks into next line, process it again break; } } } return lineInlineDecorations; } } export { InjectedTextInlineDecorationsComputer, InlineDecoration, InlineModelDecorationsComputer };