Path: blob/main/src/vs/editor/test/browser/viewModel/modelLineProjection.test.ts
3296 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 assert from 'assert';6import { IDisposable } from '../../../../base/common/lifecycle.js';7import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../base/test/common/utils.js';8import { EditorOption } from '../../../common/config/editorOptions.js';9import { Position } from '../../../common/core/position.js';10import { IRange, Range } from '../../../common/core/range.js';11import { MetadataConsts } from '../../../common/encodedTokenAttributes.js';12import * as languages from '../../../common/languages.js';13import { NullState } from '../../../common/languages/nullTokenize.js';14import { EndOfLinePreference } from '../../../common/model.js';15import { TextModel } from '../../../common/model/textModel.js';16import { ModelLineProjectionData } from '../../../common/modelLineProjectionData.js';17import { IViewLineTokens } from '../../../common/tokens/lineTokens.js';18import { ViewLineData } from '../../../common/viewModel.js';19import { IModelLineProjection, ISimpleModel, createModelLineProjection } from '../../../common/viewModel/modelLineProjection.js';20import { MonospaceLineBreaksComputerFactory } from '../../../common/viewModel/monospaceLineBreaksComputer.js';21import { ViewModelLinesFromProjectedModel } from '../../../common/viewModel/viewModelLines.js';22import { TestConfiguration } from '../config/testConfiguration.js';23import { createTextModel } from '../../common/testTextModel.js';2425suite('Editor ViewModel - SplitLinesCollection', () => {2627ensureNoDisposablesAreLeakedInTestSuite();2829test('SplitLine', () => {30let model1 = createModel('My First LineMy Second LineAnd another one');31let line1 = createSplitLine([13, 14, 15], [13, 13 + 14, 13 + 14 + 15], 0);3233assert.strictEqual(line1.getViewLineCount(), 3);34assert.strictEqual(line1.getViewLineContent(model1, 1, 0), 'My First Line');35assert.strictEqual(line1.getViewLineContent(model1, 1, 1), 'My Second Line');36assert.strictEqual(line1.getViewLineContent(model1, 1, 2), 'And another one');37assert.strictEqual(line1.getViewLineMaxColumn(model1, 1, 0), 14);38assert.strictEqual(line1.getViewLineMaxColumn(model1, 1, 1), 15);39assert.strictEqual(line1.getViewLineMaxColumn(model1, 1, 2), 16);40for (let col = 1; col <= 14; col++) {41assert.strictEqual(line1.getModelColumnOfViewPosition(0, col), col, 'getInputColumnOfOutputPosition(0, ' + col + ')');42}43for (let col = 1; col <= 15; col++) {44assert.strictEqual(line1.getModelColumnOfViewPosition(1, col), 13 + col, 'getInputColumnOfOutputPosition(1, ' + col + ')');45}46for (let col = 1; col <= 16; col++) {47assert.strictEqual(line1.getModelColumnOfViewPosition(2, col), 13 + 14 + col, 'getInputColumnOfOutputPosition(2, ' + col + ')');48}49for (let col = 1; col <= 13; col++) {50assert.deepStrictEqual(line1.getViewPositionOfModelPosition(0, col), pos(0, col), 'getOutputPositionOfInputPosition(' + col + ')');51}52for (let col = 1 + 13; col <= 14 + 13; col++) {53assert.deepStrictEqual(line1.getViewPositionOfModelPosition(0, col), pos(1, col - 13), 'getOutputPositionOfInputPosition(' + col + ')');54}55for (let col = 1 + 13 + 14; col <= 15 + 14 + 13; col++) {56assert.deepStrictEqual(line1.getViewPositionOfModelPosition(0, col), pos(2, col - 13 - 14), 'getOutputPositionOfInputPosition(' + col + ')');57}5859model1 = createModel('My First LineMy Second LineAnd another one');60line1 = createSplitLine([13, 14, 15], [13, 13 + 14, 13 + 14 + 15], 4);6162assert.strictEqual(line1.getViewLineCount(), 3);63assert.strictEqual(line1.getViewLineContent(model1, 1, 0), 'My First Line');64assert.strictEqual(line1.getViewLineContent(model1, 1, 1), ' My Second Line');65assert.strictEqual(line1.getViewLineContent(model1, 1, 2), ' And another one');66assert.strictEqual(line1.getViewLineMaxColumn(model1, 1, 0), 14);67assert.strictEqual(line1.getViewLineMaxColumn(model1, 1, 1), 19);68assert.strictEqual(line1.getViewLineMaxColumn(model1, 1, 2), 20);6970const actualViewColumnMapping: number[][] = [];71for (let lineIndex = 0; lineIndex < line1.getViewLineCount(); lineIndex++) {72const actualLineViewColumnMapping: number[] = [];73for (let col = 1; col <= line1.getViewLineMaxColumn(model1, 1, lineIndex); col++) {74actualLineViewColumnMapping.push(line1.getModelColumnOfViewPosition(lineIndex, col));75}76actualViewColumnMapping.push(actualLineViewColumnMapping);77}78assert.deepStrictEqual(actualViewColumnMapping, [79[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14],80[14, 14, 14, 14, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28],81[28, 28, 28, 28, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43],82]);8384for (let col = 1; col <= 13; col++) {85assert.deepStrictEqual(line1.getViewPositionOfModelPosition(0, col), pos(0, col), '6.getOutputPositionOfInputPosition(' + col + ')');86}87for (let col = 1 + 13; col <= 14 + 13; col++) {88assert.deepStrictEqual(line1.getViewPositionOfModelPosition(0, col), pos(1, 4 + col - 13), '7.getOutputPositionOfInputPosition(' + col + ')');89}90for (let col = 1 + 13 + 14; col <= 15 + 14 + 13; col++) {91assert.deepStrictEqual(line1.getViewPositionOfModelPosition(0, col), pos(2, 4 + col - 13 - 14), '8.getOutputPositionOfInputPosition(' + col + ')');92}93});9495function withSplitLinesCollection(text: string, callback: (model: TextModel, linesCollection: ViewModelLinesFromProjectedModel) => void): void {96const config = new TestConfiguration({});97const wrappingInfo = config.options.get(EditorOption.wrappingInfo);98const fontInfo = config.options.get(EditorOption.fontInfo);99const wordWrapBreakAfterCharacters = config.options.get(EditorOption.wordWrapBreakAfterCharacters);100const wordWrapBreakBeforeCharacters = config.options.get(EditorOption.wordWrapBreakBeforeCharacters);101const wrappingIndent = config.options.get(EditorOption.wrappingIndent);102const wordBreak = config.options.get(EditorOption.wordBreak);103const wrapOnEscapedLineFeeds = config.options.get(EditorOption.wrapOnEscapedLineFeeds);104const lineBreaksComputerFactory = new MonospaceLineBreaksComputerFactory(wordWrapBreakBeforeCharacters, wordWrapBreakAfterCharacters);105106const model = createTextModel([107'int main() {',108'\tprintf("Hello world!");',109'}',110'int main() {',111'\tprintf("Hello world!");',112'}',113].join('\n'));114115const linesCollection = new ViewModelLinesFromProjectedModel(1161,117model,118lineBreaksComputerFactory,119lineBreaksComputerFactory,120fontInfo,121model.getOptions().tabSize,122'simple',123wrappingInfo.wrappingColumn,124wrappingIndent,125wordBreak,126wrapOnEscapedLineFeeds127);128129callback(model, linesCollection);130131linesCollection.dispose();132model.dispose();133config.dispose();134}135136test('Invalid line numbers', () => {137138const text = [139'int main() {',140'\tprintf("Hello world!");',141'}',142'int main() {',143'\tprintf("Hello world!");',144'}',145].join('\n');146147withSplitLinesCollection(text, (model, linesCollection) => {148assert.strictEqual(linesCollection.getViewLineCount(), 6);149150// getOutputIndentGuide151assert.deepStrictEqual(linesCollection.getViewLinesIndentGuides(-1, -1), [0]);152assert.deepStrictEqual(linesCollection.getViewLinesIndentGuides(0, 0), [0]);153assert.deepStrictEqual(linesCollection.getViewLinesIndentGuides(1, 1), [0]);154assert.deepStrictEqual(linesCollection.getViewLinesIndentGuides(2, 2), [1]);155assert.deepStrictEqual(linesCollection.getViewLinesIndentGuides(3, 3), [0]);156assert.deepStrictEqual(linesCollection.getViewLinesIndentGuides(4, 4), [0]);157assert.deepStrictEqual(linesCollection.getViewLinesIndentGuides(5, 5), [1]);158assert.deepStrictEqual(linesCollection.getViewLinesIndentGuides(6, 6), [0]);159assert.deepStrictEqual(linesCollection.getViewLinesIndentGuides(7, 7), [0]);160161assert.deepStrictEqual(linesCollection.getViewLinesIndentGuides(0, 7), [0, 1, 0, 0, 1, 0]);162163// getOutputLineContent164assert.strictEqual(linesCollection.getViewLineContent(-1), 'int main() {');165assert.strictEqual(linesCollection.getViewLineContent(0), 'int main() {');166assert.strictEqual(linesCollection.getViewLineContent(1), 'int main() {');167assert.strictEqual(linesCollection.getViewLineContent(2), '\tprintf("Hello world!");');168assert.strictEqual(linesCollection.getViewLineContent(3), '}');169assert.strictEqual(linesCollection.getViewLineContent(4), 'int main() {');170assert.strictEqual(linesCollection.getViewLineContent(5), '\tprintf("Hello world!");');171assert.strictEqual(linesCollection.getViewLineContent(6), '}');172assert.strictEqual(linesCollection.getViewLineContent(7), '}');173174// getOutputLineMinColumn175assert.strictEqual(linesCollection.getViewLineMinColumn(-1), 1);176assert.strictEqual(linesCollection.getViewLineMinColumn(0), 1);177assert.strictEqual(linesCollection.getViewLineMinColumn(1), 1);178assert.strictEqual(linesCollection.getViewLineMinColumn(2), 1);179assert.strictEqual(linesCollection.getViewLineMinColumn(3), 1);180assert.strictEqual(linesCollection.getViewLineMinColumn(4), 1);181assert.strictEqual(linesCollection.getViewLineMinColumn(5), 1);182assert.strictEqual(linesCollection.getViewLineMinColumn(6), 1);183assert.strictEqual(linesCollection.getViewLineMinColumn(7), 1);184185// getOutputLineMaxColumn186assert.strictEqual(linesCollection.getViewLineMaxColumn(-1), 13);187assert.strictEqual(linesCollection.getViewLineMaxColumn(0), 13);188assert.strictEqual(linesCollection.getViewLineMaxColumn(1), 13);189assert.strictEqual(linesCollection.getViewLineMaxColumn(2), 25);190assert.strictEqual(linesCollection.getViewLineMaxColumn(3), 2);191assert.strictEqual(linesCollection.getViewLineMaxColumn(4), 13);192assert.strictEqual(linesCollection.getViewLineMaxColumn(5), 25);193assert.strictEqual(linesCollection.getViewLineMaxColumn(6), 2);194assert.strictEqual(linesCollection.getViewLineMaxColumn(7), 2);195196// convertOutputPositionToInputPosition197assert.deepStrictEqual(linesCollection.convertViewPositionToModelPosition(-1, 1), new Position(1, 1));198assert.deepStrictEqual(linesCollection.convertViewPositionToModelPosition(0, 1), new Position(1, 1));199assert.deepStrictEqual(linesCollection.convertViewPositionToModelPosition(1, 1), new Position(1, 1));200assert.deepStrictEqual(linesCollection.convertViewPositionToModelPosition(2, 1), new Position(2, 1));201assert.deepStrictEqual(linesCollection.convertViewPositionToModelPosition(3, 1), new Position(3, 1));202assert.deepStrictEqual(linesCollection.convertViewPositionToModelPosition(4, 1), new Position(4, 1));203assert.deepStrictEqual(linesCollection.convertViewPositionToModelPosition(5, 1), new Position(5, 1));204assert.deepStrictEqual(linesCollection.convertViewPositionToModelPosition(6, 1), new Position(6, 1));205assert.deepStrictEqual(linesCollection.convertViewPositionToModelPosition(7, 1), new Position(6, 1));206assert.deepStrictEqual(linesCollection.convertViewPositionToModelPosition(8, 1), new Position(6, 1));207});208});209210test('issue #3662', () => {211212const text = [213'int main() {',214'\tprintf("Hello world!");',215'}',216'int main() {',217'\tprintf("Hello world!");',218'}',219].join('\n');220221withSplitLinesCollection(text, (model, linesCollection) => {222linesCollection.setHiddenAreas([223new Range(1, 1, 3, 1),224new Range(5, 1, 6, 1)225]);226227const viewLineCount = linesCollection.getViewLineCount();228assert.strictEqual(viewLineCount, 1, 'getOutputLineCount()');229230const modelLineCount = model.getLineCount();231for (let lineNumber = 0; lineNumber <= modelLineCount + 1; lineNumber++) {232const lineMinColumn = (lineNumber >= 1 && lineNumber <= modelLineCount) ? model.getLineMinColumn(lineNumber) : 1;233const lineMaxColumn = (lineNumber >= 1 && lineNumber <= modelLineCount) ? model.getLineMaxColumn(lineNumber) : 1;234for (let column = lineMinColumn - 1; column <= lineMaxColumn + 1; column++) {235const viewPosition = linesCollection.convertModelPositionToViewPosition(lineNumber, column);236237// validate view position238let viewLineNumber = viewPosition.lineNumber;239let viewColumn = viewPosition.column;240if (viewLineNumber < 1) {241viewLineNumber = 1;242}243const lineCount = linesCollection.getViewLineCount();244if (viewLineNumber > lineCount) {245viewLineNumber = lineCount;246}247const viewMinColumn = linesCollection.getViewLineMinColumn(viewLineNumber);248const viewMaxColumn = linesCollection.getViewLineMaxColumn(viewLineNumber);249if (viewColumn < viewMinColumn) {250viewColumn = viewMinColumn;251}252if (viewColumn > viewMaxColumn) {253viewColumn = viewMaxColumn;254}255const validViewPosition = new Position(viewLineNumber, viewColumn);256assert.strictEqual(viewPosition.toString(), validViewPosition.toString(), 'model->view for ' + lineNumber + ', ' + column);257}258}259260for (let lineNumber = 0; lineNumber <= viewLineCount + 1; lineNumber++) {261const lineMinColumn = linesCollection.getViewLineMinColumn(lineNumber);262const lineMaxColumn = linesCollection.getViewLineMaxColumn(lineNumber);263for (let column = lineMinColumn - 1; column <= lineMaxColumn + 1; column++) {264const modelPosition = linesCollection.convertViewPositionToModelPosition(lineNumber, column);265const validModelPosition = model.validatePosition(modelPosition);266assert.strictEqual(modelPosition.toString(), validModelPosition.toString(), 'view->model for ' + lineNumber + ', ' + column);267}268}269});270});271272});273274suite('SplitLinesCollection', () => {275276const _text = [277'class Nice {',278' function hi() {',279' console.log("Hello world");',280' }',281' function hello() {',282' console.log("Hello world, this is a somewhat longer line");',283' }',284'}',285];286287const _tokens = [288[289{ startIndex: 0, value: 1 },290{ startIndex: 5, value: 2 },291{ startIndex: 6, value: 3 },292{ startIndex: 10, value: 4 },293],294[295{ startIndex: 0, value: 5 },296{ startIndex: 1, value: 6 },297{ startIndex: 9, value: 7 },298{ startIndex: 10, value: 8 },299{ startIndex: 12, value: 9 },300],301[302{ startIndex: 0, value: 10 },303{ startIndex: 2, value: 11 },304{ startIndex: 9, value: 12 },305{ startIndex: 10, value: 13 },306{ startIndex: 13, value: 14 },307{ startIndex: 14, value: 15 },308{ startIndex: 27, value: 16 },309],310[311{ startIndex: 0, value: 17 },312],313[314{ startIndex: 0, value: 18 },315{ startIndex: 1, value: 19 },316{ startIndex: 9, value: 20 },317{ startIndex: 10, value: 21 },318{ startIndex: 15, value: 22 },319],320[321{ startIndex: 0, value: 23 },322{ startIndex: 2, value: 24 },323{ startIndex: 9, value: 25 },324{ startIndex: 10, value: 26 },325{ startIndex: 13, value: 27 },326{ startIndex: 14, value: 28 },327{ startIndex: 59, value: 29 },328],329[330{ startIndex: 0, value: 30 },331],332[333{ startIndex: 0, value: 31 },334]335];336337let model: TextModel;338let languageRegistration: IDisposable;339340setup(() => {341let _lineIndex = 0;342const tokenizationSupport: languages.ITokenizationSupport = {343getInitialState: () => NullState,344tokenize: undefined!,345tokenizeEncoded: (line: string, hasEOL: boolean, state: languages.IState): languages.EncodedTokenizationResult => {346const tokens = _tokens[_lineIndex++];347348const result = new Uint32Array(2 * tokens.length);349for (let i = 0; i < tokens.length; i++) {350result[2 * i] = tokens[i].startIndex;351result[2 * i + 1] = (352tokens[i].value << MetadataConsts.FOREGROUND_OFFSET353);354}355return new languages.EncodedTokenizationResult(result, state);356}357};358const LANGUAGE_ID = 'modelModeTest1';359languageRegistration = languages.TokenizationRegistry.register(LANGUAGE_ID, tokenizationSupport);360model = createTextModel(_text.join('\n'), LANGUAGE_ID);361// force tokenization362model.tokenization.forceTokenization(model.getLineCount());363});364365teardown(() => {366model.dispose();367languageRegistration.dispose();368});369370ensureNoDisposablesAreLeakedInTestSuite();371372interface ITestViewLineToken {373endIndex: number;374value: number;375}376377function assertViewLineTokens(_actual: IViewLineTokens, expected: ITestViewLineToken[]): void {378const actual: ITestViewLineToken[] = [];379for (let i = 0, len = _actual.getCount(); i < len; i++) {380actual[i] = {381endIndex: _actual.getEndOffset(i),382value: _actual.getForeground(i)383};384}385assert.deepStrictEqual(actual, expected);386}387388interface ITestMinimapLineRenderingData {389content: string;390minColumn: number;391maxColumn: number;392tokens: ITestViewLineToken[];393}394395function assertMinimapLineRenderingData(actual: ViewLineData, expected: ITestMinimapLineRenderingData | null): void {396if (actual === null && expected === null) {397assert.ok(true);398return;399}400if (expected === null) {401assert.ok(false);402}403assert.strictEqual(actual.content, expected.content);404assert.strictEqual(actual.minColumn, expected.minColumn);405assert.strictEqual(actual.maxColumn, expected.maxColumn);406assertViewLineTokens(actual.tokens, expected.tokens);407}408409function assertMinimapLinesRenderingData(actual: ViewLineData[], expected: Array<ITestMinimapLineRenderingData | null>): void {410assert.strictEqual(actual.length, expected.length);411for (let i = 0; i < expected.length; i++) {412assertMinimapLineRenderingData(actual[i], expected[i]);413}414}415416function assertAllMinimapLinesRenderingData(splitLinesCollection: ViewModelLinesFromProjectedModel, all: ITestMinimapLineRenderingData[]): void {417const lineCount = all.length;418for (let line = 1; line <= lineCount; line++) {419assert.strictEqual(splitLinesCollection.getViewLineData(line).content, splitLinesCollection.getViewLineContent(line));420}421422for (let start = 1; start <= lineCount; start++) {423for (let end = start; end <= lineCount; end++) {424const count = end - start + 1;425for (let desired = Math.pow(2, count) - 1; desired >= 0; desired--) {426const needed: boolean[] = [];427const expected: Array<ITestMinimapLineRenderingData | null> = [];428for (let i = 0; i < count; i++) {429needed[i] = (desired & (1 << i)) ? true : false;430expected[i] = (needed[i] ? all[start - 1 + i] : null);431}432const actual = splitLinesCollection.getViewLinesData(start, end, needed);433434assertMinimapLinesRenderingData(actual, expected);435// Comment out next line to test all possible combinations436break;437}438}439}440}441442test('getViewLinesData - no wrapping', () => {443withSplitLinesCollection(model, 'off', 0, false, (splitLinesCollection) => {444assert.strictEqual(splitLinesCollection.getViewLineCount(), 8);445assert.strictEqual(splitLinesCollection.modelPositionIsVisible(1, 1), true);446assert.strictEqual(splitLinesCollection.modelPositionIsVisible(2, 1), true);447assert.strictEqual(splitLinesCollection.modelPositionIsVisible(3, 1), true);448assert.strictEqual(splitLinesCollection.modelPositionIsVisible(4, 1), true);449assert.strictEqual(splitLinesCollection.modelPositionIsVisible(5, 1), true);450assert.strictEqual(splitLinesCollection.modelPositionIsVisible(6, 1), true);451assert.strictEqual(splitLinesCollection.modelPositionIsVisible(7, 1), true);452assert.strictEqual(splitLinesCollection.modelPositionIsVisible(8, 1), true);453454const _expected: ITestMinimapLineRenderingData[] = [455{456content: 'class Nice {',457minColumn: 1,458maxColumn: 13,459tokens: [460{ endIndex: 5, value: 1 },461{ endIndex: 6, value: 2 },462{ endIndex: 10, value: 3 },463{ endIndex: 12, value: 4 },464]465},466{467content: ' function hi() {',468minColumn: 1,469maxColumn: 17,470tokens: [471{ endIndex: 1, value: 5 },472{ endIndex: 9, value: 6 },473{ endIndex: 10, value: 7 },474{ endIndex: 12, value: 8 },475{ endIndex: 16, value: 9 },476]477},478{479content: ' console.log("Hello world");',480minColumn: 1,481maxColumn: 30,482tokens: [483{ endIndex: 2, value: 10 },484{ endIndex: 9, value: 11 },485{ endIndex: 10, value: 12 },486{ endIndex: 13, value: 13 },487{ endIndex: 14, value: 14 },488{ endIndex: 27, value: 15 },489{ endIndex: 29, value: 16 },490]491},492{493content: ' }',494minColumn: 1,495maxColumn: 3,496tokens: [497{ endIndex: 2, value: 17 },498]499},500{501content: ' function hello() {',502minColumn: 1,503maxColumn: 20,504tokens: [505{ endIndex: 1, value: 18 },506{ endIndex: 9, value: 19 },507{ endIndex: 10, value: 20 },508{ endIndex: 15, value: 21 },509{ endIndex: 19, value: 22 },510]511},512{513content: ' console.log("Hello world, this is a somewhat longer line");',514minColumn: 1,515maxColumn: 62,516tokens: [517{ endIndex: 2, value: 23 },518{ endIndex: 9, value: 24 },519{ endIndex: 10, value: 25 },520{ endIndex: 13, value: 26 },521{ endIndex: 14, value: 27 },522{ endIndex: 59, value: 28 },523{ endIndex: 61, value: 29 },524]525},526{527minColumn: 1,528maxColumn: 3,529content: ' }',530tokens: [531{ endIndex: 2, value: 30 },532]533},534{535minColumn: 1,536maxColumn: 2,537content: '}',538tokens: [539{ endIndex: 1, value: 31 },540]541}542];543544assertAllMinimapLinesRenderingData(splitLinesCollection, [545_expected[0],546_expected[1],547_expected[2],548_expected[3],549_expected[4],550_expected[5],551_expected[6],552_expected[7],553]);554555splitLinesCollection.setHiddenAreas([new Range(2, 1, 4, 1)]);556assert.strictEqual(splitLinesCollection.getViewLineCount(), 5);557assert.strictEqual(splitLinesCollection.modelPositionIsVisible(1, 1), true);558assert.strictEqual(splitLinesCollection.modelPositionIsVisible(2, 1), false);559assert.strictEqual(splitLinesCollection.modelPositionIsVisible(3, 1), false);560assert.strictEqual(splitLinesCollection.modelPositionIsVisible(4, 1), false);561assert.strictEqual(splitLinesCollection.modelPositionIsVisible(5, 1), true);562assert.strictEqual(splitLinesCollection.modelPositionIsVisible(6, 1), true);563assert.strictEqual(splitLinesCollection.modelPositionIsVisible(7, 1), true);564assert.strictEqual(splitLinesCollection.modelPositionIsVisible(8, 1), true);565566assertAllMinimapLinesRenderingData(splitLinesCollection, [567_expected[0],568_expected[4],569_expected[5],570_expected[6],571_expected[7],572]);573});574});575576test('getViewLinesData - with wrapping', () => {577withSplitLinesCollection(model, 'wordWrapColumn', 30, false, (splitLinesCollection) => {578assert.strictEqual(splitLinesCollection.getViewLineCount(), 12);579assert.strictEqual(splitLinesCollection.modelPositionIsVisible(1, 1), true);580assert.strictEqual(splitLinesCollection.modelPositionIsVisible(2, 1), true);581assert.strictEqual(splitLinesCollection.modelPositionIsVisible(3, 1), true);582assert.strictEqual(splitLinesCollection.modelPositionIsVisible(4, 1), true);583assert.strictEqual(splitLinesCollection.modelPositionIsVisible(5, 1), true);584assert.strictEqual(splitLinesCollection.modelPositionIsVisible(6, 1), true);585assert.strictEqual(splitLinesCollection.modelPositionIsVisible(7, 1), true);586assert.strictEqual(splitLinesCollection.modelPositionIsVisible(8, 1), true);587588const _expected: ITestMinimapLineRenderingData[] = [589{590content: 'class Nice {',591minColumn: 1,592maxColumn: 13,593tokens: [594{ endIndex: 5, value: 1 },595{ endIndex: 6, value: 2 },596{ endIndex: 10, value: 3 },597{ endIndex: 12, value: 4 },598]599},600{601content: ' function hi() {',602minColumn: 1,603maxColumn: 17,604tokens: [605{ endIndex: 1, value: 5 },606{ endIndex: 9, value: 6 },607{ endIndex: 10, value: 7 },608{ endIndex: 12, value: 8 },609{ endIndex: 16, value: 9 },610]611},612{613content: ' console.log("Hello ',614minColumn: 1,615maxColumn: 22,616tokens: [617{ endIndex: 2, value: 10 },618{ endIndex: 9, value: 11 },619{ endIndex: 10, value: 12 },620{ endIndex: 13, value: 13 },621{ endIndex: 14, value: 14 },622{ endIndex: 21, value: 15 },623]624},625{626content: ' world");',627minColumn: 13,628maxColumn: 21,629tokens: [630{ endIndex: 18, value: 15 },631{ endIndex: 20, value: 16 },632]633},634{635content: ' }',636minColumn: 1,637maxColumn: 3,638tokens: [639{ endIndex: 2, value: 17 },640]641},642{643content: ' function hello() {',644minColumn: 1,645maxColumn: 20,646tokens: [647{ endIndex: 1, value: 18 },648{ endIndex: 9, value: 19 },649{ endIndex: 10, value: 20 },650{ endIndex: 15, value: 21 },651{ endIndex: 19, value: 22 },652]653},654{655content: ' console.log("Hello ',656minColumn: 1,657maxColumn: 22,658tokens: [659{ endIndex: 2, value: 23 },660{ endIndex: 9, value: 24 },661{ endIndex: 10, value: 25 },662{ endIndex: 13, value: 26 },663{ endIndex: 14, value: 27 },664{ endIndex: 21, value: 28 },665]666},667{668content: ' world, this is a ',669minColumn: 13,670maxColumn: 30,671tokens: [672{ endIndex: 29, value: 28 },673]674},675{676content: ' somewhat longer ',677minColumn: 13,678maxColumn: 29,679tokens: [680{ endIndex: 28, value: 28 },681]682},683{684content: ' line");',685minColumn: 13,686maxColumn: 20,687tokens: [688{ endIndex: 17, value: 28 },689{ endIndex: 19, value: 29 },690]691},692{693content: ' }',694minColumn: 1,695maxColumn: 3,696tokens: [697{ endIndex: 2, value: 30 },698]699},700{701content: '}',702minColumn: 1,703maxColumn: 2,704tokens: [705{ endIndex: 1, value: 31 },706]707}708];709710assertAllMinimapLinesRenderingData(splitLinesCollection, [711_expected[0],712_expected[1],713_expected[2],714_expected[3],715_expected[4],716_expected[5],717_expected[6],718_expected[7],719_expected[8],720_expected[9],721_expected[10],722_expected[11],723]);724725splitLinesCollection.setHiddenAreas([new Range(2, 1, 4, 1)]);726assert.strictEqual(splitLinesCollection.getViewLineCount(), 8);727assert.strictEqual(splitLinesCollection.modelPositionIsVisible(1, 1), true);728assert.strictEqual(splitLinesCollection.modelPositionIsVisible(2, 1), false);729assert.strictEqual(splitLinesCollection.modelPositionIsVisible(3, 1), false);730assert.strictEqual(splitLinesCollection.modelPositionIsVisible(4, 1), false);731assert.strictEqual(splitLinesCollection.modelPositionIsVisible(5, 1), true);732assert.strictEqual(splitLinesCollection.modelPositionIsVisible(6, 1), true);733assert.strictEqual(splitLinesCollection.modelPositionIsVisible(7, 1), true);734assert.strictEqual(splitLinesCollection.modelPositionIsVisible(8, 1), true);735736assertAllMinimapLinesRenderingData(splitLinesCollection, [737_expected[0],738_expected[5],739_expected[6],740_expected[7],741_expected[8],742_expected[9],743_expected[10],744_expected[11],745]);746});747});748749test('getViewLinesData - with wrapping and injected text', () => {750model.deltaDecorations([], [{751range: new Range(1, 9, 1, 9),752options: {753description: 'example',754after: {755content: 'very very long injected text that causes a line break',756inlineClassName: 'myClassName'757},758showIfCollapsed: true,759}760}]);761762withSplitLinesCollection(model, 'wordWrapColumn', 30, false, (splitLinesCollection) => {763assert.strictEqual(splitLinesCollection.getViewLineCount(), 14);764765assert.strictEqual(splitLinesCollection.getViewLineMaxColumn(1), 24);766767const _expected: ITestMinimapLineRenderingData[] = [768{769content: 'class Nivery very long ',770minColumn: 1,771maxColumn: 24,772tokens: [773{ endIndex: 5, value: 1 },774{ endIndex: 6, value: 2 },775{ endIndex: 8, value: 3 },776{ endIndex: 23, value: 1 },777]778},779{780content: ' injected text that causes ',781minColumn: 5,782maxColumn: 31,783tokens: [{ endIndex: 30, value: 1 }]784},785{786content: ' a line breakce {',787minColumn: 5,788maxColumn: 21,789tokens: [790{ endIndex: 16, value: 1 },791{ endIndex: 18, value: 3 },792{ endIndex: 20, value: 4 }793]794},795{796content: ' function hi() {',797minColumn: 1,798maxColumn: 17,799tokens: [800{ endIndex: 1, value: 5 },801{ endIndex: 9, value: 6 },802{ endIndex: 10, value: 7 },803{ endIndex: 12, value: 8 },804{ endIndex: 16, value: 9 },805]806},807{808content: ' console.log("Hello ',809minColumn: 1,810maxColumn: 22,811tokens: [812{ endIndex: 2, value: 10 },813{ endIndex: 9, value: 11 },814{ endIndex: 10, value: 12 },815{ endIndex: 13, value: 13 },816{ endIndex: 14, value: 14 },817{ endIndex: 21, value: 15 },818]819},820{821content: ' world");',822minColumn: 13,823maxColumn: 21,824tokens: [825{ endIndex: 18, value: 15 },826{ endIndex: 20, value: 16 },827]828},829{830content: ' }',831minColumn: 1,832maxColumn: 3,833tokens: [834{ endIndex: 2, value: 17 },835]836},837{838content: ' function hello() {',839minColumn: 1,840maxColumn: 20,841tokens: [842{ endIndex: 1, value: 18 },843{ endIndex: 9, value: 19 },844{ endIndex: 10, value: 20 },845{ endIndex: 15, value: 21 },846{ endIndex: 19, value: 22 },847]848},849{850content: ' console.log("Hello ',851minColumn: 1,852maxColumn: 22,853tokens: [854{ endIndex: 2, value: 23 },855{ endIndex: 9, value: 24 },856{ endIndex: 10, value: 25 },857{ endIndex: 13, value: 26 },858{ endIndex: 14, value: 27 },859{ endIndex: 21, value: 28 },860]861},862{863content: ' world, this is a ',864minColumn: 13,865maxColumn: 30,866tokens: [867{ endIndex: 29, value: 28 },868]869},870{871content: ' somewhat longer ',872minColumn: 13,873maxColumn: 29,874tokens: [875{ endIndex: 28, value: 28 },876]877},878{879content: ' line");',880minColumn: 13,881maxColumn: 20,882tokens: [883{ endIndex: 17, value: 28 },884{ endIndex: 19, value: 29 },885]886},887{888content: ' }',889minColumn: 1,890maxColumn: 3,891tokens: [892{ endIndex: 2, value: 30 },893]894},895{896content: '}',897minColumn: 1,898maxColumn: 2,899tokens: [900{ endIndex: 1, value: 31 },901]902}903];904905assertAllMinimapLinesRenderingData(splitLinesCollection, [906_expected[0],907_expected[1],908_expected[2],909_expected[3],910_expected[4],911_expected[5],912_expected[6],913_expected[7],914_expected[8],915_expected[9],916_expected[10],917_expected[11],918]);919920const data = splitLinesCollection.getViewLinesData(1, 14, new Array(14).fill(true));921assert.deepStrictEqual(922data.map((d) => ({923inlineDecorations: d.inlineDecorations?.map((d) => ({924startOffset: d.startOffset,925endOffset: d.endOffset,926})),927})),928[929{ inlineDecorations: [{ startOffset: 8, endOffset: 23 }] },930{ inlineDecorations: [{ startOffset: 4, endOffset: 30 }] },931{ inlineDecorations: [{ startOffset: 4, endOffset: 16 }] },932{ inlineDecorations: undefined },933{ inlineDecorations: undefined },934{ inlineDecorations: undefined },935{ inlineDecorations: undefined },936{ inlineDecorations: undefined },937{ inlineDecorations: undefined },938{ inlineDecorations: undefined },939{ inlineDecorations: undefined },940{ inlineDecorations: undefined },941{ inlineDecorations: undefined },942{ inlineDecorations: undefined },943]944);945});946});947948function withSplitLinesCollection(model: TextModel, wordWrap: 'on' | 'off' | 'wordWrapColumn' | 'bounded', wordWrapColumn: number, wrapOnEscapedLineFeeds: boolean, callback: (splitLinesCollection: ViewModelLinesFromProjectedModel) => void): void {949const configuration = new TestConfiguration({950wordWrap: wordWrap,951wordWrapColumn: wordWrapColumn,952wrappingIndent: 'indent'953});954const wrappingInfo = configuration.options.get(EditorOption.wrappingInfo);955const fontInfo = configuration.options.get(EditorOption.fontInfo);956const wordWrapBreakAfterCharacters = configuration.options.get(EditorOption.wordWrapBreakAfterCharacters);957const wordWrapBreakBeforeCharacters = configuration.options.get(EditorOption.wordWrapBreakBeforeCharacters);958const wrappingIndent = configuration.options.get(EditorOption.wrappingIndent);959const wordBreak = configuration.options.get(EditorOption.wordBreak);960961const lineBreaksComputerFactory = new MonospaceLineBreaksComputerFactory(wordWrapBreakBeforeCharacters, wordWrapBreakAfterCharacters);962963const linesCollection = new ViewModelLinesFromProjectedModel(9641,965model,966lineBreaksComputerFactory,967lineBreaksComputerFactory,968fontInfo,969model.getOptions().tabSize,970'simple',971wrappingInfo.wrappingColumn,972wrappingIndent,973wordBreak,974wrapOnEscapedLineFeeds975);976977callback(linesCollection);978979configuration.dispose();980}981});982983984function pos(lineNumber: number, column: number): Position {985return new Position(lineNumber, column);986}987988function createSplitLine(splitLengths: number[], breakingOffsetsVisibleColumn: number[], wrappedTextIndentWidth: number, isVisible: boolean = true): IModelLineProjection {989return createModelLineProjection(createLineBreakData(splitLengths, breakingOffsetsVisibleColumn, wrappedTextIndentWidth), isVisible);990}991992function createLineBreakData(breakingLengths: number[], breakingOffsetsVisibleColumn: number[], wrappedTextIndentWidth: number): ModelLineProjectionData {993const sums: number[] = [];994for (let i = 0; i < breakingLengths.length; i++) {995sums[i] = (i > 0 ? sums[i - 1] : 0) + breakingLengths[i];996}997return new ModelLineProjectionData(null, null, sums, breakingOffsetsVisibleColumn, wrappedTextIndentWidth);998}9991000function createModel(text: string): ISimpleModel {1001return {1002tokenization: {1003getLineTokens: (lineNumber: number) => {1004return null!;1005},1006},1007getLineContent: (lineNumber: number) => {1008return text;1009},1010getLineLength: (lineNumber: number) => {1011return text.length;1012},1013getLineMinColumn: (lineNumber: number) => {1014return 1;1015},1016getLineMaxColumn: (lineNumber: number) => {1017return text.length + 1;1018},1019getValueInRange: (range: IRange, eol?: EndOfLinePreference) => {1020return text.substring(range.startColumn - 1, range.endColumn - 1);1021}1022};1023}102410251026