| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329 |
- /*---------------------------------------------------------------------------------------------
- * Copyright (c) Microsoft Corporation. All rights reserved.
- * Licensed under the MIT License. See License.txt in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
- import { LineTokens } from '../tokens/lineTokens.js';
- import { Position } from '../core/position.js';
- import { LineInjectedText } from '../textModelEvents.js';
- import { SingleLineInlineDecoration, ViewLineData } from '../viewModel.js';
- export function createModelLineProjection(lineBreakData, isVisible) {
- if (lineBreakData === null) {
- // No mapping needed
- if (isVisible) {
- return IdentityModelLineProjection.INSTANCE;
- }
- return HiddenModelLineProjection.INSTANCE;
- }
- else {
- return new ModelLineProjection(lineBreakData, isVisible);
- }
- }
- /**
- * This projection is used to
- * * wrap model lines
- * * inject text
- */
- class ModelLineProjection {
- constructor(lineBreakData, isVisible) {
- this._projectionData = lineBreakData;
- this._isVisible = isVisible;
- }
- isVisible() {
- return this._isVisible;
- }
- setVisible(isVisible) {
- this._isVisible = isVisible;
- return this;
- }
- getProjectionData() {
- return this._projectionData;
- }
- getViewLineCount() {
- if (!this._isVisible) {
- return 0;
- }
- return this._projectionData.getOutputLineCount();
- }
- getViewLineContent(model, modelLineNumber, outputLineIndex) {
- this._assertVisible();
- const startOffsetInInputWithInjections = outputLineIndex > 0 ? this._projectionData.breakOffsets[outputLineIndex - 1] : 0;
- const endOffsetInInputWithInjections = this._projectionData.breakOffsets[outputLineIndex];
- let r;
- if (this._projectionData.injectionOffsets !== null) {
- const injectedTexts = this._projectionData.injectionOffsets.map((offset, idx) => new LineInjectedText(0, 0, offset + 1, this._projectionData.injectionOptions[idx], 0));
- const lineWithInjections = LineInjectedText.applyInjectedText(model.getLineContent(modelLineNumber), injectedTexts);
- r = lineWithInjections.substring(startOffsetInInputWithInjections, endOffsetInInputWithInjections);
- }
- else {
- r = model.getValueInRange({
- startLineNumber: modelLineNumber,
- startColumn: startOffsetInInputWithInjections + 1,
- endLineNumber: modelLineNumber,
- endColumn: endOffsetInInputWithInjections + 1
- });
- }
- if (outputLineIndex > 0) {
- r = spaces(this._projectionData.wrappedTextIndentLength) + r;
- }
- return r;
- }
- getViewLineLength(model, modelLineNumber, outputLineIndex) {
- this._assertVisible();
- return this._projectionData.getLineLength(outputLineIndex);
- }
- getViewLineMinColumn(_model, _modelLineNumber, outputLineIndex) {
- this._assertVisible();
- return this._projectionData.getMinOutputOffset(outputLineIndex) + 1;
- }
- getViewLineMaxColumn(model, modelLineNumber, outputLineIndex) {
- this._assertVisible();
- return this._projectionData.getMaxOutputOffset(outputLineIndex) + 1;
- }
- /**
- * Try using {@link getViewLinesData} instead.
- */
- getViewLineData(model, modelLineNumber, outputLineIndex) {
- const arr = new Array();
- this.getViewLinesData(model, modelLineNumber, outputLineIndex, 1, 0, [true], arr);
- return arr[0];
- }
- getViewLinesData(model, modelLineNumber, outputLineIdx, lineCount, globalStartIndex, needed, result) {
- this._assertVisible();
- const lineBreakData = this._projectionData;
- const injectionOffsets = lineBreakData.injectionOffsets;
- const injectionOptions = lineBreakData.injectionOptions;
- let inlineDecorationsPerOutputLine = null;
- if (injectionOffsets) {
- inlineDecorationsPerOutputLine = [];
- let totalInjectedTextLengthBefore = 0;
- let currentInjectedOffset = 0;
- for (let outputLineIndex = 0; outputLineIndex < lineBreakData.getOutputLineCount(); outputLineIndex++) {
- const inlineDecorations = new Array();
- inlineDecorationsPerOutputLine[outputLineIndex] = inlineDecorations;
- const lineStartOffsetInInputWithInjections = outputLineIndex > 0 ? lineBreakData.breakOffsets[outputLineIndex - 1] : 0;
- const lineEndOffsetInInputWithInjections = lineBreakData.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 offset = (outputLineIndex > 0 ? lineBreakData.wrappedTextIndentLength : 0);
- const start = offset + Math.max(injectedTextStartOffsetInInputWithInjections - lineStartOffsetInInputWithInjections, 0);
- const end = offset + Math.min(injectedTextEndOffsetInInputWithInjections - lineStartOffsetInInputWithInjections, lineEndOffsetInInputWithInjections);
- if (start !== end) {
- inlineDecorations.push(new SingleLineInlineDecoration(start, end, options.inlineClassName, options.inlineClassNameAffectsLetterSpacing));
- }
- }
- }
- if (injectedTextEndOffsetInInputWithInjections <= lineEndOffsetInInputWithInjections) {
- totalInjectedTextLengthBefore += length;
- currentInjectedOffset++;
- }
- else {
- // injected text breaks into next line, process it again
- break;
- }
- }
- }
- }
- let lineWithInjections;
- if (injectionOffsets) {
- lineWithInjections = model.tokenization.getLineTokens(modelLineNumber).withInserted(injectionOffsets.map((offset, idx) => ({
- offset,
- text: injectionOptions[idx].content,
- tokenMetadata: LineTokens.defaultTokenMetadata
- })));
- }
- else {
- lineWithInjections = model.tokenization.getLineTokens(modelLineNumber);
- }
- for (let outputLineIndex = outputLineIdx; outputLineIndex < outputLineIdx + lineCount; outputLineIndex++) {
- const globalIndex = globalStartIndex + outputLineIndex - outputLineIdx;
- if (!needed[globalIndex]) {
- result[globalIndex] = null;
- continue;
- }
- result[globalIndex] = this._getViewLineData(lineWithInjections, inlineDecorationsPerOutputLine ? inlineDecorationsPerOutputLine[outputLineIndex] : null, outputLineIndex);
- }
- }
- _getViewLineData(lineWithInjections, inlineDecorations, outputLineIndex) {
- this._assertVisible();
- const lineBreakData = this._projectionData;
- const deltaStartIndex = (outputLineIndex > 0 ? lineBreakData.wrappedTextIndentLength : 0);
- const lineStartOffsetInInputWithInjections = outputLineIndex > 0 ? lineBreakData.breakOffsets[outputLineIndex - 1] : 0;
- const lineEndOffsetInInputWithInjections = lineBreakData.breakOffsets[outputLineIndex];
- const tokens = lineWithInjections.sliceAndInflate(lineStartOffsetInInputWithInjections, lineEndOffsetInInputWithInjections, deltaStartIndex);
- let lineContent = tokens.getLineContent();
- if (outputLineIndex > 0) {
- lineContent = spaces(lineBreakData.wrappedTextIndentLength) + lineContent;
- }
- const minColumn = this._projectionData.getMinOutputOffset(outputLineIndex) + 1;
- const maxColumn = lineContent.length + 1;
- const continuesWithWrappedLine = (outputLineIndex + 1 < this.getViewLineCount());
- const startVisibleColumn = (outputLineIndex === 0 ? 0 : lineBreakData.breakOffsetsVisibleColumn[outputLineIndex - 1]);
- return new ViewLineData(lineContent, continuesWithWrappedLine, minColumn, maxColumn, startVisibleColumn, tokens, inlineDecorations);
- }
- getModelColumnOfViewPosition(outputLineIndex, outputColumn) {
- this._assertVisible();
- return this._projectionData.translateToInputOffset(outputLineIndex, outputColumn - 1) + 1;
- }
- getViewPositionOfModelPosition(deltaLineNumber, inputColumn, affinity = 2 /* PositionAffinity.None */) {
- this._assertVisible();
- const r = this._projectionData.translateToOutputPosition(inputColumn - 1, affinity);
- return r.toPosition(deltaLineNumber);
- }
- getViewLineNumberOfModelPosition(deltaLineNumber, inputColumn) {
- this._assertVisible();
- const r = this._projectionData.translateToOutputPosition(inputColumn - 1);
- return deltaLineNumber + r.outputLineIndex;
- }
- normalizePosition(outputLineIndex, outputPosition, affinity) {
- const baseViewLineNumber = outputPosition.lineNumber - outputLineIndex;
- const normalizedOutputPosition = this._projectionData.normalizeOutputPosition(outputLineIndex, outputPosition.column - 1, affinity);
- const result = normalizedOutputPosition.toPosition(baseViewLineNumber);
- return result;
- }
- getInjectedTextAt(outputLineIndex, outputColumn) {
- return this._projectionData.getInjectedText(outputLineIndex, outputColumn - 1);
- }
- _assertVisible() {
- if (!this._isVisible) {
- throw new Error('Not supported');
- }
- }
- }
- /**
- * This projection does not change the model line.
- */
- class IdentityModelLineProjection {
- constructor() { }
- isVisible() {
- return true;
- }
- setVisible(isVisible) {
- if (isVisible) {
- return this;
- }
- return HiddenModelLineProjection.INSTANCE;
- }
- getProjectionData() {
- return null;
- }
- getViewLineCount() {
- return 1;
- }
- getViewLineContent(model, modelLineNumber, _outputLineIndex) {
- return model.getLineContent(modelLineNumber);
- }
- getViewLineLength(model, modelLineNumber, _outputLineIndex) {
- return model.getLineLength(modelLineNumber);
- }
- getViewLineMinColumn(model, modelLineNumber, _outputLineIndex) {
- return model.getLineMinColumn(modelLineNumber);
- }
- getViewLineMaxColumn(model, modelLineNumber, _outputLineIndex) {
- return model.getLineMaxColumn(modelLineNumber);
- }
- getViewLineData(model, modelLineNumber, _outputLineIndex) {
- const lineTokens = model.tokenization.getLineTokens(modelLineNumber);
- const lineContent = lineTokens.getLineContent();
- return new ViewLineData(lineContent, false, 1, lineContent.length + 1, 0, lineTokens.inflate(), null);
- }
- getViewLinesData(model, modelLineNumber, _fromOuputLineIndex, _toOutputLineIndex, globalStartIndex, needed, result) {
- if (!needed[globalStartIndex]) {
- result[globalStartIndex] = null;
- return;
- }
- result[globalStartIndex] = this.getViewLineData(model, modelLineNumber, 0);
- }
- getModelColumnOfViewPosition(_outputLineIndex, outputColumn) {
- return outputColumn;
- }
- getViewPositionOfModelPosition(deltaLineNumber, inputColumn) {
- return new Position(deltaLineNumber, inputColumn);
- }
- getViewLineNumberOfModelPosition(deltaLineNumber, _inputColumn) {
- return deltaLineNumber;
- }
- normalizePosition(outputLineIndex, outputPosition, affinity) {
- return outputPosition;
- }
- getInjectedTextAt(_outputLineIndex, _outputColumn) {
- return null;
- }
- }
- IdentityModelLineProjection.INSTANCE = new IdentityModelLineProjection();
- /**
- * This projection hides the model line.
- */
- class HiddenModelLineProjection {
- constructor() { }
- isVisible() {
- return false;
- }
- setVisible(isVisible) {
- if (!isVisible) {
- return this;
- }
- return IdentityModelLineProjection.INSTANCE;
- }
- getProjectionData() {
- return null;
- }
- getViewLineCount() {
- return 0;
- }
- getViewLineContent(_model, _modelLineNumber, _outputLineIndex) {
- throw new Error('Not supported');
- }
- getViewLineLength(_model, _modelLineNumber, _outputLineIndex) {
- throw new Error('Not supported');
- }
- getViewLineMinColumn(_model, _modelLineNumber, _outputLineIndex) {
- throw new Error('Not supported');
- }
- getViewLineMaxColumn(_model, _modelLineNumber, _outputLineIndex) {
- throw new Error('Not supported');
- }
- getViewLineData(_model, _modelLineNumber, _outputLineIndex) {
- throw new Error('Not supported');
- }
- getViewLinesData(_model, _modelLineNumber, _fromOuputLineIndex, _toOutputLineIndex, _globalStartIndex, _needed, _result) {
- throw new Error('Not supported');
- }
- getModelColumnOfViewPosition(_outputLineIndex, _outputColumn) {
- throw new Error('Not supported');
- }
- getViewPositionOfModelPosition(_deltaLineNumber, _inputColumn) {
- throw new Error('Not supported');
- }
- getViewLineNumberOfModelPosition(_deltaLineNumber, _inputColumn) {
- throw new Error('Not supported');
- }
- normalizePosition(outputLineIndex, outputPosition, affinity) {
- throw new Error('Not supported');
- }
- getInjectedTextAt(_outputLineIndex, _outputColumn) {
- throw new Error('Not supported');
- }
- }
- HiddenModelLineProjection.INSTANCE = new HiddenModelLineProjection();
- const _spaces = [''];
- function spaces(count) {
- if (count >= _spaces.length) {
- for (let i = 1; i <= count; i++) {
- _spaces[i] = _makeSpaces(i);
- }
- }
- return _spaces[count];
- }
- function _makeSpaces(count) {
- return new Array(count + 1).join(' ');
- }
|