Path: blob/main/src/vs/editor/common/viewModel/viewModelLines.ts
3294 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import * as arrays from '../../../base/common/arrays.js';6import { IDisposable } from '../../../base/common/lifecycle.js';7import { WrappingIndent } from '../config/editorOptions.js';8import { FontInfo } from '../config/fontInfo.js';9import { IPosition, Position } from '../core/position.js';10import { Range } from '../core/range.js';11import { IModelDecoration, IModelDeltaDecoration, ITextModel, PositionAffinity } from '../model.js';12import { IActiveIndentGuideInfo, BracketGuideOptions, IndentGuide, IndentGuideHorizontalLine } from '../textModelGuides.js';13import { ModelDecorationOptions } from '../model/textModel.js';14import { LineInjectedText } from '../textModelEvents.js';15import * as viewEvents from '../viewEvents.js';16import { createModelLineProjection, IModelLineProjection } from './modelLineProjection.js';17import { ILineBreaksComputer, ModelLineProjectionData, InjectedText, ILineBreaksComputerFactory } from '../modelLineProjectionData.js';18import { ConstantTimePrefixSumComputer } from '../model/prefixSumComputer.js';19import { ViewLineData } from '../viewModel.js';20import { ICoordinatesConverter, IdentityCoordinatesConverter } from '../coordinatesConverter.js';2122export interface IViewModelLines extends IDisposable {23createCoordinatesConverter(): ICoordinatesConverter;2425setWrappingSettings(fontInfo: FontInfo, wrappingStrategy: 'simple' | 'advanced', wrappingColumn: number, wrappingIndent: WrappingIndent, wordBreak: 'normal' | 'keepAll'): boolean;26setTabSize(newTabSize: number): boolean;27getHiddenAreas(): Range[];28setHiddenAreas(_ranges: readonly Range[]): boolean;2930createLineBreaksComputer(): ILineBreaksComputer;31onModelFlushed(): void;32onModelLinesDeleted(versionId: number | null, fromLineNumber: number, toLineNumber: number): viewEvents.ViewLinesDeletedEvent | null;33onModelLinesInserted(versionId: number | null, fromLineNumber: number, toLineNumber: number, lineBreaks: (ModelLineProjectionData | null)[]): viewEvents.ViewLinesInsertedEvent | null;34onModelLineChanged(versionId: number | null, lineNumber: number, lineBreakData: ModelLineProjectionData | null): [boolean, viewEvents.ViewLinesChangedEvent | null, viewEvents.ViewLinesInsertedEvent | null, viewEvents.ViewLinesDeletedEvent | null];35acceptVersionId(versionId: number): void;3637getViewLineCount(): number;38getActiveIndentGuide(viewLineNumber: number, minLineNumber: number, maxLineNumber: number): IActiveIndentGuideInfo;39getViewLinesIndentGuides(viewStartLineNumber: number, viewEndLineNumber: number): number[];40getViewLinesBracketGuides(startLineNumber: number, endLineNumber: number, activePosition: IPosition | null, options: BracketGuideOptions): IndentGuide[][];41getViewLineContent(viewLineNumber: number): string;42getViewLineLength(viewLineNumber: number): number;43getViewLineMinColumn(viewLineNumber: number): number;44getViewLineMaxColumn(viewLineNumber: number): number;45getViewLineData(viewLineNumber: number): ViewLineData;46getViewLinesData(viewStartLineNumber: number, viewEndLineNumber: number, needed: boolean[]): Array<ViewLineData | null>;4748getDecorationsInRange(range: Range, ownerId: number, filterOutValidation: boolean, filterFontDecorations: boolean, onlyMinimapDecorations: boolean, onlyMarginDecorations: boolean): IModelDecoration[];4950getInjectedTextAt(viewPosition: Position): InjectedText | null;5152normalizePosition(position: Position, affinity: PositionAffinity): Position;53/**54* Gets the column at which indentation stops at a given line.55* @internal56*/57getLineIndentColumn(lineNumber: number): number;58}5960export class ViewModelLinesFromProjectedModel implements IViewModelLines {61private readonly _editorId: number;62private readonly model: ITextModel;63private _validModelVersionId: number;6465private readonly _domLineBreaksComputerFactory: ILineBreaksComputerFactory;66private readonly _monospaceLineBreaksComputerFactory: ILineBreaksComputerFactory;6768private fontInfo: FontInfo;69private tabSize: number;70private wrappingColumn: number;71private wrappingIndent: WrappingIndent;72private wordBreak: 'normal' | 'keepAll';73private wrappingStrategy: 'simple' | 'advanced';74private wrapOnEscapedLineFeeds: boolean;7576private modelLineProjections!: IModelLineProjection[];7778/**79* Reflects the sum of the line counts of all projected model lines.80*/81private projectedModelLineLineCounts!: ConstantTimePrefixSumComputer;8283private hiddenAreasDecorationIds!: string[];8485constructor(86editorId: number,87model: ITextModel,88domLineBreaksComputerFactory: ILineBreaksComputerFactory,89monospaceLineBreaksComputerFactory: ILineBreaksComputerFactory,90fontInfo: FontInfo,91tabSize: number,92wrappingStrategy: 'simple' | 'advanced',93wrappingColumn: number,94wrappingIndent: WrappingIndent,95wordBreak: 'normal' | 'keepAll',96wrapOnEscapedLineFeeds: boolean97) {98this._editorId = editorId;99this.model = model;100this._validModelVersionId = -1;101this._domLineBreaksComputerFactory = domLineBreaksComputerFactory;102this._monospaceLineBreaksComputerFactory = monospaceLineBreaksComputerFactory;103this.fontInfo = fontInfo;104this.tabSize = tabSize;105this.wrappingStrategy = wrappingStrategy;106this.wrappingColumn = wrappingColumn;107this.wrappingIndent = wrappingIndent;108this.wordBreak = wordBreak;109this.wrapOnEscapedLineFeeds = wrapOnEscapedLineFeeds;110111this._constructLines(/*resetHiddenAreas*/true, null);112}113114public dispose(): void {115this.hiddenAreasDecorationIds = this.model.deltaDecorations(this.hiddenAreasDecorationIds, []);116}117118public createCoordinatesConverter(): ICoordinatesConverter {119return new CoordinatesConverter(this);120}121122private _constructLines(resetHiddenAreas: boolean, previousLineBreaks: ((ModelLineProjectionData | null)[]) | null): void {123this.modelLineProjections = [];124125if (resetHiddenAreas) {126this.hiddenAreasDecorationIds = this.model.deltaDecorations(this.hiddenAreasDecorationIds, []);127}128129const linesContent = this.model.getLinesContent();130const injectedTextDecorations = this.model.getInjectedTextDecorations(this._editorId);131const lineCount = linesContent.length;132const lineBreaksComputer = this.createLineBreaksComputer();133134const injectedTextQueue = new arrays.ArrayQueue(LineInjectedText.fromDecorations(injectedTextDecorations));135for (let i = 0; i < lineCount; i++) {136const lineInjectedText = injectedTextQueue.takeWhile(t => t.lineNumber === i + 1);137lineBreaksComputer.addRequest(linesContent[i], lineInjectedText, previousLineBreaks ? previousLineBreaks[i] : null);138}139const linesBreaks = lineBreaksComputer.finalize();140141const values: number[] = [];142143const hiddenAreas = this.hiddenAreasDecorationIds.map((areaId) => this.model.getDecorationRange(areaId)!).sort(Range.compareRangesUsingStarts);144let hiddenAreaStart = 1, hiddenAreaEnd = 0;145let hiddenAreaIdx = -1;146let nextLineNumberToUpdateHiddenArea = (hiddenAreaIdx + 1 < hiddenAreas.length) ? hiddenAreaEnd + 1 : lineCount + 2;147148for (let i = 0; i < lineCount; i++) {149const lineNumber = i + 1;150151if (lineNumber === nextLineNumberToUpdateHiddenArea) {152hiddenAreaIdx++;153hiddenAreaStart = hiddenAreas[hiddenAreaIdx]!.startLineNumber;154hiddenAreaEnd = hiddenAreas[hiddenAreaIdx]!.endLineNumber;155nextLineNumberToUpdateHiddenArea = (hiddenAreaIdx + 1 < hiddenAreas.length) ? hiddenAreaEnd + 1 : lineCount + 2;156}157158const isInHiddenArea = (lineNumber >= hiddenAreaStart && lineNumber <= hiddenAreaEnd);159const line = createModelLineProjection(linesBreaks[i], !isInHiddenArea);160values[i] = line.getViewLineCount();161this.modelLineProjections[i] = line;162}163164this._validModelVersionId = this.model.getVersionId();165166this.projectedModelLineLineCounts = new ConstantTimePrefixSumComputer(values);167}168169public getHiddenAreas(): Range[] {170return this.hiddenAreasDecorationIds.map(171(decId) => this.model.getDecorationRange(decId)!172);173}174175public setHiddenAreas(_ranges: Range[]): boolean {176const validatedRanges = _ranges.map(r => this.model.validateRange(r));177const newRanges = normalizeLineRanges(validatedRanges);178179// TODO@Martin: Please stop calling this method on each model change!180181// This checks if there really was a change182const oldRanges = this.hiddenAreasDecorationIds.map((areaId) => this.model.getDecorationRange(areaId)!).sort(Range.compareRangesUsingStarts);183if (newRanges.length === oldRanges.length) {184let hasDifference = false;185for (let i = 0; i < newRanges.length; i++) {186if (!newRanges[i].equalsRange(oldRanges[i])) {187hasDifference = true;188break;189}190}191if (!hasDifference) {192return false;193}194}195196const newDecorations = newRanges.map<IModelDeltaDecoration>(197(r) =>198({199range: r,200options: ModelDecorationOptions.EMPTY,201})202);203204this.hiddenAreasDecorationIds = this.model.deltaDecorations(this.hiddenAreasDecorationIds, newDecorations);205206const hiddenAreas = newRanges;207let hiddenAreaStart = 1, hiddenAreaEnd = 0;208let hiddenAreaIdx = -1;209let nextLineNumberToUpdateHiddenArea = (hiddenAreaIdx + 1 < hiddenAreas.length) ? hiddenAreaEnd + 1 : this.modelLineProjections.length + 2;210211let hasVisibleLine = false;212for (let i = 0; i < this.modelLineProjections.length; i++) {213const lineNumber = i + 1;214215if (lineNumber === nextLineNumberToUpdateHiddenArea) {216hiddenAreaIdx++;217hiddenAreaStart = hiddenAreas[hiddenAreaIdx].startLineNumber;218hiddenAreaEnd = hiddenAreas[hiddenAreaIdx].endLineNumber;219nextLineNumberToUpdateHiddenArea = (hiddenAreaIdx + 1 < hiddenAreas.length) ? hiddenAreaEnd + 1 : this.modelLineProjections.length + 2;220}221222let lineChanged = false;223if (lineNumber >= hiddenAreaStart && lineNumber <= hiddenAreaEnd) {224// Line should be hidden225if (this.modelLineProjections[i].isVisible()) {226this.modelLineProjections[i] = this.modelLineProjections[i].setVisible(false);227lineChanged = true;228}229} else {230hasVisibleLine = true;231// Line should be visible232if (!this.modelLineProjections[i].isVisible()) {233this.modelLineProjections[i] = this.modelLineProjections[i].setVisible(true);234lineChanged = true;235}236}237if (lineChanged) {238const newOutputLineCount = this.modelLineProjections[i].getViewLineCount();239this.projectedModelLineLineCounts.setValue(i, newOutputLineCount);240}241}242243if (!hasVisibleLine) {244// Cannot have everything be hidden => reveal everything!245this.setHiddenAreas([]);246}247248return true;249}250251public modelPositionIsVisible(modelLineNumber: number, _modelColumn: number): boolean {252if (modelLineNumber < 1 || modelLineNumber > this.modelLineProjections.length) {253// invalid arguments254return false;255}256return this.modelLineProjections[modelLineNumber - 1].isVisible();257}258259public getModelLineViewLineCount(modelLineNumber: number): number {260if (modelLineNumber < 1 || modelLineNumber > this.modelLineProjections.length) {261// invalid arguments262return 1;263}264return this.modelLineProjections[modelLineNumber - 1].getViewLineCount();265}266267public setTabSize(newTabSize: number): boolean {268if (this.tabSize === newTabSize) {269return false;270}271this.tabSize = newTabSize;272273this._constructLines(/*resetHiddenAreas*/false, null);274275return true;276}277278public setWrappingSettings(fontInfo: FontInfo, wrappingStrategy: 'simple' | 'advanced', wrappingColumn: number, wrappingIndent: WrappingIndent, wordBreak: 'normal' | 'keepAll'): boolean {279const equalFontInfo = this.fontInfo.equals(fontInfo);280const equalWrappingStrategy = (this.wrappingStrategy === wrappingStrategy);281const equalWrappingColumn = (this.wrappingColumn === wrappingColumn);282const equalWrappingIndent = (this.wrappingIndent === wrappingIndent);283const equalWordBreak = (this.wordBreak === wordBreak);284if (equalFontInfo && equalWrappingStrategy && equalWrappingColumn && equalWrappingIndent && equalWordBreak) {285return false;286}287288const onlyWrappingColumnChanged = (equalFontInfo && equalWrappingStrategy && !equalWrappingColumn && equalWrappingIndent && equalWordBreak);289290this.fontInfo = fontInfo;291this.wrappingStrategy = wrappingStrategy;292this.wrappingColumn = wrappingColumn;293this.wrappingIndent = wrappingIndent;294this.wordBreak = wordBreak;295296let previousLineBreaks: ((ModelLineProjectionData | null)[]) | null = null;297if (onlyWrappingColumnChanged) {298previousLineBreaks = [];299for (let i = 0, len = this.modelLineProjections.length; i < len; i++) {300previousLineBreaks[i] = this.modelLineProjections[i].getProjectionData();301}302}303304this._constructLines(/*resetHiddenAreas*/false, previousLineBreaks);305306return true;307}308309public createLineBreaksComputer(): ILineBreaksComputer {310const lineBreaksComputerFactory = (311this.wrappingStrategy === 'advanced'312? this._domLineBreaksComputerFactory313: this._monospaceLineBreaksComputerFactory314);315return lineBreaksComputerFactory.createLineBreaksComputer(this.fontInfo, this.tabSize, this.wrappingColumn, this.wrappingIndent, this.wordBreak, this.wrapOnEscapedLineFeeds);316}317318public onModelFlushed(): void {319this._constructLines(/*resetHiddenAreas*/true, null);320}321322public onModelLinesDeleted(versionId: number | null, fromLineNumber: number, toLineNumber: number): viewEvents.ViewLinesDeletedEvent | null {323if (!versionId || versionId <= this._validModelVersionId) {324// Here we check for versionId in case the lines were reconstructed in the meantime.325// We don't want to apply stale change events on top of a newer read model state.326return null;327}328329const outputFromLineNumber = (fromLineNumber === 1 ? 1 : this.projectedModelLineLineCounts.getPrefixSum(fromLineNumber - 1) + 1);330const outputToLineNumber = this.projectedModelLineLineCounts.getPrefixSum(toLineNumber);331332this.modelLineProjections.splice(fromLineNumber - 1, toLineNumber - fromLineNumber + 1);333this.projectedModelLineLineCounts.removeValues(fromLineNumber - 1, toLineNumber - fromLineNumber + 1);334335return new viewEvents.ViewLinesDeletedEvent(outputFromLineNumber, outputToLineNumber);336}337338public onModelLinesInserted(versionId: number | null, fromLineNumber: number, _toLineNumber: number, lineBreaks: (ModelLineProjectionData | null)[]): viewEvents.ViewLinesInsertedEvent | null {339if (!versionId || versionId <= this._validModelVersionId) {340// Here we check for versionId in case the lines were reconstructed in the meantime.341// We don't want to apply stale change events on top of a newer read model state.342return null;343}344345// cannot use this.getHiddenAreas() because those decorations have already seen the effect of this model change346const isInHiddenArea = (fromLineNumber > 2 && !this.modelLineProjections[fromLineNumber - 2].isVisible());347348const outputFromLineNumber = (fromLineNumber === 1 ? 1 : this.projectedModelLineLineCounts.getPrefixSum(fromLineNumber - 1) + 1);349350let totalOutputLineCount = 0;351const insertLines: IModelLineProjection[] = [];352const insertPrefixSumValues: number[] = [];353354for (let i = 0, len = lineBreaks.length; i < len; i++) {355const line = createModelLineProjection(lineBreaks[i], !isInHiddenArea);356insertLines.push(line);357358const outputLineCount = line.getViewLineCount();359totalOutputLineCount += outputLineCount;360insertPrefixSumValues[i] = outputLineCount;361}362363// TODO@Alex: use arrays.arrayInsert364this.modelLineProjections =365this.modelLineProjections.slice(0, fromLineNumber - 1)366.concat(insertLines)367.concat(this.modelLineProjections.slice(fromLineNumber - 1));368369this.projectedModelLineLineCounts.insertValues(fromLineNumber - 1, insertPrefixSumValues);370371return new viewEvents.ViewLinesInsertedEvent(outputFromLineNumber, outputFromLineNumber + totalOutputLineCount - 1);372}373374public onModelLineChanged(versionId: number | null, lineNumber: number, lineBreakData: ModelLineProjectionData | null): [boolean, viewEvents.ViewLinesChangedEvent | null, viewEvents.ViewLinesInsertedEvent | null, viewEvents.ViewLinesDeletedEvent | null] {375if (versionId !== null && versionId <= this._validModelVersionId) {376// Here we check for versionId in case the lines were reconstructed in the meantime.377// We don't want to apply stale change events on top of a newer read model state.378return [false, null, null, null];379}380381const lineIndex = lineNumber - 1;382383const oldOutputLineCount = this.modelLineProjections[lineIndex].getViewLineCount();384const isVisible = this.modelLineProjections[lineIndex].isVisible();385const line = createModelLineProjection(lineBreakData, isVisible);386this.modelLineProjections[lineIndex] = line;387const newOutputLineCount = this.modelLineProjections[lineIndex].getViewLineCount();388389let lineMappingChanged = false;390let changeFrom = 0;391let changeTo = -1;392let insertFrom = 0;393let insertTo = -1;394let deleteFrom = 0;395let deleteTo = -1;396397if (oldOutputLineCount > newOutputLineCount) {398changeFrom = this.projectedModelLineLineCounts.getPrefixSum(lineNumber - 1) + 1;399changeTo = changeFrom + newOutputLineCount - 1;400deleteFrom = changeTo + 1;401deleteTo = deleteFrom + (oldOutputLineCount - newOutputLineCount) - 1;402lineMappingChanged = true;403} else if (oldOutputLineCount < newOutputLineCount) {404changeFrom = this.projectedModelLineLineCounts.getPrefixSum(lineNumber - 1) + 1;405changeTo = changeFrom + oldOutputLineCount - 1;406insertFrom = changeTo + 1;407insertTo = insertFrom + (newOutputLineCount - oldOutputLineCount) - 1;408lineMappingChanged = true;409} else {410changeFrom = this.projectedModelLineLineCounts.getPrefixSum(lineNumber - 1) + 1;411changeTo = changeFrom + newOutputLineCount - 1;412}413414this.projectedModelLineLineCounts.setValue(lineIndex, newOutputLineCount);415416const viewLinesChangedEvent = (changeFrom <= changeTo ? new viewEvents.ViewLinesChangedEvent(changeFrom, changeTo - changeFrom + 1) : null);417const viewLinesInsertedEvent = (insertFrom <= insertTo ? new viewEvents.ViewLinesInsertedEvent(insertFrom, insertTo) : null);418const viewLinesDeletedEvent = (deleteFrom <= deleteTo ? new viewEvents.ViewLinesDeletedEvent(deleteFrom, deleteTo) : null);419420return [lineMappingChanged, viewLinesChangedEvent, viewLinesInsertedEvent, viewLinesDeletedEvent];421}422423public acceptVersionId(versionId: number): void {424this._validModelVersionId = versionId;425if (this.modelLineProjections.length === 1 && !this.modelLineProjections[0].isVisible()) {426// At least one line must be visible => reset hidden areas427this.setHiddenAreas([]);428}429}430431public getViewLineCount(): number {432return this.projectedModelLineLineCounts.getTotalSum();433}434435private _toValidViewLineNumber(viewLineNumber: number): number {436if (viewLineNumber < 1) {437return 1;438}439const viewLineCount = this.getViewLineCount();440if (viewLineNumber > viewLineCount) {441return viewLineCount;442}443return viewLineNumber | 0;444}445446public getActiveIndentGuide(viewLineNumber: number, minLineNumber: number, maxLineNumber: number): IActiveIndentGuideInfo {447viewLineNumber = this._toValidViewLineNumber(viewLineNumber);448minLineNumber = this._toValidViewLineNumber(minLineNumber);449maxLineNumber = this._toValidViewLineNumber(maxLineNumber);450451const modelPosition = this.convertViewPositionToModelPosition(viewLineNumber, this.getViewLineMinColumn(viewLineNumber));452const modelMinPosition = this.convertViewPositionToModelPosition(minLineNumber, this.getViewLineMinColumn(minLineNumber));453const modelMaxPosition = this.convertViewPositionToModelPosition(maxLineNumber, this.getViewLineMinColumn(maxLineNumber));454const result = this.model.guides.getActiveIndentGuide(modelPosition.lineNumber, modelMinPosition.lineNumber, modelMaxPosition.lineNumber);455456const viewStartPosition = this.convertModelPositionToViewPosition(result.startLineNumber, 1);457const viewEndPosition = this.convertModelPositionToViewPosition(result.endLineNumber, this.model.getLineMaxColumn(result.endLineNumber));458return {459startLineNumber: viewStartPosition.lineNumber,460endLineNumber: viewEndPosition.lineNumber,461indent: result.indent462};463}464465// #region ViewLineInfo466467private getViewLineInfo(viewLineNumber: number): ViewLineInfo {468viewLineNumber = this._toValidViewLineNumber(viewLineNumber);469const r = this.projectedModelLineLineCounts.getIndexOf(viewLineNumber - 1);470const lineIndex = r.index;471const remainder = r.remainder;472return new ViewLineInfo(lineIndex + 1, remainder);473}474475private getMinColumnOfViewLine(viewLineInfo: ViewLineInfo): number {476return this.modelLineProjections[viewLineInfo.modelLineNumber - 1].getViewLineMinColumn(477this.model,478viewLineInfo.modelLineNumber,479viewLineInfo.modelLineWrappedLineIdx480);481}482483private getMaxColumnOfViewLine(viewLineInfo: ViewLineInfo): number {484return this.modelLineProjections[viewLineInfo.modelLineNumber - 1].getViewLineMaxColumn(485this.model,486viewLineInfo.modelLineNumber,487viewLineInfo.modelLineWrappedLineIdx488);489}490491private getModelStartPositionOfViewLine(viewLineInfo: ViewLineInfo): Position {492const line = this.modelLineProjections[viewLineInfo.modelLineNumber - 1];493const minViewColumn = line.getViewLineMinColumn(494this.model,495viewLineInfo.modelLineNumber,496viewLineInfo.modelLineWrappedLineIdx497);498const column = line.getModelColumnOfViewPosition(499viewLineInfo.modelLineWrappedLineIdx,500minViewColumn501);502return new Position(viewLineInfo.modelLineNumber, column);503}504505private getModelEndPositionOfViewLine(viewLineInfo: ViewLineInfo): Position {506const line = this.modelLineProjections[viewLineInfo.modelLineNumber - 1];507const maxViewColumn = line.getViewLineMaxColumn(508this.model,509viewLineInfo.modelLineNumber,510viewLineInfo.modelLineWrappedLineIdx511);512const column = line.getModelColumnOfViewPosition(513viewLineInfo.modelLineWrappedLineIdx,514maxViewColumn515);516return new Position(viewLineInfo.modelLineNumber, column);517}518519private getViewLineInfosGroupedByModelRanges(viewStartLineNumber: number, viewEndLineNumber: number): ViewLineInfoGroupedByModelRange[] {520const startViewLine = this.getViewLineInfo(viewStartLineNumber);521const endViewLine = this.getViewLineInfo(viewEndLineNumber);522523const result = new Array<ViewLineInfoGroupedByModelRange>();524let lastVisibleModelPos: Position | null = this.getModelStartPositionOfViewLine(startViewLine);525let viewLines = new Array<ViewLineInfo>();526527for (let curModelLine = startViewLine.modelLineNumber; curModelLine <= endViewLine.modelLineNumber; curModelLine++) {528const line = this.modelLineProjections[curModelLine - 1];529530if (line.isVisible()) {531const startOffset =532curModelLine === startViewLine.modelLineNumber533? startViewLine.modelLineWrappedLineIdx534: 0;535536const endOffset =537curModelLine === endViewLine.modelLineNumber538? endViewLine.modelLineWrappedLineIdx + 1539: line.getViewLineCount();540541for (let i = startOffset; i < endOffset; i++) {542viewLines.push(new ViewLineInfo(curModelLine, i));543}544}545546if (!line.isVisible() && lastVisibleModelPos) {547const lastVisibleModelPos2 = new Position(curModelLine - 1, this.model.getLineMaxColumn(curModelLine - 1) + 1);548549const modelRange = Range.fromPositions(lastVisibleModelPos, lastVisibleModelPos2);550result.push(new ViewLineInfoGroupedByModelRange(modelRange, viewLines));551viewLines = [];552553lastVisibleModelPos = null;554} else if (line.isVisible() && !lastVisibleModelPos) {555lastVisibleModelPos = new Position(curModelLine, 1);556}557}558559if (lastVisibleModelPos) {560const modelRange = Range.fromPositions(lastVisibleModelPos, this.getModelEndPositionOfViewLine(endViewLine));561result.push(new ViewLineInfoGroupedByModelRange(modelRange, viewLines));562}563564return result;565}566567// #endregion568569public getViewLinesBracketGuides(viewStartLineNumber: number, viewEndLineNumber: number, activeViewPosition: IPosition | null, options: BracketGuideOptions): IndentGuide[][] {570const modelActivePosition = activeViewPosition ? this.convertViewPositionToModelPosition(activeViewPosition.lineNumber, activeViewPosition.column) : null;571const resultPerViewLine: IndentGuide[][] = [];572573for (const group of this.getViewLineInfosGroupedByModelRanges(viewStartLineNumber, viewEndLineNumber)) {574const modelRangeStartLineNumber = group.modelRange.startLineNumber;575576const bracketGuidesPerModelLine = this.model.guides.getLinesBracketGuides(577modelRangeStartLineNumber,578group.modelRange.endLineNumber,579modelActivePosition,580options581);582583for (const viewLineInfo of group.viewLines) {584585const bracketGuides = bracketGuidesPerModelLine[viewLineInfo.modelLineNumber - modelRangeStartLineNumber];586587// visibleColumns stay as they are (this is a bug and needs to be fixed, but it is not a regression)588// model-columns must be converted to view-model columns.589const result = bracketGuides.map(g => {590if (g.forWrappedLinesAfterColumn !== -1) {591const p = this.modelLineProjections[viewLineInfo.modelLineNumber - 1].getViewPositionOfModelPosition(0, g.forWrappedLinesAfterColumn);592if (p.lineNumber >= viewLineInfo.modelLineWrappedLineIdx) {593return undefined;594}595}596597if (g.forWrappedLinesBeforeOrAtColumn !== -1) {598const p = this.modelLineProjections[viewLineInfo.modelLineNumber - 1].getViewPositionOfModelPosition(0, g.forWrappedLinesBeforeOrAtColumn);599if (p.lineNumber < viewLineInfo.modelLineWrappedLineIdx) {600return undefined;601}602}603604if (!g.horizontalLine) {605return g;606}607608let column = -1;609if (g.column !== -1) {610const p = this.modelLineProjections[viewLineInfo.modelLineNumber - 1].getViewPositionOfModelPosition(0, g.column);611if (p.lineNumber === viewLineInfo.modelLineWrappedLineIdx) {612column = p.column;613} else if (p.lineNumber < viewLineInfo.modelLineWrappedLineIdx) {614column = this.getMinColumnOfViewLine(viewLineInfo);615} else if (p.lineNumber > viewLineInfo.modelLineWrappedLineIdx) {616return undefined;617}618}619620const viewPosition = this.convertModelPositionToViewPosition(viewLineInfo.modelLineNumber, g.horizontalLine.endColumn);621const p = this.modelLineProjections[viewLineInfo.modelLineNumber - 1].getViewPositionOfModelPosition(0, g.horizontalLine.endColumn);622if (p.lineNumber === viewLineInfo.modelLineWrappedLineIdx) {623return new IndentGuide(g.visibleColumn, column, g.className,624new IndentGuideHorizontalLine(g.horizontalLine.top,625viewPosition.column),626- 1,627-1,628);629} else if (p.lineNumber < viewLineInfo.modelLineWrappedLineIdx) {630return undefined;631} else {632if (g.visibleColumn !== -1) {633// Don't repeat horizontal lines that use visibleColumn for unrelated lines.634return undefined;635}636return new IndentGuide(g.visibleColumn, column, g.className,637new IndentGuideHorizontalLine(g.horizontalLine.top,638this.getMaxColumnOfViewLine(viewLineInfo)639),640-1,641-1,642);643}644});645resultPerViewLine.push(result.filter((r): r is IndentGuide => !!r));646647}648}649650return resultPerViewLine;651}652653public getViewLinesIndentGuides(viewStartLineNumber: number, viewEndLineNumber: number): number[] {654// TODO: Use the same code as in `getViewLinesBracketGuides`.655// Future TODO: Merge with `getViewLinesBracketGuides`.656// However, this requires more refactoring of indent guides.657viewStartLineNumber = this._toValidViewLineNumber(viewStartLineNumber);658viewEndLineNumber = this._toValidViewLineNumber(viewEndLineNumber);659660const modelStart = this.convertViewPositionToModelPosition(viewStartLineNumber, this.getViewLineMinColumn(viewStartLineNumber));661const modelEnd = this.convertViewPositionToModelPosition(viewEndLineNumber, this.getViewLineMaxColumn(viewEndLineNumber));662663let result: number[] = [];664const resultRepeatCount: number[] = [];665const resultRepeatOption: IndentGuideRepeatOption[] = [];666const modelStartLineIndex = modelStart.lineNumber - 1;667const modelEndLineIndex = modelEnd.lineNumber - 1;668669let reqStart: Position | null = null;670for (let modelLineIndex = modelStartLineIndex; modelLineIndex <= modelEndLineIndex; modelLineIndex++) {671const line = this.modelLineProjections[modelLineIndex];672if (line.isVisible()) {673const viewLineStartIndex = line.getViewLineNumberOfModelPosition(0, modelLineIndex === modelStartLineIndex ? modelStart.column : 1);674const viewLineEndIndex = line.getViewLineNumberOfModelPosition(0, this.model.getLineMaxColumn(modelLineIndex + 1));675const count = viewLineEndIndex - viewLineStartIndex + 1;676let option = IndentGuideRepeatOption.BlockNone;677if (count > 1 && line.getViewLineMinColumn(this.model, modelLineIndex + 1, viewLineEndIndex) === 1) {678// wrapped lines should block indent guides679option = (viewLineStartIndex === 0 ? IndentGuideRepeatOption.BlockSubsequent : IndentGuideRepeatOption.BlockAll);680}681resultRepeatCount.push(count);682resultRepeatOption.push(option);683// merge into previous request684if (reqStart === null) {685reqStart = new Position(modelLineIndex + 1, 0);686}687} else {688// hit invisible line => flush request689if (reqStart !== null) {690result = result.concat(this.model.guides.getLinesIndentGuides(reqStart.lineNumber, modelLineIndex));691reqStart = null;692}693}694}695696if (reqStart !== null) {697result = result.concat(this.model.guides.getLinesIndentGuides(reqStart.lineNumber, modelEnd.lineNumber));698reqStart = null;699}700701const viewLineCount = viewEndLineNumber - viewStartLineNumber + 1;702const viewIndents = new Array<number>(viewLineCount);703let currIndex = 0;704for (let i = 0, len = result.length; i < len; i++) {705let value = result[i];706const count = Math.min(viewLineCount - currIndex, resultRepeatCount[i]);707const option = resultRepeatOption[i];708let blockAtIndex: number;709if (option === IndentGuideRepeatOption.BlockAll) {710blockAtIndex = 0;711} else if (option === IndentGuideRepeatOption.BlockSubsequent) {712blockAtIndex = 1;713} else {714blockAtIndex = count;715}716for (let j = 0; j < count; j++) {717if (j === blockAtIndex) {718value = 0;719}720viewIndents[currIndex++] = value;721}722}723return viewIndents;724}725726public getViewLineContent(viewLineNumber: number): string {727const info = this.getViewLineInfo(viewLineNumber);728return this.modelLineProjections[info.modelLineNumber - 1].getViewLineContent(this.model, info.modelLineNumber, info.modelLineWrappedLineIdx);729}730731public getViewLineLength(viewLineNumber: number): number {732const info = this.getViewLineInfo(viewLineNumber);733return this.modelLineProjections[info.modelLineNumber - 1].getViewLineLength(this.model, info.modelLineNumber, info.modelLineWrappedLineIdx);734}735736public getViewLineMinColumn(viewLineNumber: number): number {737const info = this.getViewLineInfo(viewLineNumber);738return this.modelLineProjections[info.modelLineNumber - 1].getViewLineMinColumn(this.model, info.modelLineNumber, info.modelLineWrappedLineIdx);739}740741public getViewLineMaxColumn(viewLineNumber: number): number {742const info = this.getViewLineInfo(viewLineNumber);743return this.modelLineProjections[info.modelLineNumber - 1].getViewLineMaxColumn(this.model, info.modelLineNumber, info.modelLineWrappedLineIdx);744}745746public getViewLineData(viewLineNumber: number): ViewLineData {747const info = this.getViewLineInfo(viewLineNumber);748return this.modelLineProjections[info.modelLineNumber - 1].getViewLineData(this.model, info.modelLineNumber, info.modelLineWrappedLineIdx);749}750751public getViewLinesData(viewStartLineNumber: number, viewEndLineNumber: number, needed: boolean[]): ViewLineData[] {752753viewStartLineNumber = this._toValidViewLineNumber(viewStartLineNumber);754viewEndLineNumber = this._toValidViewLineNumber(viewEndLineNumber);755756const start = this.projectedModelLineLineCounts.getIndexOf(viewStartLineNumber - 1);757let viewLineNumber = viewStartLineNumber;758const startModelLineIndex = start.index;759const startRemainder = start.remainder;760761const result: ViewLineData[] = [];762for (let modelLineIndex = startModelLineIndex, len = this.model.getLineCount(); modelLineIndex < len; modelLineIndex++) {763const line = this.modelLineProjections[modelLineIndex];764if (!line.isVisible()) {765continue;766}767const fromViewLineIndex = (modelLineIndex === startModelLineIndex ? startRemainder : 0);768let remainingViewLineCount = line.getViewLineCount() - fromViewLineIndex;769770let lastLine = false;771if (viewLineNumber + remainingViewLineCount > viewEndLineNumber) {772lastLine = true;773remainingViewLineCount = viewEndLineNumber - viewLineNumber + 1;774}775776line.getViewLinesData(this.model, modelLineIndex + 1, fromViewLineIndex, remainingViewLineCount, viewLineNumber - viewStartLineNumber, needed, result);777778viewLineNumber += remainingViewLineCount;779780if (lastLine) {781break;782}783}784785return result;786}787788public validateViewPosition(viewLineNumber: number, viewColumn: number, expectedModelPosition: Position): Position {789viewLineNumber = this._toValidViewLineNumber(viewLineNumber);790791const r = this.projectedModelLineLineCounts.getIndexOf(viewLineNumber - 1);792const lineIndex = r.index;793const remainder = r.remainder;794795const line = this.modelLineProjections[lineIndex];796797const minColumn = line.getViewLineMinColumn(this.model, lineIndex + 1, remainder);798const maxColumn = line.getViewLineMaxColumn(this.model, lineIndex + 1, remainder);799if (viewColumn < minColumn) {800viewColumn = minColumn;801}802if (viewColumn > maxColumn) {803viewColumn = maxColumn;804}805806const computedModelColumn = line.getModelColumnOfViewPosition(remainder, viewColumn);807const computedModelPosition = this.model.validatePosition(new Position(lineIndex + 1, computedModelColumn));808809if (computedModelPosition.equals(expectedModelPosition)) {810return new Position(viewLineNumber, viewColumn);811}812813return this.convertModelPositionToViewPosition(expectedModelPosition.lineNumber, expectedModelPosition.column);814}815816public validateViewRange(viewRange: Range, expectedModelRange: Range): Range {817const validViewStart = this.validateViewPosition(viewRange.startLineNumber, viewRange.startColumn, expectedModelRange.getStartPosition());818const validViewEnd = this.validateViewPosition(viewRange.endLineNumber, viewRange.endColumn, expectedModelRange.getEndPosition());819return new Range(validViewStart.lineNumber, validViewStart.column, validViewEnd.lineNumber, validViewEnd.column);820}821822public convertViewPositionToModelPosition(viewLineNumber: number, viewColumn: number): Position {823const info = this.getViewLineInfo(viewLineNumber);824825const inputColumn = this.modelLineProjections[info.modelLineNumber - 1].getModelColumnOfViewPosition(info.modelLineWrappedLineIdx, viewColumn);826// console.log('out -> in ' + viewLineNumber + ',' + viewColumn + ' ===> ' + (lineIndex+1) + ',' + inputColumn);827return this.model.validatePosition(new Position(info.modelLineNumber, inputColumn));828}829830public convertViewRangeToModelRange(viewRange: Range): Range {831const start = this.convertViewPositionToModelPosition(viewRange.startLineNumber, viewRange.startColumn);832const end = this.convertViewPositionToModelPosition(viewRange.endLineNumber, viewRange.endColumn);833return new Range(start.lineNumber, start.column, end.lineNumber, end.column);834}835836public convertModelPositionToViewPosition(_modelLineNumber: number, _modelColumn: number, affinity: PositionAffinity = PositionAffinity.None, allowZeroLineNumber: boolean = false, belowHiddenRanges: boolean = false): Position {837838const validPosition = this.model.validatePosition(new Position(_modelLineNumber, _modelColumn));839const inputLineNumber = validPosition.lineNumber;840const inputColumn = validPosition.column;841842let lineIndex = inputLineNumber - 1, lineIndexChanged = false;843if (belowHiddenRanges) {844while (lineIndex < this.modelLineProjections.length && !this.modelLineProjections[lineIndex].isVisible()) {845lineIndex++;846lineIndexChanged = true;847}848} else {849while (lineIndex > 0 && !this.modelLineProjections[lineIndex].isVisible()) {850lineIndex--;851lineIndexChanged = true;852}853}854if (lineIndex === 0 && !this.modelLineProjections[lineIndex].isVisible()) {855// Could not reach a real line856// console.log('in -> out ' + inputLineNumber + ',' + inputColumn + ' ===> ' + 1 + ',' + 1);857// TODO@alexdima@hediet this isn't soo pretty858return new Position(allowZeroLineNumber ? 0 : 1, 1);859}860const deltaLineNumber = 1 + this.projectedModelLineLineCounts.getPrefixSum(lineIndex);861862let r: Position;863if (lineIndexChanged) {864if (belowHiddenRanges) {865r = this.modelLineProjections[lineIndex].getViewPositionOfModelPosition(deltaLineNumber, 1, affinity);866} else {867r = this.modelLineProjections[lineIndex].getViewPositionOfModelPosition(deltaLineNumber, this.model.getLineMaxColumn(lineIndex + 1), affinity);868}869} else {870r = this.modelLineProjections[inputLineNumber - 1].getViewPositionOfModelPosition(deltaLineNumber, inputColumn, affinity);871}872873// console.log('in -> out ' + inputLineNumber + ',' + inputColumn + ' ===> ' + r.lineNumber + ',' + r);874return r;875}876877/**878* @param affinity The affinity in case of an empty range. Has no effect for non-empty ranges.879*/880public convertModelRangeToViewRange(modelRange: Range, affinity: PositionAffinity = PositionAffinity.Left): Range {881if (modelRange.isEmpty()) {882const start = this.convertModelPositionToViewPosition(modelRange.startLineNumber, modelRange.startColumn, affinity);883return Range.fromPositions(start);884} else {885const start = this.convertModelPositionToViewPosition(modelRange.startLineNumber, modelRange.startColumn, PositionAffinity.Right);886const end = this.convertModelPositionToViewPosition(modelRange.endLineNumber, modelRange.endColumn, PositionAffinity.Left);887return new Range(start.lineNumber, start.column, end.lineNumber, end.column);888}889}890891public getViewLineNumberOfModelPosition(modelLineNumber: number, modelColumn: number): number {892let lineIndex = modelLineNumber - 1;893if (this.modelLineProjections[lineIndex].isVisible()) {894// this model line is visible895const deltaLineNumber = 1 + this.projectedModelLineLineCounts.getPrefixSum(lineIndex);896return this.modelLineProjections[lineIndex].getViewLineNumberOfModelPosition(deltaLineNumber, modelColumn);897}898899// this model line is not visible900while (lineIndex > 0 && !this.modelLineProjections[lineIndex].isVisible()) {901lineIndex--;902}903if (lineIndex === 0 && !this.modelLineProjections[lineIndex].isVisible()) {904// Could not reach a real line905return 1;906}907const deltaLineNumber = 1 + this.projectedModelLineLineCounts.getPrefixSum(lineIndex);908return this.modelLineProjections[lineIndex].getViewLineNumberOfModelPosition(deltaLineNumber, this.model.getLineMaxColumn(lineIndex + 1));909}910911public getDecorationsInRange(range: Range, ownerId: number, filterOutValidation: boolean, filterFontDecorations: boolean, onlyMinimapDecorations: boolean, onlyMarginDecorations: boolean): IModelDecoration[] {912const modelStart = this.convertViewPositionToModelPosition(range.startLineNumber, range.startColumn);913const modelEnd = this.convertViewPositionToModelPosition(range.endLineNumber, range.endColumn);914915if (modelEnd.lineNumber - modelStart.lineNumber <= range.endLineNumber - range.startLineNumber) {916// most likely there are no hidden lines => fast path917// fetch decorations from column 1 to cover the case of wrapped lines that have whole line decorations at column 1918return this.model.getDecorationsInRange(new Range(modelStart.lineNumber, 1, modelEnd.lineNumber, modelEnd.column), ownerId, filterOutValidation, filterFontDecorations, onlyMinimapDecorations, onlyMarginDecorations);919}920921let result: IModelDecoration[] = [];922const modelStartLineIndex = modelStart.lineNumber - 1;923const modelEndLineIndex = modelEnd.lineNumber - 1;924925let reqStart: Position | null = null;926for (let modelLineIndex = modelStartLineIndex; modelLineIndex <= modelEndLineIndex; modelLineIndex++) {927const line = this.modelLineProjections[modelLineIndex];928if (line.isVisible()) {929// merge into previous request930if (reqStart === null) {931reqStart = new Position(modelLineIndex + 1, modelLineIndex === modelStartLineIndex ? modelStart.column : 1);932}933} else {934// hit invisible line => flush request935if (reqStart !== null) {936const maxLineColumn = this.model.getLineMaxColumn(modelLineIndex);937result = result.concat(this.model.getDecorationsInRange(new Range(reqStart.lineNumber, reqStart.column, modelLineIndex, maxLineColumn), ownerId, filterOutValidation, filterFontDecorations, onlyMinimapDecorations));938reqStart = null;939}940}941}942943if (reqStart !== null) {944result = result.concat(this.model.getDecorationsInRange(new Range(reqStart.lineNumber, reqStart.column, modelEnd.lineNumber, modelEnd.column), ownerId, filterOutValidation, filterFontDecorations, onlyMinimapDecorations));945reqStart = null;946}947948result.sort((a, b) => {949const res = Range.compareRangesUsingStarts(a.range, b.range);950if (res === 0) {951if (a.id < b.id) {952return -1;953}954if (a.id > b.id) {955return 1;956}957return 0;958}959return res;960});961962// Eliminate duplicate decorations that might have intersected our visible ranges multiple times963const finalResult: IModelDecoration[] = [];964let finalResultLen = 0;965let prevDecId: string | null = null;966for (const dec of result) {967const decId = dec.id;968if (prevDecId === decId) {969// skip970continue;971}972prevDecId = decId;973finalResult[finalResultLen++] = dec;974}975976return finalResult;977}978979public getInjectedTextAt(position: Position): InjectedText | null {980const info = this.getViewLineInfo(position.lineNumber);981return this.modelLineProjections[info.modelLineNumber - 1].getInjectedTextAt(info.modelLineWrappedLineIdx, position.column);982}983984normalizePosition(position: Position, affinity: PositionAffinity): Position {985const info = this.getViewLineInfo(position.lineNumber);986return this.modelLineProjections[info.modelLineNumber - 1].normalizePosition(info.modelLineWrappedLineIdx, position, affinity);987}988989public getLineIndentColumn(lineNumber: number): number {990const info = this.getViewLineInfo(lineNumber);991if (info.modelLineWrappedLineIdx === 0) {992return this.model.getLineIndentColumn(info.modelLineNumber);993}994995// wrapped lines have no indentation.996// We deliberately don't handle the case that indentation is wrapped997// to avoid two view lines reporting indentation for the very same model line.998return 0;999}1000}10011002/**1003* Overlapping unsorted ranges:1004* [ ) [ ) [ )1005* [ ) [ )1006* ->1007* Non overlapping sorted ranges:1008* [ ) [ ) [ )1009*1010* Note: This function only considers line information! Columns are ignored.1011*/1012function normalizeLineRanges(ranges: Range[]): Range[] {1013if (ranges.length === 0) {1014return [];1015}10161017const sortedRanges = ranges.slice();1018sortedRanges.sort(Range.compareRangesUsingStarts);10191020const result: Range[] = [];1021let currentRangeStart = sortedRanges[0].startLineNumber;1022let currentRangeEnd = sortedRanges[0].endLineNumber;10231024for (let i = 1, len = sortedRanges.length; i < len; i++) {1025const range = sortedRanges[i];10261027if (range.startLineNumber > currentRangeEnd + 1) {1028result.push(new Range(currentRangeStart, 1, currentRangeEnd, 1));1029currentRangeStart = range.startLineNumber;1030currentRangeEnd = range.endLineNumber;1031} else if (range.endLineNumber > currentRangeEnd) {1032currentRangeEnd = range.endLineNumber;1033}1034}1035result.push(new Range(currentRangeStart, 1, currentRangeEnd, 1));1036return result;1037}10381039/**1040* Represents a view line. Can be used to efficiently query more information about it.1041*/1042class ViewLineInfo {1043public get isWrappedLineContinuation(): boolean {1044return this.modelLineWrappedLineIdx > 0;1045}10461047constructor(1048public readonly modelLineNumber: number,1049public readonly modelLineWrappedLineIdx: number,1050) { }1051}10521053/**1054* A list of view lines that have a contiguous span in the model.1055*/1056class ViewLineInfoGroupedByModelRange {1057constructor(public readonly modelRange: Range, public readonly viewLines: ViewLineInfo[]) {1058}1059}10601061class CoordinatesConverter implements ICoordinatesConverter {1062private readonly _lines: ViewModelLinesFromProjectedModel;10631064constructor(lines: ViewModelLinesFromProjectedModel) {1065this._lines = lines;1066}10671068// View -> Model conversion and related methods10691070public convertViewPositionToModelPosition(viewPosition: Position): Position {1071return this._lines.convertViewPositionToModelPosition(viewPosition.lineNumber, viewPosition.column);1072}10731074public convertViewRangeToModelRange(viewRange: Range): Range {1075return this._lines.convertViewRangeToModelRange(viewRange);1076}10771078public validateViewPosition(viewPosition: Position, expectedModelPosition: Position): Position {1079return this._lines.validateViewPosition(viewPosition.lineNumber, viewPosition.column, expectedModelPosition);1080}10811082public validateViewRange(viewRange: Range, expectedModelRange: Range): Range {1083return this._lines.validateViewRange(viewRange, expectedModelRange);1084}10851086// Model -> View conversion and related methods10871088public convertModelPositionToViewPosition(modelPosition: Position, affinity?: PositionAffinity, allowZero?: boolean, belowHiddenRanges?: boolean): Position {1089return this._lines.convertModelPositionToViewPosition(modelPosition.lineNumber, modelPosition.column, affinity, allowZero, belowHiddenRanges);1090}10911092public convertModelRangeToViewRange(modelRange: Range, affinity?: PositionAffinity): Range {1093return this._lines.convertModelRangeToViewRange(modelRange, affinity);1094}10951096public modelPositionIsVisible(modelPosition: Position): boolean {1097return this._lines.modelPositionIsVisible(modelPosition.lineNumber, modelPosition.column);1098}10991100public getModelLineViewLineCount(modelLineNumber: number): number {1101return this._lines.getModelLineViewLineCount(modelLineNumber);1102}11031104public getViewLineNumberOfModelPosition(modelLineNumber: number, modelColumn: number): number {1105return this._lines.getViewLineNumberOfModelPosition(modelLineNumber, modelColumn);1106}1107}11081109const enum IndentGuideRepeatOption {1110BlockNone = 0,1111BlockSubsequent = 1,1112BlockAll = 21113}11141115export class ViewModelLinesFromModelAsIs implements IViewModelLines {1116public readonly model: ITextModel;11171118constructor(model: ITextModel) {1119this.model = model;1120}11211122public dispose(): void {1123}11241125public createCoordinatesConverter(): ICoordinatesConverter {1126return new IdentityCoordinatesConverter(this.model);1127}11281129public getHiddenAreas(): Range[] {1130return [];1131}11321133public setHiddenAreas(_ranges: Range[]): boolean {1134return false;1135}11361137public setTabSize(_newTabSize: number): boolean {1138return false;1139}11401141public setWrappingSettings(_fontInfo: FontInfo, _wrappingStrategy: 'simple' | 'advanced', _wrappingColumn: number, _wrappingIndent: WrappingIndent): boolean {1142return false;1143}11441145public createLineBreaksComputer(): ILineBreaksComputer {1146const result: null[] = [];1147return {1148addRequest: (lineText: string, injectedText: LineInjectedText[] | null, previousLineBreakData: ModelLineProjectionData | null) => {1149result.push(null);1150},1151finalize: () => {1152return result;1153}1154};1155}11561157public onModelFlushed(): void {1158}11591160public onModelLinesDeleted(_versionId: number | null, fromLineNumber: number, toLineNumber: number): viewEvents.ViewLinesDeletedEvent | null {1161return new viewEvents.ViewLinesDeletedEvent(fromLineNumber, toLineNumber);1162}11631164public onModelLinesInserted(_versionId: number | null, fromLineNumber: number, toLineNumber: number, lineBreaks: (ModelLineProjectionData | null)[]): viewEvents.ViewLinesInsertedEvent | null {1165return new viewEvents.ViewLinesInsertedEvent(fromLineNumber, toLineNumber);1166}11671168public onModelLineChanged(_versionId: number | null, lineNumber: number, lineBreakData: ModelLineProjectionData | null): [boolean, viewEvents.ViewLinesChangedEvent | null, viewEvents.ViewLinesInsertedEvent | null, viewEvents.ViewLinesDeletedEvent | null] {1169return [false, new viewEvents.ViewLinesChangedEvent(lineNumber, 1), null, null];1170}11711172public acceptVersionId(_versionId: number): void {1173}11741175public getViewLineCount(): number {1176return this.model.getLineCount();1177}11781179public getActiveIndentGuide(viewLineNumber: number, _minLineNumber: number, _maxLineNumber: number): IActiveIndentGuideInfo {1180return {1181startLineNumber: viewLineNumber,1182endLineNumber: viewLineNumber,1183indent: 01184};1185}11861187public getViewLinesBracketGuides(startLineNumber: number, endLineNumber: number, activePosition: IPosition | null): IndentGuide[][] {1188return new Array(endLineNumber - startLineNumber + 1).fill([]);1189}11901191public getViewLinesIndentGuides(viewStartLineNumber: number, viewEndLineNumber: number): number[] {1192const viewLineCount = viewEndLineNumber - viewStartLineNumber + 1;1193const result = new Array<number>(viewLineCount);1194for (let i = 0; i < viewLineCount; i++) {1195result[i] = 0;1196}1197return result;1198}11991200public getViewLineContent(viewLineNumber: number): string {1201return this.model.getLineContent(viewLineNumber);1202}12031204public getViewLineLength(viewLineNumber: number): number {1205return this.model.getLineLength(viewLineNumber);1206}12071208public getViewLineMinColumn(viewLineNumber: number): number {1209return this.model.getLineMinColumn(viewLineNumber);1210}12111212public getViewLineMaxColumn(viewLineNumber: number): number {1213return this.model.getLineMaxColumn(viewLineNumber);1214}12151216public getViewLineData(viewLineNumber: number): ViewLineData {1217const lineTokens = this.model.tokenization.getLineTokens(viewLineNumber);1218const lineContent = lineTokens.getLineContent();1219return new ViewLineData(1220lineContent,1221false,12221,1223lineContent.length + 1,12240,1225lineTokens.inflate(),1226null1227);1228}12291230public getViewLinesData(viewStartLineNumber: number, viewEndLineNumber: number, needed: boolean[]): Array<ViewLineData | null> {1231const lineCount = this.model.getLineCount();1232viewStartLineNumber = Math.min(Math.max(1, viewStartLineNumber), lineCount);1233viewEndLineNumber = Math.min(Math.max(1, viewEndLineNumber), lineCount);12341235const result: Array<ViewLineData | null> = [];1236for (let lineNumber = viewStartLineNumber; lineNumber <= viewEndLineNumber; lineNumber++) {1237const idx = lineNumber - viewStartLineNumber;1238result[idx] = needed[idx] ? this.getViewLineData(lineNumber) : null;1239}12401241return result;1242}12431244public getDecorationsInRange(range: Range, ownerId: number, filterOutValidation: boolean, filterFontDecorations: boolean, onlyMinimapDecorations: boolean, onlyMarginDecorations: boolean): IModelDecoration[] {1245return this.model.getDecorationsInRange(range, ownerId, filterOutValidation, filterFontDecorations, onlyMinimapDecorations, onlyMarginDecorations);1246}12471248normalizePosition(position: Position, affinity: PositionAffinity): Position {1249return this.model.normalizePosition(position, affinity);1250}12511252public getLineIndentColumn(lineNumber: number): number {1253return this.model.getLineIndentColumn(lineNumber);1254}12551256public getInjectedTextAt(position: Position): InjectedText | null {1257// Identity lines collection does not support injected text.1258return null;1259}1260}126112621263