123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927 |
- /*---------------------------------------------------------------------------------------------
- * Copyright (c) Microsoft Corporation. All rights reserved.
- * Licensed under the MIT License. See License.txt in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
- import * as arrays from '../../../base/common/arrays.js';
- import { Position } from '../core/position.js';
- import { Range } from '../core/range.js';
- import { IndentGuide, IndentGuideHorizontalLine } from '../model.js';
- import { ModelDecorationOptions } from '../model/textModel.js';
- import { LineInjectedText } from '../model/textModelEvents.js';
- import * as viewEvents from '../view/viewEvents.js';
- import { createModelLineProjection } from './modelLineProjection.js';
- import { ConstantTimePrefixSumComputer } from './prefixSumComputer.js';
- import { ViewLineData } from './viewModel.js';
- export class ViewModelLinesFromProjectedModel {
- constructor(editorId, model, domLineBreaksComputerFactory, monospaceLineBreaksComputerFactory, fontInfo, tabSize, wrappingStrategy, wrappingColumn, wrappingIndent) {
- this._editorId = editorId;
- this.model = model;
- this._validModelVersionId = -1;
- this._domLineBreaksComputerFactory = domLineBreaksComputerFactory;
- this._monospaceLineBreaksComputerFactory = monospaceLineBreaksComputerFactory;
- this.fontInfo = fontInfo;
- this.tabSize = tabSize;
- this.wrappingStrategy = wrappingStrategy;
- this.wrappingColumn = wrappingColumn;
- this.wrappingIndent = wrappingIndent;
- this._constructLines(/*resetHiddenAreas*/ true, null);
- }
- dispose() {
- this.hiddenAreasDecorationIds = this.model.deltaDecorations(this.hiddenAreasDecorationIds, []);
- }
- createCoordinatesConverter() {
- return new CoordinatesConverter(this);
- }
- _constructLines(resetHiddenAreas, previousLineBreaks) {
- this.modelLineProjections = [];
- if (resetHiddenAreas) {
- this.hiddenAreasDecorationIds = this.model.deltaDecorations(this.hiddenAreasDecorationIds, []);
- }
- const linesContent = this.model.getLinesContent();
- const injectedTextDecorations = this.model.getInjectedTextDecorations(this._editorId);
- const lineCount = linesContent.length;
- const lineBreaksComputer = this.createLineBreaksComputer();
- const injectedTextQueue = new arrays.ArrayQueue(LineInjectedText.fromDecorations(injectedTextDecorations));
- for (let i = 0; i < lineCount; i++) {
- const lineInjectedText = injectedTextQueue.takeWhile(t => t.lineNumber === i + 1);
- lineBreaksComputer.addRequest(linesContent[i], lineInjectedText, previousLineBreaks ? previousLineBreaks[i] : null);
- }
- const linesBreaks = lineBreaksComputer.finalize();
- let values = [];
- let hiddenAreas = this.hiddenAreasDecorationIds.map((areaId) => this.model.getDecorationRange(areaId)).sort(Range.compareRangesUsingStarts);
- let hiddenAreaStart = 1, hiddenAreaEnd = 0;
- let hiddenAreaIdx = -1;
- let nextLineNumberToUpdateHiddenArea = (hiddenAreaIdx + 1 < hiddenAreas.length) ? hiddenAreaEnd + 1 : lineCount + 2;
- for (let i = 0; i < lineCount; i++) {
- let lineNumber = i + 1;
- if (lineNumber === nextLineNumberToUpdateHiddenArea) {
- hiddenAreaIdx++;
- hiddenAreaStart = hiddenAreas[hiddenAreaIdx].startLineNumber;
- hiddenAreaEnd = hiddenAreas[hiddenAreaIdx].endLineNumber;
- nextLineNumberToUpdateHiddenArea = (hiddenAreaIdx + 1 < hiddenAreas.length) ? hiddenAreaEnd + 1 : lineCount + 2;
- }
- let isInHiddenArea = (lineNumber >= hiddenAreaStart && lineNumber <= hiddenAreaEnd);
- let line = createModelLineProjection(linesBreaks[i], !isInHiddenArea);
- values[i] = line.getViewLineCount();
- this.modelLineProjections[i] = line;
- }
- this._validModelVersionId = this.model.getVersionId();
- this.projectedModelLineLineCounts = new ConstantTimePrefixSumComputer(values);
- }
- getHiddenAreas() {
- return this.hiddenAreasDecorationIds.map((decId) => this.model.getDecorationRange(decId));
- }
- setHiddenAreas(_ranges) {
- const validatedRanges = _ranges.map(r => this.model.validateRange(r));
- let newRanges = normalizeLineRanges(validatedRanges);
- // TODO@Martin: Please stop calling this method on each model change!
- // This checks if there really was a change
- let oldRanges = this.hiddenAreasDecorationIds.map((areaId) => this.model.getDecorationRange(areaId)).sort(Range.compareRangesUsingStarts);
- if (newRanges.length === oldRanges.length) {
- let hasDifference = false;
- for (let i = 0; i < newRanges.length; i++) {
- if (!newRanges[i].equalsRange(oldRanges[i])) {
- hasDifference = true;
- break;
- }
- }
- if (!hasDifference) {
- return false;
- }
- }
- const newDecorations = newRanges.map((r) => ({
- range: r,
- options: ModelDecorationOptions.EMPTY,
- }));
- this.hiddenAreasDecorationIds = this.model.deltaDecorations(this.hiddenAreasDecorationIds, newDecorations);
- let hiddenAreas = newRanges;
- let hiddenAreaStart = 1, hiddenAreaEnd = 0;
- let hiddenAreaIdx = -1;
- let nextLineNumberToUpdateHiddenArea = (hiddenAreaIdx + 1 < hiddenAreas.length) ? hiddenAreaEnd + 1 : this.modelLineProjections.length + 2;
- let hasVisibleLine = false;
- for (let i = 0; i < this.modelLineProjections.length; i++) {
- let lineNumber = i + 1;
- if (lineNumber === nextLineNumberToUpdateHiddenArea) {
- hiddenAreaIdx++;
- hiddenAreaStart = hiddenAreas[hiddenAreaIdx].startLineNumber;
- hiddenAreaEnd = hiddenAreas[hiddenAreaIdx].endLineNumber;
- nextLineNumberToUpdateHiddenArea = (hiddenAreaIdx + 1 < hiddenAreas.length) ? hiddenAreaEnd + 1 : this.modelLineProjections.length + 2;
- }
- let lineChanged = false;
- if (lineNumber >= hiddenAreaStart && lineNumber <= hiddenAreaEnd) {
- // Line should be hidden
- if (this.modelLineProjections[i].isVisible()) {
- this.modelLineProjections[i] = this.modelLineProjections[i].setVisible(false);
- lineChanged = true;
- }
- }
- else {
- hasVisibleLine = true;
- // Line should be visible
- if (!this.modelLineProjections[i].isVisible()) {
- this.modelLineProjections[i] = this.modelLineProjections[i].setVisible(true);
- lineChanged = true;
- }
- }
- if (lineChanged) {
- let newOutputLineCount = this.modelLineProjections[i].getViewLineCount();
- this.projectedModelLineLineCounts.setValue(i, newOutputLineCount);
- }
- }
- if (!hasVisibleLine) {
- // Cannot have everything be hidden => reveal everything!
- this.setHiddenAreas([]);
- }
- return true;
- }
- modelPositionIsVisible(modelLineNumber, _modelColumn) {
- if (modelLineNumber < 1 || modelLineNumber > this.modelLineProjections.length) {
- // invalid arguments
- return false;
- }
- return this.modelLineProjections[modelLineNumber - 1].isVisible();
- }
- getModelLineViewLineCount(modelLineNumber) {
- if (modelLineNumber < 1 || modelLineNumber > this.modelLineProjections.length) {
- // invalid arguments
- return 1;
- }
- return this.modelLineProjections[modelLineNumber - 1].getViewLineCount();
- }
- setTabSize(newTabSize) {
- if (this.tabSize === newTabSize) {
- return false;
- }
- this.tabSize = newTabSize;
- this._constructLines(/*resetHiddenAreas*/ false, null);
- return true;
- }
- setWrappingSettings(fontInfo, wrappingStrategy, wrappingColumn, wrappingIndent) {
- const equalFontInfo = this.fontInfo.equals(fontInfo);
- const equalWrappingStrategy = (this.wrappingStrategy === wrappingStrategy);
- const equalWrappingColumn = (this.wrappingColumn === wrappingColumn);
- const equalWrappingIndent = (this.wrappingIndent === wrappingIndent);
- if (equalFontInfo && equalWrappingStrategy && equalWrappingColumn && equalWrappingIndent) {
- return false;
- }
- const onlyWrappingColumnChanged = (equalFontInfo && equalWrappingStrategy && !equalWrappingColumn && equalWrappingIndent);
- this.fontInfo = fontInfo;
- this.wrappingStrategy = wrappingStrategy;
- this.wrappingColumn = wrappingColumn;
- this.wrappingIndent = wrappingIndent;
- let previousLineBreaks = null;
- if (onlyWrappingColumnChanged) {
- previousLineBreaks = [];
- for (let i = 0, len = this.modelLineProjections.length; i < len; i++) {
- previousLineBreaks[i] = this.modelLineProjections[i].getLineBreakData();
- }
- }
- this._constructLines(/*resetHiddenAreas*/ false, previousLineBreaks);
- return true;
- }
- createLineBreaksComputer() {
- const lineBreaksComputerFactory = (this.wrappingStrategy === 'advanced'
- ? this._domLineBreaksComputerFactory
- : this._monospaceLineBreaksComputerFactory);
- return lineBreaksComputerFactory.createLineBreaksComputer(this.fontInfo, this.tabSize, this.wrappingColumn, this.wrappingIndent);
- }
- onModelFlushed() {
- this._constructLines(/*resetHiddenAreas*/ true, null);
- }
- onModelLinesDeleted(versionId, fromLineNumber, toLineNumber) {
- if (!versionId || versionId <= this._validModelVersionId) {
- // Here we check for versionId in case the lines were reconstructed in the meantime.
- // We don't want to apply stale change events on top of a newer read model state.
- return null;
- }
- let outputFromLineNumber = (fromLineNumber === 1 ? 1 : this.projectedModelLineLineCounts.getPrefixSum(fromLineNumber - 1) + 1);
- let outputToLineNumber = this.projectedModelLineLineCounts.getPrefixSum(toLineNumber);
- this.modelLineProjections.splice(fromLineNumber - 1, toLineNumber - fromLineNumber + 1);
- this.projectedModelLineLineCounts.removeValues(fromLineNumber - 1, toLineNumber - fromLineNumber + 1);
- return new viewEvents.ViewLinesDeletedEvent(outputFromLineNumber, outputToLineNumber);
- }
- onModelLinesInserted(versionId, fromLineNumber, _toLineNumber, lineBreaks) {
- if (!versionId || versionId <= this._validModelVersionId) {
- // Here we check for versionId in case the lines were reconstructed in the meantime.
- // We don't want to apply stale change events on top of a newer read model state.
- return null;
- }
- // cannot use this.getHiddenAreas() because those decorations have already seen the effect of this model change
- const isInHiddenArea = (fromLineNumber > 2 && !this.modelLineProjections[fromLineNumber - 2].isVisible());
- let outputFromLineNumber = (fromLineNumber === 1 ? 1 : this.projectedModelLineLineCounts.getPrefixSum(fromLineNumber - 1) + 1);
- let totalOutputLineCount = 0;
- let insertLines = [];
- let insertPrefixSumValues = [];
- for (let i = 0, len = lineBreaks.length; i < len; i++) {
- let line = createModelLineProjection(lineBreaks[i], !isInHiddenArea);
- insertLines.push(line);
- let outputLineCount = line.getViewLineCount();
- totalOutputLineCount += outputLineCount;
- insertPrefixSumValues[i] = outputLineCount;
- }
- // TODO@Alex: use arrays.arrayInsert
- this.modelLineProjections =
- this.modelLineProjections.slice(0, fromLineNumber - 1)
- .concat(insertLines)
- .concat(this.modelLineProjections.slice(fromLineNumber - 1));
- this.projectedModelLineLineCounts.insertValues(fromLineNumber - 1, insertPrefixSumValues);
- return new viewEvents.ViewLinesInsertedEvent(outputFromLineNumber, outputFromLineNumber + totalOutputLineCount - 1);
- }
- onModelLineChanged(versionId, lineNumber, lineBreakData) {
- if (versionId !== null && versionId <= this._validModelVersionId) {
- // Here we check for versionId in case the lines were reconstructed in the meantime.
- // We don't want to apply stale change events on top of a newer read model state.
- return [false, null, null, null];
- }
- let lineIndex = lineNumber - 1;
- let oldOutputLineCount = this.modelLineProjections[lineIndex].getViewLineCount();
- let isVisible = this.modelLineProjections[lineIndex].isVisible();
- let line = createModelLineProjection(lineBreakData, isVisible);
- this.modelLineProjections[lineIndex] = line;
- let newOutputLineCount = this.modelLineProjections[lineIndex].getViewLineCount();
- let lineMappingChanged = false;
- let changeFrom = 0;
- let changeTo = -1;
- let insertFrom = 0;
- let insertTo = -1;
- let deleteFrom = 0;
- let deleteTo = -1;
- if (oldOutputLineCount > newOutputLineCount) {
- changeFrom = this.projectedModelLineLineCounts.getPrefixSum(lineNumber - 1) + 1;
- changeTo = changeFrom + newOutputLineCount - 1;
- deleteFrom = changeTo + 1;
- deleteTo = deleteFrom + (oldOutputLineCount - newOutputLineCount) - 1;
- lineMappingChanged = true;
- }
- else if (oldOutputLineCount < newOutputLineCount) {
- changeFrom = this.projectedModelLineLineCounts.getPrefixSum(lineNumber - 1) + 1;
- changeTo = changeFrom + oldOutputLineCount - 1;
- insertFrom = changeTo + 1;
- insertTo = insertFrom + (newOutputLineCount - oldOutputLineCount) - 1;
- lineMappingChanged = true;
- }
- else {
- changeFrom = this.projectedModelLineLineCounts.getPrefixSum(lineNumber - 1) + 1;
- changeTo = changeFrom + newOutputLineCount - 1;
- }
- this.projectedModelLineLineCounts.setValue(lineIndex, newOutputLineCount);
- const viewLinesChangedEvent = (changeFrom <= changeTo ? new viewEvents.ViewLinesChangedEvent(changeFrom, changeTo) : null);
- const viewLinesInsertedEvent = (insertFrom <= insertTo ? new viewEvents.ViewLinesInsertedEvent(insertFrom, insertTo) : null);
- const viewLinesDeletedEvent = (deleteFrom <= deleteTo ? new viewEvents.ViewLinesDeletedEvent(deleteFrom, deleteTo) : null);
- return [lineMappingChanged, viewLinesChangedEvent, viewLinesInsertedEvent, viewLinesDeletedEvent];
- }
- acceptVersionId(versionId) {
- this._validModelVersionId = versionId;
- if (this.modelLineProjections.length === 1 && !this.modelLineProjections[0].isVisible()) {
- // At least one line must be visible => reset hidden areas
- this.setHiddenAreas([]);
- }
- }
- getViewLineCount() {
- return this.projectedModelLineLineCounts.getTotalSum();
- }
- _toValidViewLineNumber(viewLineNumber) {
- if (viewLineNumber < 1) {
- return 1;
- }
- const viewLineCount = this.getViewLineCount();
- if (viewLineNumber > viewLineCount) {
- return viewLineCount;
- }
- return viewLineNumber | 0;
- }
- getActiveIndentGuide(viewLineNumber, minLineNumber, maxLineNumber) {
- viewLineNumber = this._toValidViewLineNumber(viewLineNumber);
- minLineNumber = this._toValidViewLineNumber(minLineNumber);
- maxLineNumber = this._toValidViewLineNumber(maxLineNumber);
- const modelPosition = this.convertViewPositionToModelPosition(viewLineNumber, this.getViewLineMinColumn(viewLineNumber));
- const modelMinPosition = this.convertViewPositionToModelPosition(minLineNumber, this.getViewLineMinColumn(minLineNumber));
- const modelMaxPosition = this.convertViewPositionToModelPosition(maxLineNumber, this.getViewLineMinColumn(maxLineNumber));
- const result = this.model.getActiveIndentGuide(modelPosition.lineNumber, modelMinPosition.lineNumber, modelMaxPosition.lineNumber);
- const viewStartPosition = this.convertModelPositionToViewPosition(result.startLineNumber, 1);
- const viewEndPosition = this.convertModelPositionToViewPosition(result.endLineNumber, this.model.getLineMaxColumn(result.endLineNumber));
- return {
- startLineNumber: viewStartPosition.lineNumber,
- endLineNumber: viewEndPosition.lineNumber,
- indent: result.indent
- };
- }
- // #region ViewLineInfo
- getViewLineInfo(viewLineNumber) {
- viewLineNumber = this._toValidViewLineNumber(viewLineNumber);
- let r = this.projectedModelLineLineCounts.getIndexOf(viewLineNumber - 1);
- let lineIndex = r.index;
- let remainder = r.remainder;
- return new ViewLineInfo(lineIndex + 1, remainder);
- }
- getMinColumnOfViewLine(viewLineInfo) {
- return this.modelLineProjections[viewLineInfo.modelLineNumber - 1].getViewLineMinColumn(this.model, viewLineInfo.modelLineNumber, viewLineInfo.modelLineWrappedLineIdx);
- }
- getModelStartPositionOfViewLine(viewLineInfo) {
- const line = this.modelLineProjections[viewLineInfo.modelLineNumber - 1];
- const minViewColumn = line.getViewLineMinColumn(this.model, viewLineInfo.modelLineNumber, viewLineInfo.modelLineWrappedLineIdx);
- const column = line.getModelColumnOfViewPosition(viewLineInfo.modelLineWrappedLineIdx, minViewColumn);
- return new Position(viewLineInfo.modelLineNumber, column);
- }
- getModelEndPositionOfViewLine(viewLineInfo) {
- const line = this.modelLineProjections[viewLineInfo.modelLineNumber - 1];
- const maxViewColumn = line.getViewLineMaxColumn(this.model, viewLineInfo.modelLineNumber, viewLineInfo.modelLineWrappedLineIdx);
- const column = line.getModelColumnOfViewPosition(viewLineInfo.modelLineWrappedLineIdx, maxViewColumn);
- return new Position(viewLineInfo.modelLineNumber, column);
- }
- getViewLineInfosGroupedByModelRanges(viewStartLineNumber, viewEndLineNumber) {
- const startViewLine = this.getViewLineInfo(viewStartLineNumber);
- const endViewLine = this.getViewLineInfo(viewEndLineNumber);
- const result = new Array();
- let lastVisibleModelPos = this.getModelStartPositionOfViewLine(startViewLine);
- let viewLines = new Array();
- for (let curModelLine = startViewLine.modelLineNumber; curModelLine <= endViewLine.modelLineNumber; curModelLine++) {
- const line = this.modelLineProjections[curModelLine - 1];
- if (line.isVisible()) {
- let startOffset = curModelLine === startViewLine.modelLineNumber
- ? startViewLine.modelLineWrappedLineIdx
- : 0;
- let endOffset = curModelLine === endViewLine.modelLineNumber
- ? endViewLine.modelLineWrappedLineIdx + 1
- : line.getViewLineCount();
- for (let i = startOffset; i < endOffset; i++) {
- viewLines.push(new ViewLineInfo(curModelLine, i));
- }
- }
- if (!line.isVisible() && lastVisibleModelPos) {
- const lastVisibleModelPos2 = new Position(curModelLine - 1, this.model.getLineMaxColumn(curModelLine - 1) + 1);
- const modelRange = Range.fromPositions(lastVisibleModelPos, lastVisibleModelPos2);
- result.push(new ViewLineInfoGroupedByModelRange(modelRange, viewLines));
- viewLines = [];
- lastVisibleModelPos = null;
- }
- else if (line.isVisible() && !lastVisibleModelPos) {
- lastVisibleModelPos = new Position(curModelLine, 1);
- }
- }
- if (lastVisibleModelPos) {
- const modelRange = Range.fromPositions(lastVisibleModelPos, this.getModelEndPositionOfViewLine(endViewLine));
- result.push(new ViewLineInfoGroupedByModelRange(modelRange, viewLines));
- }
- return result;
- }
- // #endregion
- getViewLinesBracketGuides(viewStartLineNumber, viewEndLineNumber, activeViewPosition, options) {
- const modelActivePosition = activeViewPosition ? this.convertViewPositionToModelPosition(activeViewPosition.lineNumber, activeViewPosition.column) : null;
- const resultPerViewLine = [];
- for (const group of this.getViewLineInfosGroupedByModelRanges(viewStartLineNumber, viewEndLineNumber)) {
- const modelRangeStartLineNumber = group.modelRange.startLineNumber;
- const bracketGuidesPerModelLine = this.model.getLinesBracketGuides(modelRangeStartLineNumber, group.modelRange.endLineNumber, modelActivePosition, options);
- for (const viewLineInfo of group.viewLines) {
- if (viewLineInfo.isWrappedLineContinuation && this.getMinColumnOfViewLine(viewLineInfo) === 1) {
- // Don't add indent guides when the wrapped line continuation has no wrapping-indentation.
- resultPerViewLine.push([]);
- }
- else {
- let bracketGuides = bracketGuidesPerModelLine[viewLineInfo.modelLineNumber - modelRangeStartLineNumber];
- // visibleColumns stay as they are (this is a bug and needs to be fixed, but it is not a regression)
- // model-columns must be converted to view-model columns.
- bracketGuides = bracketGuides.map(g => g.horizontalLine ?
- new IndentGuide(g.visibleColumn, g.className, new IndentGuideHorizontalLine(g.horizontalLine.top, this.convertModelPositionToViewPosition(viewLineInfo.modelLineNumber, g.horizontalLine.endColumn).column)) : g);
- resultPerViewLine.push(bracketGuides);
- }
- }
- }
- return resultPerViewLine;
- }
- getViewLinesIndentGuides(viewStartLineNumber, viewEndLineNumber) {
- // TODO: Use the same code as in `getViewLinesBracketGuides`.
- // Future TODO: Merge with `getViewLinesBracketGuides`.
- // However, this requires more refactoring of indent guides.
- viewStartLineNumber = this._toValidViewLineNumber(viewStartLineNumber);
- viewEndLineNumber = this._toValidViewLineNumber(viewEndLineNumber);
- const modelStart = this.convertViewPositionToModelPosition(viewStartLineNumber, this.getViewLineMinColumn(viewStartLineNumber));
- const modelEnd = this.convertViewPositionToModelPosition(viewEndLineNumber, this.getViewLineMaxColumn(viewEndLineNumber));
- let result = [];
- let resultRepeatCount = [];
- let resultRepeatOption = [];
- const modelStartLineIndex = modelStart.lineNumber - 1;
- const modelEndLineIndex = modelEnd.lineNumber - 1;
- let reqStart = null;
- for (let modelLineIndex = modelStartLineIndex; modelLineIndex <= modelEndLineIndex; modelLineIndex++) {
- const line = this.modelLineProjections[modelLineIndex];
- if (line.isVisible()) {
- let viewLineStartIndex = line.getViewLineNumberOfModelPosition(0, modelLineIndex === modelStartLineIndex ? modelStart.column : 1);
- let viewLineEndIndex = line.getViewLineNumberOfModelPosition(0, this.model.getLineMaxColumn(modelLineIndex + 1));
- let count = viewLineEndIndex - viewLineStartIndex + 1;
- let option = 0 /* BlockNone */;
- if (count > 1 && line.getViewLineMinColumn(this.model, modelLineIndex + 1, viewLineEndIndex) === 1) {
- // wrapped lines should block indent guides
- option = (viewLineStartIndex === 0 ? 1 /* BlockSubsequent */ : 2 /* BlockAll */);
- }
- resultRepeatCount.push(count);
- resultRepeatOption.push(option);
- // merge into previous request
- if (reqStart === null) {
- reqStart = new Position(modelLineIndex + 1, 0);
- }
- }
- else {
- // hit invisible line => flush request
- if (reqStart !== null) {
- result = result.concat(this.model.getLinesIndentGuides(reqStart.lineNumber, modelLineIndex));
- reqStart = null;
- }
- }
- }
- if (reqStart !== null) {
- result = result.concat(this.model.getLinesIndentGuides(reqStart.lineNumber, modelEnd.lineNumber));
- reqStart = null;
- }
- const viewLineCount = viewEndLineNumber - viewStartLineNumber + 1;
- let viewIndents = new Array(viewLineCount);
- let currIndex = 0;
- for (let i = 0, len = result.length; i < len; i++) {
- let value = result[i];
- let count = Math.min(viewLineCount - currIndex, resultRepeatCount[i]);
- let option = resultRepeatOption[i];
- let blockAtIndex;
- if (option === 2 /* BlockAll */) {
- blockAtIndex = 0;
- }
- else if (option === 1 /* BlockSubsequent */) {
- blockAtIndex = 1;
- }
- else {
- blockAtIndex = count;
- }
- for (let j = 0; j < count; j++) {
- if (j === blockAtIndex) {
- value = 0;
- }
- viewIndents[currIndex++] = value;
- }
- }
- return viewIndents;
- }
- getViewLineContent(viewLineNumber) {
- const info = this.getViewLineInfo(viewLineNumber);
- return this.modelLineProjections[info.modelLineNumber - 1].getViewLineContent(this.model, info.modelLineNumber, info.modelLineWrappedLineIdx);
- }
- getViewLineLength(viewLineNumber) {
- const info = this.getViewLineInfo(viewLineNumber);
- return this.modelLineProjections[info.modelLineNumber - 1].getViewLineLength(this.model, info.modelLineNumber, info.modelLineWrappedLineIdx);
- }
- getViewLineMinColumn(viewLineNumber) {
- const info = this.getViewLineInfo(viewLineNumber);
- return this.modelLineProjections[info.modelLineNumber - 1].getViewLineMinColumn(this.model, info.modelLineNumber, info.modelLineWrappedLineIdx);
- }
- getViewLineMaxColumn(viewLineNumber) {
- const info = this.getViewLineInfo(viewLineNumber);
- return this.modelLineProjections[info.modelLineNumber - 1].getViewLineMaxColumn(this.model, info.modelLineNumber, info.modelLineWrappedLineIdx);
- }
- getViewLineData(viewLineNumber) {
- const info = this.getViewLineInfo(viewLineNumber);
- return this.modelLineProjections[info.modelLineNumber - 1].getViewLineData(this.model, info.modelLineNumber, info.modelLineWrappedLineIdx);
- }
- getViewLinesData(viewStartLineNumber, viewEndLineNumber, needed) {
- viewStartLineNumber = this._toValidViewLineNumber(viewStartLineNumber);
- viewEndLineNumber = this._toValidViewLineNumber(viewEndLineNumber);
- let start = this.projectedModelLineLineCounts.getIndexOf(viewStartLineNumber - 1);
- let viewLineNumber = viewStartLineNumber;
- let startModelLineIndex = start.index;
- let startRemainder = start.remainder;
- let result = [];
- for (let modelLineIndex = startModelLineIndex, len = this.model.getLineCount(); modelLineIndex < len; modelLineIndex++) {
- let line = this.modelLineProjections[modelLineIndex];
- if (!line.isVisible()) {
- continue;
- }
- let fromViewLineIndex = (modelLineIndex === startModelLineIndex ? startRemainder : 0);
- let remainingViewLineCount = line.getViewLineCount() - fromViewLineIndex;
- let lastLine = false;
- if (viewLineNumber + remainingViewLineCount > viewEndLineNumber) {
- lastLine = true;
- remainingViewLineCount = viewEndLineNumber - viewLineNumber + 1;
- }
- let toViewLineIndex = fromViewLineIndex + remainingViewLineCount;
- line.getViewLinesData(this.model, modelLineIndex + 1, fromViewLineIndex, toViewLineIndex, viewLineNumber - viewStartLineNumber, needed, result);
- viewLineNumber += remainingViewLineCount;
- if (lastLine) {
- break;
- }
- }
- return result;
- }
- validateViewPosition(viewLineNumber, viewColumn, expectedModelPosition) {
- viewLineNumber = this._toValidViewLineNumber(viewLineNumber);
- let r = this.projectedModelLineLineCounts.getIndexOf(viewLineNumber - 1);
- let lineIndex = r.index;
- let remainder = r.remainder;
- let line = this.modelLineProjections[lineIndex];
- let minColumn = line.getViewLineMinColumn(this.model, lineIndex + 1, remainder);
- let maxColumn = line.getViewLineMaxColumn(this.model, lineIndex + 1, remainder);
- if (viewColumn < minColumn) {
- viewColumn = minColumn;
- }
- if (viewColumn > maxColumn) {
- viewColumn = maxColumn;
- }
- let computedModelColumn = line.getModelColumnOfViewPosition(remainder, viewColumn);
- let computedModelPosition = this.model.validatePosition(new Position(lineIndex + 1, computedModelColumn));
- if (computedModelPosition.equals(expectedModelPosition)) {
- return new Position(viewLineNumber, viewColumn);
- }
- return this.convertModelPositionToViewPosition(expectedModelPosition.lineNumber, expectedModelPosition.column);
- }
- validateViewRange(viewRange, expectedModelRange) {
- const validViewStart = this.validateViewPosition(viewRange.startLineNumber, viewRange.startColumn, expectedModelRange.getStartPosition());
- const validViewEnd = this.validateViewPosition(viewRange.endLineNumber, viewRange.endColumn, expectedModelRange.getEndPosition());
- return new Range(validViewStart.lineNumber, validViewStart.column, validViewEnd.lineNumber, validViewEnd.column);
- }
- convertViewPositionToModelPosition(viewLineNumber, viewColumn) {
- const info = this.getViewLineInfo(viewLineNumber);
- let inputColumn = this.modelLineProjections[info.modelLineNumber - 1].getModelColumnOfViewPosition(info.modelLineWrappedLineIdx, viewColumn);
- // console.log('out -> in ' + viewLineNumber + ',' + viewColumn + ' ===> ' + (lineIndex+1) + ',' + inputColumn);
- return this.model.validatePosition(new Position(info.modelLineNumber, inputColumn));
- }
- convertViewRangeToModelRange(viewRange) {
- const start = this.convertViewPositionToModelPosition(viewRange.startLineNumber, viewRange.startColumn);
- const end = this.convertViewPositionToModelPosition(viewRange.endLineNumber, viewRange.endColumn);
- return new Range(start.lineNumber, start.column, end.lineNumber, end.column);
- }
- convertModelPositionToViewPosition(_modelLineNumber, _modelColumn, affinity = 2 /* None */) {
- const validPosition = this.model.validatePosition(new Position(_modelLineNumber, _modelColumn));
- const inputLineNumber = validPosition.lineNumber;
- const inputColumn = validPosition.column;
- let lineIndex = inputLineNumber - 1, lineIndexChanged = false;
- while (lineIndex > 0 && !this.modelLineProjections[lineIndex].isVisible()) {
- lineIndex--;
- lineIndexChanged = true;
- }
- if (lineIndex === 0 && !this.modelLineProjections[lineIndex].isVisible()) {
- // Could not reach a real line
- // console.log('in -> out ' + inputLineNumber + ',' + inputColumn + ' ===> ' + 1 + ',' + 1);
- return new Position(1, 1);
- }
- const deltaLineNumber = 1 + this.projectedModelLineLineCounts.getPrefixSum(lineIndex);
- let r;
- if (lineIndexChanged) {
- r = this.modelLineProjections[lineIndex].getViewPositionOfModelPosition(deltaLineNumber, this.model.getLineMaxColumn(lineIndex + 1), affinity);
- }
- else {
- r = this.modelLineProjections[inputLineNumber - 1].getViewPositionOfModelPosition(deltaLineNumber, inputColumn, affinity);
- }
- // console.log('in -> out ' + inputLineNumber + ',' + inputColumn + ' ===> ' + r.lineNumber + ',' + r);
- return r;
- }
- /**
- * @param affinity The affinity in case of an empty range. Has no effect for non-empty ranges.
- */
- convertModelRangeToViewRange(modelRange, affinity = 0 /* Left */) {
- if (modelRange.isEmpty()) {
- const start = this.convertModelPositionToViewPosition(modelRange.startLineNumber, modelRange.startColumn, affinity);
- return Range.fromPositions(start);
- }
- else {
- const start = this.convertModelPositionToViewPosition(modelRange.startLineNumber, modelRange.startColumn, 1 /* Right */);
- const end = this.convertModelPositionToViewPosition(modelRange.endLineNumber, modelRange.endColumn, 0 /* Left */);
- return new Range(start.lineNumber, start.column, end.lineNumber, end.column);
- }
- }
- getViewLineNumberOfModelPosition(modelLineNumber, modelColumn) {
- let lineIndex = modelLineNumber - 1;
- if (this.modelLineProjections[lineIndex].isVisible()) {
- // this model line is visible
- const deltaLineNumber = 1 + this.projectedModelLineLineCounts.getPrefixSum(lineIndex);
- return this.modelLineProjections[lineIndex].getViewLineNumberOfModelPosition(deltaLineNumber, modelColumn);
- }
- // this model line is not visible
- while (lineIndex > 0 && !this.modelLineProjections[lineIndex].isVisible()) {
- lineIndex--;
- }
- if (lineIndex === 0 && !this.modelLineProjections[lineIndex].isVisible()) {
- // Could not reach a real line
- return 1;
- }
- const deltaLineNumber = 1 + this.projectedModelLineLineCounts.getPrefixSum(lineIndex);
- return this.modelLineProjections[lineIndex].getViewLineNumberOfModelPosition(deltaLineNumber, this.model.getLineMaxColumn(lineIndex + 1));
- }
- getDecorationsInRange(range, ownerId, filterOutValidation) {
- const modelStart = this.convertViewPositionToModelPosition(range.startLineNumber, range.startColumn);
- const modelEnd = this.convertViewPositionToModelPosition(range.endLineNumber, range.endColumn);
- if (modelEnd.lineNumber - modelStart.lineNumber <= range.endLineNumber - range.startLineNumber) {
- // most likely there are no hidden lines => fast path
- // fetch decorations from column 1 to cover the case of wrapped lines that have whole line decorations at column 1
- return this.model.getDecorationsInRange(new Range(modelStart.lineNumber, 1, modelEnd.lineNumber, modelEnd.column), ownerId, filterOutValidation);
- }
- let result = [];
- const modelStartLineIndex = modelStart.lineNumber - 1;
- const modelEndLineIndex = modelEnd.lineNumber - 1;
- let reqStart = null;
- for (let modelLineIndex = modelStartLineIndex; modelLineIndex <= modelEndLineIndex; modelLineIndex++) {
- const line = this.modelLineProjections[modelLineIndex];
- if (line.isVisible()) {
- // merge into previous request
- if (reqStart === null) {
- reqStart = new Position(modelLineIndex + 1, modelLineIndex === modelStartLineIndex ? modelStart.column : 1);
- }
- }
- else {
- // hit invisible line => flush request
- if (reqStart !== null) {
- const maxLineColumn = this.model.getLineMaxColumn(modelLineIndex);
- result = result.concat(this.model.getDecorationsInRange(new Range(reqStart.lineNumber, reqStart.column, modelLineIndex, maxLineColumn), ownerId, filterOutValidation));
- reqStart = null;
- }
- }
- }
- if (reqStart !== null) {
- result = result.concat(this.model.getDecorationsInRange(new Range(reqStart.lineNumber, reqStart.column, modelEnd.lineNumber, modelEnd.column), ownerId, filterOutValidation));
- reqStart = null;
- }
- result.sort((a, b) => {
- const res = Range.compareRangesUsingStarts(a.range, b.range);
- if (res === 0) {
- if (a.id < b.id) {
- return -1;
- }
- if (a.id > b.id) {
- return 1;
- }
- return 0;
- }
- return res;
- });
- // Eliminate duplicate decorations that might have intersected our visible ranges multiple times
- let finalResult = [], finalResultLen = 0;
- let prevDecId = null;
- for (const dec of result) {
- const decId = dec.id;
- if (prevDecId === decId) {
- // skip
- continue;
- }
- prevDecId = decId;
- finalResult[finalResultLen++] = dec;
- }
- return finalResult;
- }
- getInjectedTextAt(position) {
- const info = this.getViewLineInfo(position.lineNumber);
- return this.modelLineProjections[info.modelLineNumber - 1].getInjectedTextAt(info.modelLineWrappedLineIdx, position.column);
- }
- normalizePosition(position, affinity) {
- const info = this.getViewLineInfo(position.lineNumber);
- return this.modelLineProjections[info.modelLineNumber - 1].normalizePosition(info.modelLineWrappedLineIdx, position, affinity);
- }
- getLineIndentColumn(lineNumber) {
- const info = this.getViewLineInfo(lineNumber);
- if (info.modelLineWrappedLineIdx === 0) {
- return this.model.getLineIndentColumn(info.modelLineNumber);
- }
- // wrapped lines have no indentation.
- // We deliberately don't handle the case that indentation is wrapped
- // to avoid two view lines reporting indentation for the very same model line.
- return 0;
- }
- }
- /**
- * Overlapping unsorted ranges:
- * [ ) [ ) [ )
- * [ ) [ )
- * ->
- * Non overlapping sorted ranges:
- * [ ) [ ) [ )
- *
- * Note: This function only considers line information! Columns are ignored.
- */
- function normalizeLineRanges(ranges) {
- if (ranges.length === 0) {
- return [];
- }
- const sortedRanges = ranges.slice();
- sortedRanges.sort(Range.compareRangesUsingStarts);
- const result = [];
- let currentRangeStart = sortedRanges[0].startLineNumber;
- let currentRangeEnd = sortedRanges[0].endLineNumber;
- for (let i = 1, len = sortedRanges.length; i < len; i++) {
- let range = sortedRanges[i];
- if (range.startLineNumber > currentRangeEnd + 1) {
- result.push(new Range(currentRangeStart, 1, currentRangeEnd, 1));
- currentRangeStart = range.startLineNumber;
- currentRangeEnd = range.endLineNumber;
- }
- else if (range.endLineNumber > currentRangeEnd) {
- currentRangeEnd = range.endLineNumber;
- }
- }
- result.push(new Range(currentRangeStart, 1, currentRangeEnd, 1));
- return result;
- }
- /**
- * Represents a view line. Can be used to efficiently query more information about it.
- */
- class ViewLineInfo {
- constructor(modelLineNumber, modelLineWrappedLineIdx) {
- this.modelLineNumber = modelLineNumber;
- this.modelLineWrappedLineIdx = modelLineWrappedLineIdx;
- }
- get isWrappedLineContinuation() {
- return this.modelLineWrappedLineIdx > 0;
- }
- }
- /**
- * A list of view lines that have a contiguous span in the model.
- */
- class ViewLineInfoGroupedByModelRange {
- constructor(modelRange, viewLines) {
- this.modelRange = modelRange;
- this.viewLines = viewLines;
- }
- }
- class CoordinatesConverter {
- constructor(lines) {
- this._lines = lines;
- }
- // View -> Model conversion and related methods
- convertViewPositionToModelPosition(viewPosition) {
- return this._lines.convertViewPositionToModelPosition(viewPosition.lineNumber, viewPosition.column);
- }
- convertViewRangeToModelRange(viewRange) {
- return this._lines.convertViewRangeToModelRange(viewRange);
- }
- validateViewPosition(viewPosition, expectedModelPosition) {
- return this._lines.validateViewPosition(viewPosition.lineNumber, viewPosition.column, expectedModelPosition);
- }
- validateViewRange(viewRange, expectedModelRange) {
- return this._lines.validateViewRange(viewRange, expectedModelRange);
- }
- // Model -> View conversion and related methods
- convertModelPositionToViewPosition(modelPosition, affinity) {
- return this._lines.convertModelPositionToViewPosition(modelPosition.lineNumber, modelPosition.column, affinity);
- }
- convertModelRangeToViewRange(modelRange, affinity) {
- return this._lines.convertModelRangeToViewRange(modelRange, affinity);
- }
- modelPositionIsVisible(modelPosition) {
- return this._lines.modelPositionIsVisible(modelPosition.lineNumber, modelPosition.column);
- }
- getModelLineViewLineCount(modelLineNumber) {
- return this._lines.getModelLineViewLineCount(modelLineNumber);
- }
- getViewLineNumberOfModelPosition(modelLineNumber, modelColumn) {
- return this._lines.getViewLineNumberOfModelPosition(modelLineNumber, modelColumn);
- }
- }
- export class ViewModelLinesFromModelAsIs {
- constructor(model) {
- this.model = model;
- }
- dispose() {
- }
- createCoordinatesConverter() {
- return new IdentityCoordinatesConverter(this);
- }
- getHiddenAreas() {
- return [];
- }
- setHiddenAreas(_ranges) {
- return false;
- }
- setTabSize(_newTabSize) {
- return false;
- }
- setWrappingSettings(_fontInfo, _wrappingStrategy, _wrappingColumn, _wrappingIndent) {
- return false;
- }
- createLineBreaksComputer() {
- let result = [];
- return {
- addRequest: (lineText, injectedText, previousLineBreakData) => {
- result.push(null);
- },
- finalize: () => {
- return result;
- }
- };
- }
- onModelFlushed() {
- }
- onModelLinesDeleted(_versionId, fromLineNumber, toLineNumber) {
- return new viewEvents.ViewLinesDeletedEvent(fromLineNumber, toLineNumber);
- }
- onModelLinesInserted(_versionId, fromLineNumber, toLineNumber, lineBreaks) {
- return new viewEvents.ViewLinesInsertedEvent(fromLineNumber, toLineNumber);
- }
- onModelLineChanged(_versionId, lineNumber, lineBreakData) {
- return [false, new viewEvents.ViewLinesChangedEvent(lineNumber, lineNumber), null, null];
- }
- acceptVersionId(_versionId) {
- }
- getViewLineCount() {
- return this.model.getLineCount();
- }
- getActiveIndentGuide(viewLineNumber, _minLineNumber, _maxLineNumber) {
- return {
- startLineNumber: viewLineNumber,
- endLineNumber: viewLineNumber,
- indent: 0
- };
- }
- getViewLinesBracketGuides(startLineNumber, endLineNumber, activePosition) {
- return new Array(endLineNumber - startLineNumber + 1).fill([]);
- }
- getViewLinesIndentGuides(viewStartLineNumber, viewEndLineNumber) {
- const viewLineCount = viewEndLineNumber - viewStartLineNumber + 1;
- let result = new Array(viewLineCount);
- for (let i = 0; i < viewLineCount; i++) {
- result[i] = 0;
- }
- return result;
- }
- getViewLineContent(viewLineNumber) {
- return this.model.getLineContent(viewLineNumber);
- }
- getViewLineLength(viewLineNumber) {
- return this.model.getLineLength(viewLineNumber);
- }
- getViewLineMinColumn(viewLineNumber) {
- return this.model.getLineMinColumn(viewLineNumber);
- }
- getViewLineMaxColumn(viewLineNumber) {
- return this.model.getLineMaxColumn(viewLineNumber);
- }
- getViewLineData(viewLineNumber) {
- let lineTokens = this.model.getLineTokens(viewLineNumber);
- let lineContent = lineTokens.getLineContent();
- return new ViewLineData(lineContent, false, 1, lineContent.length + 1, 0, lineTokens.inflate(), null);
- }
- getViewLinesData(viewStartLineNumber, viewEndLineNumber, needed) {
- const lineCount = this.model.getLineCount();
- viewStartLineNumber = Math.min(Math.max(1, viewStartLineNumber), lineCount);
- viewEndLineNumber = Math.min(Math.max(1, viewEndLineNumber), lineCount);
- let result = [];
- for (let lineNumber = viewStartLineNumber; lineNumber <= viewEndLineNumber; lineNumber++) {
- let idx = lineNumber - viewStartLineNumber;
- if (!needed[idx]) {
- result[idx] = null;
- }
- result[idx] = this.getViewLineData(lineNumber);
- }
- return result;
- }
- getDecorationsInRange(range, ownerId, filterOutValidation) {
- return this.model.getDecorationsInRange(range, ownerId, filterOutValidation);
- }
- normalizePosition(position, affinity) {
- return this.model.normalizePosition(position, affinity);
- }
- getLineIndentColumn(lineNumber) {
- return this.model.getLineIndentColumn(lineNumber);
- }
- getInjectedTextAt(position) {
- // Identity lines collection does not support injected text.
- return null;
- }
- }
- class IdentityCoordinatesConverter {
- constructor(lines) {
- this._lines = lines;
- }
- _validPosition(pos) {
- return this._lines.model.validatePosition(pos);
- }
- _validRange(range) {
- return this._lines.model.validateRange(range);
- }
- // View -> Model conversion and related methods
- convertViewPositionToModelPosition(viewPosition) {
- return this._validPosition(viewPosition);
- }
- convertViewRangeToModelRange(viewRange) {
- return this._validRange(viewRange);
- }
- validateViewPosition(_viewPosition, expectedModelPosition) {
- return this._validPosition(expectedModelPosition);
- }
- validateViewRange(_viewRange, expectedModelRange) {
- return this._validRange(expectedModelRange);
- }
- // Model -> View conversion and related methods
- convertModelPositionToViewPosition(modelPosition) {
- return this._validPosition(modelPosition);
- }
- convertModelRangeToViewRange(modelRange) {
- return this._validRange(modelRange);
- }
- modelPositionIsVisible(modelPosition) {
- const lineCount = this._lines.model.getLineCount();
- if (modelPosition.lineNumber < 1 || modelPosition.lineNumber > lineCount) {
- // invalid arguments
- return false;
- }
- return true;
- }
- getModelLineViewLineCount(modelLineNumber) {
- return 1;
- }
- getViewLineNumberOfModelPosition(modelLineNumber, modelColumn) {
- return modelLineNumber;
- }
- }
|