Path: blob/main/src/vs/editor/test/common/model/textModel.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 { DisposableStore } from '../../../../base/common/lifecycle.js';7import { UTF8_BOM_CHARACTER } from '../../../../base/common/strings.js';8import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../base/test/common/utils.js';9import { Position } from '../../../common/core/position.js';10import { Range } from '../../../common/core/range.js';11import { PLAINTEXT_LANGUAGE_ID } from '../../../common/languages/modesRegistry.js';12import { EndOfLinePreference } from '../../../common/model.js';13import { TextModel, createTextBuffer } from '../../../common/model/textModel.js';14import { createModelServices, createTextModel } from '../testTextModel.js';15import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js';1617function testGuessIndentation(defaultInsertSpaces: boolean, defaultTabSize: number, expectedInsertSpaces: boolean, expectedTabSize: number, text: string[], msg?: string): void {18const m = createTextModel(19text.join('\n'),20undefined,21{22tabSize: defaultTabSize,23insertSpaces: defaultInsertSpaces,24detectIndentation: true25}26);27const r = m.getOptions();28m.dispose();2930assert.strictEqual(r.insertSpaces, expectedInsertSpaces, msg);31assert.strictEqual(r.tabSize, expectedTabSize, msg);32}3334function assertGuess(expectedInsertSpaces: boolean | undefined, expectedTabSize: number | undefined | [number], text: string[], msg?: string): void {35if (typeof expectedInsertSpaces === 'undefined') {36// cannot guess insertSpaces37if (typeof expectedTabSize === 'undefined') {38// cannot guess tabSize39testGuessIndentation(true, 13370, true, 13370, text, msg);40testGuessIndentation(false, 13371, false, 13371, text, msg);41} else if (typeof expectedTabSize === 'number') {42// can guess tabSize43testGuessIndentation(true, 13370, true, expectedTabSize, text, msg);44testGuessIndentation(false, 13371, false, expectedTabSize, text, msg);45} else {46// can only guess tabSize when insertSpaces is true47testGuessIndentation(true, 13370, true, expectedTabSize[0], text, msg);48testGuessIndentation(false, 13371, false, 13371, text, msg);49}50} else {51// can guess insertSpaces52if (typeof expectedTabSize === 'undefined') {53// cannot guess tabSize54testGuessIndentation(true, 13370, expectedInsertSpaces, 13370, text, msg);55testGuessIndentation(false, 13371, expectedInsertSpaces, 13371, text, msg);56} else if (typeof expectedTabSize === 'number') {57// can guess tabSize58testGuessIndentation(true, 13370, expectedInsertSpaces, expectedTabSize, text, msg);59testGuessIndentation(false, 13371, expectedInsertSpaces, expectedTabSize, text, msg);60} else {61// can only guess tabSize when insertSpaces is true62if (expectedInsertSpaces === true) {63testGuessIndentation(true, 13370, expectedInsertSpaces, expectedTabSize[0], text, msg);64testGuessIndentation(false, 13371, expectedInsertSpaces, expectedTabSize[0], text, msg);65} else {66testGuessIndentation(true, 13370, expectedInsertSpaces, 13370, text, msg);67testGuessIndentation(false, 13371, expectedInsertSpaces, 13371, text, msg);68}69}70}71}7273suite('TextModelData.fromString', () => {7475ensureNoDisposablesAreLeakedInTestSuite();7677interface ITextBufferData {78EOL: string;79lines: string[];80containsRTL: boolean;81isBasicASCII: boolean;82}8384function testTextModelDataFromString(text: string, expected: ITextBufferData): void {85const { textBuffer, disposable } = createTextBuffer(text, TextModel.DEFAULT_CREATION_OPTIONS.defaultEOL);86const actual: ITextBufferData = {87EOL: textBuffer.getEOL(),88lines: textBuffer.getLinesContent(),89containsRTL: textBuffer.mightContainRTL(),90isBasicASCII: !textBuffer.mightContainNonBasicASCII()91};92assert.deepStrictEqual(actual, expected);93disposable.dispose();94}9596test('one line text', () => {97testTextModelDataFromString('Hello world!',98{99EOL: '\n',100lines: [101'Hello world!'102],103containsRTL: false,104isBasicASCII: true105}106);107});108109test('multiline text', () => {110testTextModelDataFromString('Hello,\r\ndear friend\nHow\rare\r\nyou?',111{112EOL: '\r\n',113lines: [114'Hello,',115'dear friend',116'How',117'are',118'you?'119],120containsRTL: false,121isBasicASCII: true122}123);124});125126test('Non Basic ASCII 1', () => {127testTextModelDataFromString('Hello,\nZürich',128{129EOL: '\n',130lines: [131'Hello,',132'Zürich'133],134containsRTL: false,135isBasicASCII: false136}137);138});139140test('containsRTL 1', () => {141testTextModelDataFromString('Hello,\nזוהי עובדה מבוססת שדעתו',142{143EOL: '\n',144lines: [145'Hello,',146'זוהי עובדה מבוססת שדעתו'147],148containsRTL: true,149isBasicASCII: false150}151);152});153154test('containsRTL 2', () => {155testTextModelDataFromString('Hello,\nهناك حقيقة مثبتة منذ زمن طويل',156{157EOL: '\n',158lines: [159'Hello,',160'هناك حقيقة مثبتة منذ زمن طويل'161],162containsRTL: true,163isBasicASCII: false164}165);166});167168});169170suite('Editor Model - TextModel', () => {171172ensureNoDisposablesAreLeakedInTestSuite();173174test('TextModel does not use events internally', () => {175// Make sure that all model parts receive text model events explicitly176// to avoid that by any chance an outside listener receives events before177// the parts and thus are able to access the text model in an inconsistent state.178//179// We simply check that there are no listeners attached to text model180// after instantiation181const disposables = new DisposableStore();182const instantiationService: IInstantiationService = createModelServices(disposables);183const textModel = disposables.add(instantiationService.createInstance(TextModel, '', PLAINTEXT_LANGUAGE_ID, TextModel.DEFAULT_CREATION_OPTIONS, null));184assert.strictEqual(textModel._hasListeners(), false);185disposables.dispose();186});187188test('getValueLengthInRange', () => {189190let m = createTextModel('My First Line\r\nMy Second Line\r\nMy Third Line');191assert.strictEqual(m.getValueLengthInRange(new Range(1, 1, 1, 1)), ''.length);192assert.strictEqual(m.getValueLengthInRange(new Range(1, 1, 1, 2)), 'M'.length);193assert.strictEqual(m.getValueLengthInRange(new Range(1, 2, 1, 3)), 'y'.length);194assert.strictEqual(m.getValueLengthInRange(new Range(1, 1, 1, 14)), 'My First Line'.length);195assert.strictEqual(m.getValueLengthInRange(new Range(1, 1, 2, 1)), 'My First Line\r\n'.length);196assert.strictEqual(m.getValueLengthInRange(new Range(1, 2, 2, 1)), 'y First Line\r\n'.length);197assert.strictEqual(m.getValueLengthInRange(new Range(1, 2, 2, 2)), 'y First Line\r\nM'.length);198assert.strictEqual(m.getValueLengthInRange(new Range(1, 2, 2, 1000)), 'y First Line\r\nMy Second Line'.length);199assert.strictEqual(m.getValueLengthInRange(new Range(1, 2, 3, 1)), 'y First Line\r\nMy Second Line\r\n'.length);200assert.strictEqual(m.getValueLengthInRange(new Range(1, 2, 3, 1000)), 'y First Line\r\nMy Second Line\r\nMy Third Line'.length);201assert.strictEqual(m.getValueLengthInRange(new Range(1, 1, 1000, 1000)), 'My First Line\r\nMy Second Line\r\nMy Third Line'.length);202m.dispose();203204m = createTextModel('My First Line\nMy Second Line\nMy Third Line');205assert.strictEqual(m.getValueLengthInRange(new Range(1, 1, 1, 1)), ''.length);206assert.strictEqual(m.getValueLengthInRange(new Range(1, 1, 1, 2)), 'M'.length);207assert.strictEqual(m.getValueLengthInRange(new Range(1, 2, 1, 3)), 'y'.length);208assert.strictEqual(m.getValueLengthInRange(new Range(1, 1, 1, 14)), 'My First Line'.length);209assert.strictEqual(m.getValueLengthInRange(new Range(1, 1, 2, 1)), 'My First Line\n'.length);210assert.strictEqual(m.getValueLengthInRange(new Range(1, 2, 2, 1)), 'y First Line\n'.length);211assert.strictEqual(m.getValueLengthInRange(new Range(1, 2, 2, 2)), 'y First Line\nM'.length);212assert.strictEqual(m.getValueLengthInRange(new Range(1, 2, 2, 1000)), 'y First Line\nMy Second Line'.length);213assert.strictEqual(m.getValueLengthInRange(new Range(1, 2, 3, 1)), 'y First Line\nMy Second Line\n'.length);214assert.strictEqual(m.getValueLengthInRange(new Range(1, 2, 3, 1000)), 'y First Line\nMy Second Line\nMy Third Line'.length);215assert.strictEqual(m.getValueLengthInRange(new Range(1, 1, 1000, 1000)), 'My First Line\nMy Second Line\nMy Third Line'.length);216m.dispose();217});218219test('getValueLengthInRange different EOL', () => {220221let m = createTextModel('My First Line\r\nMy Second Line\r\nMy Third Line');222assert.strictEqual(m.getValueLengthInRange(new Range(1, 1, 2, 1), EndOfLinePreference.TextDefined), 'My First Line\r\n'.length);223assert.strictEqual(m.getValueLengthInRange(new Range(1, 1, 2, 1), EndOfLinePreference.CRLF), 'My First Line\r\n'.length);224assert.strictEqual(m.getValueLengthInRange(new Range(1, 1, 2, 1), EndOfLinePreference.LF), 'My First Line\n'.length);225assert.strictEqual(m.getValueLengthInRange(new Range(1, 1, 1000, 1000), EndOfLinePreference.TextDefined), 'My First Line\r\nMy Second Line\r\nMy Third Line'.length);226assert.strictEqual(m.getValueLengthInRange(new Range(1, 1, 1000, 1000), EndOfLinePreference.CRLF), 'My First Line\r\nMy Second Line\r\nMy Third Line'.length);227assert.strictEqual(m.getValueLengthInRange(new Range(1, 1, 1000, 1000), EndOfLinePreference.LF), 'My First Line\nMy Second Line\nMy Third Line'.length);228m.dispose();229230m = createTextModel('My First Line\nMy Second Line\nMy Third Line');231assert.strictEqual(m.getValueLengthInRange(new Range(1, 1, 2, 1), EndOfLinePreference.TextDefined), 'My First Line\n'.length);232assert.strictEqual(m.getValueLengthInRange(new Range(1, 1, 2, 1), EndOfLinePreference.LF), 'My First Line\n'.length);233assert.strictEqual(m.getValueLengthInRange(new Range(1, 1, 2, 1), EndOfLinePreference.CRLF), 'My First Line\r\n'.length);234assert.strictEqual(m.getValueLengthInRange(new Range(1, 1, 1000, 1000), EndOfLinePreference.TextDefined), 'My First Line\nMy Second Line\nMy Third Line'.length);235assert.strictEqual(m.getValueLengthInRange(new Range(1, 1, 1000, 1000), EndOfLinePreference.LF), 'My First Line\nMy Second Line\nMy Third Line'.length);236assert.strictEqual(m.getValueLengthInRange(new Range(1, 1, 1000, 1000), EndOfLinePreference.CRLF), 'My First Line\r\nMy Second Line\r\nMy Third Line'.length);237m.dispose();238});239240test('guess indentation 1', () => {241242assertGuess(undefined, undefined, [243'x',244'x',245'x',246'x',247'x',248'x',249'x'250], 'no clues');251252assertGuess(false, undefined, [253'\tx',254'x',255'x',256'x',257'x',258'x',259'x'260], 'no spaces, 1xTAB');261262assertGuess(true, 2, [263' x',264'x',265'x',266'x',267'x',268'x',269'x'270], '1x2');271272assertGuess(false, undefined, [273'\tx',274'\tx',275'\tx',276'\tx',277'\tx',278'\tx',279'\tx'280], '7xTAB');281282assertGuess(undefined, [2], [283'\tx',284' x',285'\tx',286' x',287'\tx',288' x',289'\tx',290' x',291], '4x2, 4xTAB');292assertGuess(false, undefined, [293'\tx',294' x',295'\tx',296' x',297'\tx',298' x',299'\tx',300' x'301], '4x1, 4xTAB');302assertGuess(false, undefined, [303'\tx',304'\tx',305' x',306'\tx',307' x',308'\tx',309' x',310'\tx',311' x',312], '4x2, 5xTAB');313assertGuess(false, undefined, [314'\tx',315'\tx',316'x',317'\tx',318'x',319'\tx',320'x',321'\tx',322' x',323], '1x2, 5xTAB');324assertGuess(false, undefined, [325'\tx',326'\tx',327'x',328'\tx',329'x',330'\tx',331'x',332'\tx',333' x',334], '1x4, 5xTAB');335assertGuess(false, undefined, [336'\tx',337'\tx',338'x',339'\tx',340'x',341'\tx',342' x',343'\tx',344' x',345], '1x2, 1x4, 5xTAB');346347assertGuess(undefined, undefined, [348'x',349' x',350' x',351' x',352' x',353' x',354' x',355' x'356], '7x1 - 1 space is never guessed as an indentation');357assertGuess(true, undefined, [358'x',359' x',360' x',361' x',362' x',363' x',364' x',365' x'366], '1x10, 6x1');367assertGuess(undefined, undefined, [368'',369' ',370' ',371' ',372' ',373' ',374' ',375' ',376], 'whitespace lines don\'t count');377assertGuess(true, 3, [378'x',379' x',380' x',381' x',382'x',383' x',384' x',385' x',386'x',387' x',388' x',389' x',390], '6x3, 3x4');391assertGuess(true, 5, [392'x',393' x',394' x',395' x',396'x',397' x',398' x',399' x',400'x',401' x',402' x',403' x',404], '6x5, 3x4');405assertGuess(true, 7, [406'x',407' x',408' x',409' x',410'x',411' x',412' x',413' x',414'x',415' x',416' x',417' x',418], '6x7, 1x5, 2x4');419assertGuess(true, 2, [420'x',421' x',422' x',423' x',424' x',425'x',426' x',427' x',428' x',429' x',430], '8x2');431432assertGuess(true, 2, [433'x',434' x',435' x',436'x',437' x',438' x',439'x',440' x',441' x',442'x',443' x',444' x',445], '8x2');446assertGuess(true, 2, [447'x',448' x',449' x',450'x',451' x',452' x',453'x',454' x',455' x',456'x',457' x',458' x',459], '4x2, 4x4');460assertGuess(true, 2, [461'x',462' x',463' x',464' x',465'x',466' x',467' x',468' x',469'x',470' x',471' x',472' x',473], '6x2, 3x4');474assertGuess(true, 2, [475'x',476' x',477' x',478' x',479' x',480'x',481' x',482' x',483' x',484' x',485], '4x2, 4x4');486assertGuess(true, 2, [487'x',488' x',489' x',490' x',491'x',492' x',493' x',494' x',495], '2x2, 4x4');496assertGuess(true, 4, [497'x',498' x',499' x',500'x',501' x',502' x',503'x',504' x',505' x',506'x',507' x',508' x',509], '8x4');510assertGuess(true, 2, [511'x',512' x',513' x',514' x',515' x',516'x',517' x',518' x',519' x',520' x',521], '2x2, 4x4, 2x6');522assertGuess(true, 2, [523'x',524' x',525' x',526' x',527' x',528' x',529' x',530], '1x2, 2x4, 2x6, 1x8');531assertGuess(true, 4, [532'x',533' x',534' x',535' x',536' x',537' x',538'x',539' x',540' x',541' x',542' x',543' x',544], '6x4, 2x5, 2x8');545assertGuess(true, 4, [546'x',547' x',548' x',549' x',550' x',551' x',552' x',553], '3x4, 1x5, 2x8');554assertGuess(true, 4, [555'x',556'x',557' x',558' x',559' x',560' x',561' x',562'x',563'x',564' x',565' x',566' x',567' x',568' x',569], '6x4, 2x5, 4x8');570assertGuess(true, 3, [571'x',572' x',573' x',574' x',575' x',576' x',577'x',578' x',579' x',580' x',581], '5x1, 2x0, 1x3, 2x4');582assertGuess(false, undefined, [583'\t x',584' \t x',585'\tx'586], 'mixed whitespace 1');587assertGuess(false, undefined, [588'\tx',589'\t x'590], 'mixed whitespace 2');591});592593test('issue #44991: Wrong indentation size auto-detection', () => {594assertGuess(true, 4, [595'a = 10 # 0 space indent',596'b = 5 # 0 space indent',597'if a > 10: # 0 space indent',598' a += 1 # 4 space indent delta 4 spaces',599' if b > 5: # 4 space indent',600' b += 1 # 8 space indent delta 4 spaces',601' b += 1 # 8 space indent',602' b += 1 # 8 space indent',603'# comment line 1 # 0 space indent delta 8 spaces',604'# comment line 2 # 0 space indent',605'# comment line 3 # 0 space indent',606' b += 1 # 8 space indent delta 8 spaces',607' b += 1 # 8 space indent',608' b += 1 # 8 space indent',609]);610});611612test('issue #55818: Broken indentation detection', () => {613assertGuess(true, 2, [614'',615'/* REQUIRE */',616'',617'const foo = require ( \'foo\' ),',618' bar = require ( \'bar\' );',619'',620'/* MY FN */',621'',622'function myFn () {',623'',624' const asd = 1,',625' dsa = 2;',626'',627' return bar ( foo ( asd ) );',628'',629'}',630'',631'/* EXPORT */',632'',633'module.exports = myFn;',634'',635]);636});637638test('issue #70832: Broken indentation detection', () => {639assertGuess(false, undefined, [640'x',641'x',642'x',643'x',644' x',645' x',646' x',647' x',648' x',649' x',650' x',651' x',652' x',653' x',654'x',655]);656});657658test('issue #62143: Broken indentation detection', () => {659// works before the fix660assertGuess(true, 2, [661'x',662'x',663' x',664' x'665]);666667// works before the fix668assertGuess(true, 2, [669'x',670' - item2',671' - item3'672]);673674// works before the fix675testGuessIndentation(true, 2, true, 2, [676'x x',677' x',678' x',679]);680681// fails before the fix682// empty space inline breaks the indentation guess683testGuessIndentation(true, 2, true, 2, [684'x x',685' x',686' x',687' x'688]);689690testGuessIndentation(true, 2, true, 2, [691'<!--test1.md -->',692'- item1',693' - item2',694' - item3'695]);696});697698test('issue #84217: Broken indentation detection', () => {699assertGuess(true, 4, [700'def main():',701' print(\'hello\')',702]);703assertGuess(true, 4, [704'def main():',705' with open(\'foo\') as fp:',706' print(fp.read())',707]);708});709710test('validatePosition', () => {711712const m = createTextModel('line one\nline two');713714assert.deepStrictEqual(m.validatePosition(new Position(0, 0)), new Position(1, 1));715assert.deepStrictEqual(m.validatePosition(new Position(0, 1)), new Position(1, 1));716717assert.deepStrictEqual(m.validatePosition(new Position(1, 1)), new Position(1, 1));718assert.deepStrictEqual(m.validatePosition(new Position(1, 2)), new Position(1, 2));719assert.deepStrictEqual(m.validatePosition(new Position(1, 30)), new Position(1, 9));720721assert.deepStrictEqual(m.validatePosition(new Position(2, 0)), new Position(2, 1));722assert.deepStrictEqual(m.validatePosition(new Position(2, 1)), new Position(2, 1));723assert.deepStrictEqual(m.validatePosition(new Position(2, 2)), new Position(2, 2));724assert.deepStrictEqual(m.validatePosition(new Position(2, 30)), new Position(2, 9));725726assert.deepStrictEqual(m.validatePosition(new Position(3, 0)), new Position(2, 9));727assert.deepStrictEqual(m.validatePosition(new Position(3, 1)), new Position(2, 9));728assert.deepStrictEqual(m.validatePosition(new Position(3, 30)), new Position(2, 9));729730assert.deepStrictEqual(m.validatePosition(new Position(30, 30)), new Position(2, 9));731732assert.deepStrictEqual(m.validatePosition(new Position(-123.123, -0.5)), new Position(1, 1));733assert.deepStrictEqual(m.validatePosition(new Position(Number.MIN_VALUE, Number.MIN_VALUE)), new Position(1, 1));734735assert.deepStrictEqual(m.validatePosition(new Position(Number.MAX_VALUE, Number.MAX_VALUE)), new Position(2, 9));736assert.deepStrictEqual(m.validatePosition(new Position(123.23, 47.5)), new Position(2, 9));737738m.dispose();739});740741test('validatePosition around high-low surrogate pairs 1', () => {742743const m = createTextModel('a📚b');744745assert.deepStrictEqual(m.validatePosition(new Position(0, 0)), new Position(1, 1));746assert.deepStrictEqual(m.validatePosition(new Position(0, 1)), new Position(1, 1));747assert.deepStrictEqual(m.validatePosition(new Position(0, 7)), new Position(1, 1));748749assert.deepStrictEqual(m.validatePosition(new Position(1, 1)), new Position(1, 1));750assert.deepStrictEqual(m.validatePosition(new Position(1, 2)), new Position(1, 2));751assert.deepStrictEqual(m.validatePosition(new Position(1, 3)), new Position(1, 2));752assert.deepStrictEqual(m.validatePosition(new Position(1, 4)), new Position(1, 4));753assert.deepStrictEqual(m.validatePosition(new Position(1, 5)), new Position(1, 5));754assert.deepStrictEqual(m.validatePosition(new Position(1, 30)), new Position(1, 5));755756assert.deepStrictEqual(m.validatePosition(new Position(2, 0)), new Position(1, 5));757assert.deepStrictEqual(m.validatePosition(new Position(2, 1)), new Position(1, 5));758assert.deepStrictEqual(m.validatePosition(new Position(2, 2)), new Position(1, 5));759assert.deepStrictEqual(m.validatePosition(new Position(2, 30)), new Position(1, 5));760761assert.deepStrictEqual(m.validatePosition(new Position(-123.123, -0.5)), new Position(1, 1));762assert.deepStrictEqual(m.validatePosition(new Position(Number.MIN_VALUE, Number.MIN_VALUE)), new Position(1, 1));763764assert.deepStrictEqual(m.validatePosition(new Position(Number.MAX_VALUE, Number.MAX_VALUE)), new Position(1, 5));765assert.deepStrictEqual(m.validatePosition(new Position(123.23, 47.5)), new Position(1, 5));766767m.dispose();768});769770test('validatePosition around high-low surrogate pairs 2', () => {771772const m = createTextModel('a📚📚b');773774assert.deepStrictEqual(m.validatePosition(new Position(1, 1)), new Position(1, 1));775assert.deepStrictEqual(m.validatePosition(new Position(1, 2)), new Position(1, 2));776assert.deepStrictEqual(m.validatePosition(new Position(1, 3)), new Position(1, 2));777assert.deepStrictEqual(m.validatePosition(new Position(1, 4)), new Position(1, 4));778assert.deepStrictEqual(m.validatePosition(new Position(1, 5)), new Position(1, 4));779assert.deepStrictEqual(m.validatePosition(new Position(1, 6)), new Position(1, 6));780assert.deepStrictEqual(m.validatePosition(new Position(1, 7)), new Position(1, 7));781782m.dispose();783784});785786test('validatePosition handle NaN.', () => {787788const m = createTextModel('line one\nline two');789790assert.deepStrictEqual(m.validatePosition(new Position(NaN, 1)), new Position(1, 1));791assert.deepStrictEqual(m.validatePosition(new Position(1, NaN)), new Position(1, 1));792793assert.deepStrictEqual(m.validatePosition(new Position(NaN, NaN)), new Position(1, 1));794assert.deepStrictEqual(m.validatePosition(new Position(2, NaN)), new Position(2, 1));795assert.deepStrictEqual(m.validatePosition(new Position(NaN, 3)), new Position(1, 3));796797m.dispose();798});799800test('issue #71480: validatePosition handle floats', () => {801const m = createTextModel('line one\nline two');802803assert.deepStrictEqual(m.validatePosition(new Position(0.2, 1)), new Position(1, 1), 'a');804assert.deepStrictEqual(m.validatePosition(new Position(1.2, 1)), new Position(1, 1), 'b');805assert.deepStrictEqual(m.validatePosition(new Position(1.5, 2)), new Position(1, 2), 'c');806assert.deepStrictEqual(m.validatePosition(new Position(1.8, 3)), new Position(1, 3), 'd');807assert.deepStrictEqual(m.validatePosition(new Position(1, 0.3)), new Position(1, 1), 'e');808assert.deepStrictEqual(m.validatePosition(new Position(2, 0.8)), new Position(2, 1), 'f');809assert.deepStrictEqual(m.validatePosition(new Position(1, 1.2)), new Position(1, 1), 'g');810assert.deepStrictEqual(m.validatePosition(new Position(2, 1.5)), new Position(2, 1), 'h');811812m.dispose();813});814815test('issue #71480: validateRange handle floats', () => {816const m = createTextModel('line one\nline two');817818assert.deepStrictEqual(m.validateRange(new Range(0.2, 1.5, 0.8, 2.5)), new Range(1, 1, 1, 1));819assert.deepStrictEqual(m.validateRange(new Range(1.2, 1.7, 1.8, 2.2)), new Range(1, 1, 1, 2));820821m.dispose();822});823824test('validateRange around high-low surrogate pairs 1', () => {825826const m = createTextModel('a📚b');827828assert.deepStrictEqual(m.validateRange(new Range(0, 0, 0, 1)), new Range(1, 1, 1, 1));829assert.deepStrictEqual(m.validateRange(new Range(0, 0, 0, 7)), new Range(1, 1, 1, 1));830831assert.deepStrictEqual(m.validateRange(new Range(1, 1, 1, 1)), new Range(1, 1, 1, 1));832assert.deepStrictEqual(m.validateRange(new Range(1, 1, 1, 2)), new Range(1, 1, 1, 2));833assert.deepStrictEqual(m.validateRange(new Range(1, 1, 1, 3)), new Range(1, 1, 1, 4));834assert.deepStrictEqual(m.validateRange(new Range(1, 1, 1, 4)), new Range(1, 1, 1, 4));835assert.deepStrictEqual(m.validateRange(new Range(1, 1, 1, 5)), new Range(1, 1, 1, 5));836837assert.deepStrictEqual(m.validateRange(new Range(1, 2, 1, 2)), new Range(1, 2, 1, 2));838assert.deepStrictEqual(m.validateRange(new Range(1, 2, 1, 3)), new Range(1, 2, 1, 4));839assert.deepStrictEqual(m.validateRange(new Range(1, 2, 1, 4)), new Range(1, 2, 1, 4));840assert.deepStrictEqual(m.validateRange(new Range(1, 2, 1, 5)), new Range(1, 2, 1, 5));841842assert.deepStrictEqual(m.validateRange(new Range(1, 3, 1, 3)), new Range(1, 2, 1, 2));843assert.deepStrictEqual(m.validateRange(new Range(1, 3, 1, 4)), new Range(1, 2, 1, 4));844assert.deepStrictEqual(m.validateRange(new Range(1, 3, 1, 5)), new Range(1, 2, 1, 5));845846assert.deepStrictEqual(m.validateRange(new Range(1, 4, 1, 4)), new Range(1, 4, 1, 4));847assert.deepStrictEqual(m.validateRange(new Range(1, 4, 1, 5)), new Range(1, 4, 1, 5));848849assert.deepStrictEqual(m.validateRange(new Range(1, 5, 1, 5)), new Range(1, 5, 1, 5));850851m.dispose();852});853854test('validateRange around high-low surrogate pairs 2', () => {855856const m = createTextModel('a📚📚b');857858assert.deepStrictEqual(m.validateRange(new Range(0, 0, 0, 1)), new Range(1, 1, 1, 1));859assert.deepStrictEqual(m.validateRange(new Range(0, 0, 0, 7)), new Range(1, 1, 1, 1));860861assert.deepStrictEqual(m.validateRange(new Range(1, 1, 1, 1)), new Range(1, 1, 1, 1));862assert.deepStrictEqual(m.validateRange(new Range(1, 1, 1, 2)), new Range(1, 1, 1, 2));863assert.deepStrictEqual(m.validateRange(new Range(1, 1, 1, 3)), new Range(1, 1, 1, 4));864assert.deepStrictEqual(m.validateRange(new Range(1, 1, 1, 4)), new Range(1, 1, 1, 4));865assert.deepStrictEqual(m.validateRange(new Range(1, 1, 1, 5)), new Range(1, 1, 1, 6));866assert.deepStrictEqual(m.validateRange(new Range(1, 1, 1, 6)), new Range(1, 1, 1, 6));867assert.deepStrictEqual(m.validateRange(new Range(1, 1, 1, 7)), new Range(1, 1, 1, 7));868869assert.deepStrictEqual(m.validateRange(new Range(1, 2, 1, 2)), new Range(1, 2, 1, 2));870assert.deepStrictEqual(m.validateRange(new Range(1, 2, 1, 3)), new Range(1, 2, 1, 4));871assert.deepStrictEqual(m.validateRange(new Range(1, 2, 1, 4)), new Range(1, 2, 1, 4));872assert.deepStrictEqual(m.validateRange(new Range(1, 2, 1, 5)), new Range(1, 2, 1, 6));873assert.deepStrictEqual(m.validateRange(new Range(1, 2, 1, 6)), new Range(1, 2, 1, 6));874assert.deepStrictEqual(m.validateRange(new Range(1, 2, 1, 7)), new Range(1, 2, 1, 7));875876assert.deepStrictEqual(m.validateRange(new Range(1, 3, 1, 3)), new Range(1, 2, 1, 2));877assert.deepStrictEqual(m.validateRange(new Range(1, 3, 1, 4)), new Range(1, 2, 1, 4));878assert.deepStrictEqual(m.validateRange(new Range(1, 3, 1, 5)), new Range(1, 2, 1, 6));879assert.deepStrictEqual(m.validateRange(new Range(1, 3, 1, 6)), new Range(1, 2, 1, 6));880assert.deepStrictEqual(m.validateRange(new Range(1, 3, 1, 7)), new Range(1, 2, 1, 7));881882assert.deepStrictEqual(m.validateRange(new Range(1, 4, 1, 4)), new Range(1, 4, 1, 4));883assert.deepStrictEqual(m.validateRange(new Range(1, 4, 1, 5)), new Range(1, 4, 1, 6));884assert.deepStrictEqual(m.validateRange(new Range(1, 4, 1, 6)), new Range(1, 4, 1, 6));885assert.deepStrictEqual(m.validateRange(new Range(1, 4, 1, 7)), new Range(1, 4, 1, 7));886887assert.deepStrictEqual(m.validateRange(new Range(1, 5, 1, 5)), new Range(1, 4, 1, 4));888assert.deepStrictEqual(m.validateRange(new Range(1, 5, 1, 6)), new Range(1, 4, 1, 6));889assert.deepStrictEqual(m.validateRange(new Range(1, 5, 1, 7)), new Range(1, 4, 1, 7));890891assert.deepStrictEqual(m.validateRange(new Range(1, 6, 1, 6)), new Range(1, 6, 1, 6));892assert.deepStrictEqual(m.validateRange(new Range(1, 6, 1, 7)), new Range(1, 6, 1, 7));893894assert.deepStrictEqual(m.validateRange(new Range(1, 7, 1, 7)), new Range(1, 7, 1, 7));895896m.dispose();897});898899test('modifyPosition', () => {900901const m = createTextModel('line one\nline two');902assert.deepStrictEqual(m.modifyPosition(new Position(1, 1), 0), new Position(1, 1));903assert.deepStrictEqual(m.modifyPosition(new Position(0, 0), 0), new Position(1, 1));904assert.deepStrictEqual(m.modifyPosition(new Position(30, 1), 0), new Position(2, 9));905906assert.deepStrictEqual(m.modifyPosition(new Position(1, 1), 17), new Position(2, 9));907assert.deepStrictEqual(m.modifyPosition(new Position(1, 1), 1), new Position(1, 2));908assert.deepStrictEqual(m.modifyPosition(new Position(1, 1), 3), new Position(1, 4));909assert.deepStrictEqual(m.modifyPosition(new Position(1, 2), 10), new Position(2, 3));910assert.deepStrictEqual(m.modifyPosition(new Position(1, 5), 13), new Position(2, 9));911assert.deepStrictEqual(m.modifyPosition(new Position(1, 2), 16), new Position(2, 9));912913assert.deepStrictEqual(m.modifyPosition(new Position(2, 9), -17), new Position(1, 1));914assert.deepStrictEqual(m.modifyPosition(new Position(1, 2), -1), new Position(1, 1));915assert.deepStrictEqual(m.modifyPosition(new Position(1, 4), -3), new Position(1, 1));916assert.deepStrictEqual(m.modifyPosition(new Position(2, 3), -10), new Position(1, 2));917assert.deepStrictEqual(m.modifyPosition(new Position(2, 9), -13), new Position(1, 5));918assert.deepStrictEqual(m.modifyPosition(new Position(2, 9), -16), new Position(1, 2));919920assert.deepStrictEqual(m.modifyPosition(new Position(1, 2), 17), new Position(2, 9));921assert.deepStrictEqual(m.modifyPosition(new Position(1, 2), 100), new Position(2, 9));922923assert.deepStrictEqual(m.modifyPosition(new Position(1, 2), -2), new Position(1, 1));924assert.deepStrictEqual(m.modifyPosition(new Position(1, 2), -100), new Position(1, 1));925assert.deepStrictEqual(m.modifyPosition(new Position(2, 2), -100), new Position(1, 1));926assert.deepStrictEqual(m.modifyPosition(new Position(2, 9), -18), new Position(1, 1));927928m.dispose();929});930931test('normalizeIndentation 1', () => {932const model = createTextModel('',933undefined,934{935insertSpaces: false936}937);938939assert.strictEqual(model.normalizeIndentation('\t'), '\t');940assert.strictEqual(model.normalizeIndentation(' '), '\t');941assert.strictEqual(model.normalizeIndentation(' '), ' ');942assert.strictEqual(model.normalizeIndentation(' '), ' ');943assert.strictEqual(model.normalizeIndentation(' '), ' ');944assert.strictEqual(model.normalizeIndentation(''), '');945assert.strictEqual(model.normalizeIndentation(' \t '), '\t\t');946assert.strictEqual(model.normalizeIndentation(' \t '), '\t ');947assert.strictEqual(model.normalizeIndentation(' \t '), '\t ');948assert.strictEqual(model.normalizeIndentation(' \t '), '\t ');949assert.strictEqual(model.normalizeIndentation(' \t'), '\t');950951assert.strictEqual(model.normalizeIndentation('\ta'), '\ta');952assert.strictEqual(model.normalizeIndentation(' a'), '\ta');953assert.strictEqual(model.normalizeIndentation(' a'), ' a');954assert.strictEqual(model.normalizeIndentation(' a'), ' a');955assert.strictEqual(model.normalizeIndentation(' a'), ' a');956assert.strictEqual(model.normalizeIndentation('a'), 'a');957assert.strictEqual(model.normalizeIndentation(' \t a'), '\t\ta');958assert.strictEqual(model.normalizeIndentation(' \t a'), '\t a');959assert.strictEqual(model.normalizeIndentation(' \t a'), '\t a');960assert.strictEqual(model.normalizeIndentation(' \t a'), '\t a');961assert.strictEqual(model.normalizeIndentation(' \ta'), '\ta');962963model.dispose();964});965966test('normalizeIndentation 2', () => {967const model = createTextModel('');968969assert.strictEqual(model.normalizeIndentation('\ta'), ' a');970assert.strictEqual(model.normalizeIndentation(' a'), ' a');971assert.strictEqual(model.normalizeIndentation(' a'), ' a');972assert.strictEqual(model.normalizeIndentation(' a'), ' a');973assert.strictEqual(model.normalizeIndentation(' a'), ' a');974assert.strictEqual(model.normalizeIndentation('a'), 'a');975assert.strictEqual(model.normalizeIndentation(' \t a'), ' a');976assert.strictEqual(model.normalizeIndentation(' \t a'), ' a');977assert.strictEqual(model.normalizeIndentation(' \t a'), ' a');978assert.strictEqual(model.normalizeIndentation(' \t a'), ' a');979assert.strictEqual(model.normalizeIndentation(' \ta'), ' a');980981model.dispose();982});983984test('getLineFirstNonWhitespaceColumn', () => {985const model = createTextModel([986'asd',987' asd',988'\tasd',989' asd',990'\t\tasd',991' ',992' ',993'\t',994'\t\t',995' \tasd',996'',997''998].join('\n'));9991000assert.strictEqual(model.getLineFirstNonWhitespaceColumn(1), 1, '1');1001assert.strictEqual(model.getLineFirstNonWhitespaceColumn(2), 2, '2');1002assert.strictEqual(model.getLineFirstNonWhitespaceColumn(3), 2, '3');1003assert.strictEqual(model.getLineFirstNonWhitespaceColumn(4), 3, '4');1004assert.strictEqual(model.getLineFirstNonWhitespaceColumn(5), 3, '5');1005assert.strictEqual(model.getLineFirstNonWhitespaceColumn(6), 0, '6');1006assert.strictEqual(model.getLineFirstNonWhitespaceColumn(7), 0, '7');1007assert.strictEqual(model.getLineFirstNonWhitespaceColumn(8), 0, '8');1008assert.strictEqual(model.getLineFirstNonWhitespaceColumn(9), 0, '9');1009assert.strictEqual(model.getLineFirstNonWhitespaceColumn(10), 4, '10');1010assert.strictEqual(model.getLineFirstNonWhitespaceColumn(11), 0, '11');1011assert.strictEqual(model.getLineFirstNonWhitespaceColumn(12), 0, '12');10121013model.dispose();1014});10151016test('getLineLastNonWhitespaceColumn', () => {1017const model = createTextModel([1018'asd',1019'asd ',1020'asd\t',1021'asd ',1022'asd\t\t',1023' ',1024' ',1025'\t',1026'\t\t',1027'asd \t',1028'',1029''1030].join('\n'));10311032assert.strictEqual(model.getLineLastNonWhitespaceColumn(1), 4, '1');1033assert.strictEqual(model.getLineLastNonWhitespaceColumn(2), 4, '2');1034assert.strictEqual(model.getLineLastNonWhitespaceColumn(3), 4, '3');1035assert.strictEqual(model.getLineLastNonWhitespaceColumn(4), 4, '4');1036assert.strictEqual(model.getLineLastNonWhitespaceColumn(5), 4, '5');1037assert.strictEqual(model.getLineLastNonWhitespaceColumn(6), 0, '6');1038assert.strictEqual(model.getLineLastNonWhitespaceColumn(7), 0, '7');1039assert.strictEqual(model.getLineLastNonWhitespaceColumn(8), 0, '8');1040assert.strictEqual(model.getLineLastNonWhitespaceColumn(9), 0, '9');1041assert.strictEqual(model.getLineLastNonWhitespaceColumn(10), 4, '10');1042assert.strictEqual(model.getLineLastNonWhitespaceColumn(11), 0, '11');1043assert.strictEqual(model.getLineLastNonWhitespaceColumn(12), 0, '12');10441045model.dispose();1046});10471048test('#50471. getValueInRange with invalid range', () => {1049const m = createTextModel('My First Line\r\nMy Second Line\r\nMy Third Line');1050assert.strictEqual(m.getValueInRange(new Range(1, NaN, 1, 3)), 'My');1051assert.strictEqual(m.getValueInRange(new Range(NaN, NaN, NaN, NaN)), '');1052m.dispose();1053});10541055test('issue #168836: updating tabSize should also update indentSize when indentSize is set to "tabSize"', () => {1056const m = createTextModel('some text', null, {1057tabSize: 2,1058indentSize: 'tabSize'1059});1060assert.strictEqual(m.getOptions().tabSize, 2);1061assert.strictEqual(m.getOptions().indentSize, 2);1062assert.strictEqual(m.getOptions().originalIndentSize, 'tabSize');1063m.updateOptions({1064tabSize: 41065});1066assert.strictEqual(m.getOptions().tabSize, 4);1067assert.strictEqual(m.getOptions().indentSize, 4);1068assert.strictEqual(m.getOptions().originalIndentSize, 'tabSize');1069m.dispose();1070});1071});10721073suite('TextModel.mightContainRTL', () => {10741075ensureNoDisposablesAreLeakedInTestSuite();10761077test('nope', () => {1078const model = createTextModel('hello world!');1079assert.strictEqual(model.mightContainRTL(), false);1080model.dispose();1081});10821083test('yes', () => {1084const model = createTextModel('Hello,\nזוהי עובדה מבוססת שדעתו');1085assert.strictEqual(model.mightContainRTL(), true);1086model.dispose();1087});10881089test('setValue resets 1', () => {1090const model = createTextModel('hello world!');1091assert.strictEqual(model.mightContainRTL(), false);1092model.setValue('Hello,\nזוהי עובדה מבוססת שדעתו');1093assert.strictEqual(model.mightContainRTL(), true);1094model.dispose();1095});10961097test('setValue resets 2', () => {1098const model = createTextModel('Hello,\nهناك حقيقة مثبتة منذ زمن طويل');1099assert.strictEqual(model.mightContainRTL(), true);1100model.setValue('hello world!');1101assert.strictEqual(model.mightContainRTL(), false);1102model.dispose();1103});11041105});11061107suite('TextModel.createSnapshot', () => {11081109ensureNoDisposablesAreLeakedInTestSuite();11101111test('empty file', () => {1112const model = createTextModel('');1113const snapshot = model.createSnapshot();1114assert.strictEqual(snapshot.read(), null);1115model.dispose();1116});11171118test('file with BOM', () => {1119const model = createTextModel(UTF8_BOM_CHARACTER + 'Hello');1120assert.strictEqual(model.getLineContent(1), 'Hello');1121const snapshot = model.createSnapshot(true);1122assert.strictEqual(snapshot.read(), UTF8_BOM_CHARACTER + 'Hello');1123assert.strictEqual(snapshot.read(), null);1124model.dispose();1125});11261127test('regular file', () => {1128const model = createTextModel('My First Line\n\t\tMy Second Line\n Third Line\n\n1');1129const snapshot = model.createSnapshot();1130assert.strictEqual(snapshot.read(), 'My First Line\n\t\tMy Second Line\n Third Line\n\n1');1131assert.strictEqual(snapshot.read(), null);1132model.dispose();1133});11341135test('large file', () => {1136const lines: string[] = [];1137for (let i = 0; i < 1000; i++) {1138lines[i] = 'Just some text that is a bit long such that it can consume some memory';1139}1140const text = lines.join('\n');11411142const model = createTextModel(text);1143const snapshot = model.createSnapshot();1144let actual = '';11451146// 70999 length => at most 2 read calls are necessary1147const tmp1 = snapshot.read();1148assert.ok(tmp1);1149actual += tmp1;11501151const tmp2 = snapshot.read();1152if (tmp2 === null) {1153// all good1154} else {1155actual += tmp2;1156assert.strictEqual(snapshot.read(), null);1157}11581159assert.strictEqual(actual, text);11601161model.dispose();1162});11631164test('issue #119632: invalid range', () => {1165const model = createTextModel('hello world!');1166const actual = model._validateRangeRelaxedNoAllocations(new Range(<any>undefined, 0, <any>undefined, 1));1167assert.deepStrictEqual(actual, new Range(1, 1, 1, 1));1168model.dispose();1169});11701171});117211731174