Path: blob/main/src/vs/editor/test/common/model/model.modes.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 { EditOperation } from '../../../common/core/editOperation.js';9import { Position } from '../../../common/core/position.js';10import { Range } from '../../../common/core/range.js';11import * as languages from '../../../common/languages.js';12import { NullState } from '../../../common/languages/nullTokenize.js';13import { TextModel } from '../../../common/model/textModel.js';14import { createTextModel } from '../testTextModel.js';1516// --------- utils1718suite('Editor Model - Model Modes 1', () => {1920let calledFor: string[] = [];2122function getAndClear(): string[] {23const result = calledFor;24calledFor = [];25return result;26}2728const tokenizationSupport: languages.ITokenizationSupport = {29getInitialState: () => NullState,30tokenize: undefined!,31tokenizeEncoded: (line: string, hasEOL: boolean, state: languages.IState): languages.EncodedTokenizationResult => {32calledFor.push(line.charAt(0));33return new languages.EncodedTokenizationResult(new Uint32Array(0), state);34}35};3637let thisModel: TextModel;38let languageRegistration: IDisposable;3940setup(() => {41const TEXT =42'1\r\n' +43'2\n' +44'3\n' +45'4\r\n' +46'5';47const LANGUAGE_ID = 'modelModeTest1';48calledFor = [];49languageRegistration = languages.TokenizationRegistry.register(LANGUAGE_ID, tokenizationSupport);50thisModel = createTextModel(TEXT, LANGUAGE_ID);51});5253teardown(() => {54thisModel.dispose();55languageRegistration.dispose();56calledFor = [];57});5859ensureNoDisposablesAreLeakedInTestSuite();6061test('model calls syntax highlighter 1', () => {62thisModel.tokenization.forceTokenization(1);63assert.deepStrictEqual(getAndClear(), ['1']);64});6566test('model calls syntax highlighter 2', () => {67thisModel.tokenization.forceTokenization(2);68assert.deepStrictEqual(getAndClear(), ['1', '2']);6970thisModel.tokenization.forceTokenization(2);71assert.deepStrictEqual(getAndClear(), []);72});7374test('model caches states', () => {75thisModel.tokenization.forceTokenization(1);76assert.deepStrictEqual(getAndClear(), ['1']);7778thisModel.tokenization.forceTokenization(2);79assert.deepStrictEqual(getAndClear(), ['2']);8081thisModel.tokenization.forceTokenization(3);82assert.deepStrictEqual(getAndClear(), ['3']);8384thisModel.tokenization.forceTokenization(4);85assert.deepStrictEqual(getAndClear(), ['4']);8687thisModel.tokenization.forceTokenization(5);88assert.deepStrictEqual(getAndClear(), ['5']);8990thisModel.tokenization.forceTokenization(5);91assert.deepStrictEqual(getAndClear(), []);92});9394test('model invalidates states for one line insert', () => {95thisModel.tokenization.forceTokenization(5);96assert.deepStrictEqual(getAndClear(), ['1', '2', '3', '4', '5']);9798thisModel.applyEdits([EditOperation.insert(new Position(1, 1), '-')]);99thisModel.tokenization.forceTokenization(5);100assert.deepStrictEqual(getAndClear(), ['-']);101102thisModel.tokenization.forceTokenization(5);103assert.deepStrictEqual(getAndClear(), []);104});105106test('model invalidates states for many lines insert', () => {107thisModel.tokenization.forceTokenization(5);108assert.deepStrictEqual(getAndClear(), ['1', '2', '3', '4', '5']);109110thisModel.applyEdits([EditOperation.insert(new Position(1, 1), '0\n-\n+')]);111assert.strictEqual(thisModel.getLineCount(), 7);112thisModel.tokenization.forceTokenization(7);113assert.deepStrictEqual(getAndClear(), ['0', '-', '+']);114115thisModel.tokenization.forceTokenization(7);116assert.deepStrictEqual(getAndClear(), []);117});118119test('model invalidates states for one new line', () => {120thisModel.tokenization.forceTokenization(5);121assert.deepStrictEqual(getAndClear(), ['1', '2', '3', '4', '5']);122123thisModel.applyEdits([EditOperation.insert(new Position(1, 2), '\n')]);124thisModel.applyEdits([EditOperation.insert(new Position(2, 1), 'a')]);125thisModel.tokenization.forceTokenization(6);126assert.deepStrictEqual(getAndClear(), ['1', 'a']);127});128129test('model invalidates states for one line delete', () => {130thisModel.tokenization.forceTokenization(5);131assert.deepStrictEqual(getAndClear(), ['1', '2', '3', '4', '5']);132133thisModel.applyEdits([EditOperation.insert(new Position(1, 2), '-')]);134thisModel.tokenization.forceTokenization(5);135assert.deepStrictEqual(getAndClear(), ['1']);136137thisModel.applyEdits([EditOperation.delete(new Range(1, 1, 1, 2))]);138thisModel.tokenization.forceTokenization(5);139assert.deepStrictEqual(getAndClear(), ['-']);140141thisModel.tokenization.forceTokenization(5);142assert.deepStrictEqual(getAndClear(), []);143});144145test('model invalidates states for many lines delete', () => {146thisModel.tokenization.forceTokenization(5);147assert.deepStrictEqual(getAndClear(), ['1', '2', '3', '4', '5']);148149thisModel.applyEdits([EditOperation.delete(new Range(1, 1, 3, 1))]);150thisModel.tokenization.forceTokenization(3);151assert.deepStrictEqual(getAndClear(), ['3']);152153thisModel.tokenization.forceTokenization(3);154assert.deepStrictEqual(getAndClear(), []);155});156});157158suite('Editor Model - Model Modes 2', () => {159160class ModelState2 implements languages.IState {161prevLineContent: string;162163constructor(prevLineContent: string) {164this.prevLineContent = prevLineContent;165}166167clone(): languages.IState {168return new ModelState2(this.prevLineContent);169}170171equals(other: languages.IState): boolean {172return (other instanceof ModelState2) && other.prevLineContent === this.prevLineContent;173}174}175176let calledFor: string[] = [];177178function getAndClear(): string[] {179const actual = calledFor;180calledFor = [];181return actual;182}183184const tokenizationSupport: languages.ITokenizationSupport = {185getInitialState: () => new ModelState2(''),186tokenize: undefined!,187tokenizeEncoded: (line: string, hasEOL: boolean, state: languages.IState): languages.EncodedTokenizationResult => {188calledFor.push(line);189(<ModelState2>state).prevLineContent = line;190return new languages.EncodedTokenizationResult(new Uint32Array(0), state);191}192};193194let thisModel: TextModel;195let languageRegistration: IDisposable;196197setup(() => {198const TEXT =199'Line1' + '\r\n' +200'Line2' + '\n' +201'Line3' + '\n' +202'Line4' + '\r\n' +203'Line5';204const LANGUAGE_ID = 'modelModeTest2';205languageRegistration = languages.TokenizationRegistry.register(LANGUAGE_ID, tokenizationSupport);206thisModel = createTextModel(TEXT, LANGUAGE_ID);207});208209teardown(() => {210thisModel.dispose();211languageRegistration.dispose();212});213214ensureNoDisposablesAreLeakedInTestSuite();215216test('getTokensForInvalidLines one text insert', () => {217thisModel.tokenization.forceTokenization(5);218assert.deepStrictEqual(getAndClear(), ['Line1', 'Line2', 'Line3', 'Line4', 'Line5']);219thisModel.applyEdits([EditOperation.insert(new Position(1, 6), '-')]);220thisModel.tokenization.forceTokenization(5);221assert.deepStrictEqual(getAndClear(), ['Line1-', 'Line2']);222});223224test('getTokensForInvalidLines two text insert', () => {225thisModel.tokenization.forceTokenization(5);226assert.deepStrictEqual(getAndClear(), ['Line1', 'Line2', 'Line3', 'Line4', 'Line5']);227thisModel.applyEdits([228EditOperation.insert(new Position(1, 6), '-'),229EditOperation.insert(new Position(3, 6), '-')230]);231232thisModel.tokenization.forceTokenization(5);233assert.deepStrictEqual(getAndClear(), ['Line1-', 'Line2', 'Line3-', 'Line4']);234});235236test('getTokensForInvalidLines one multi-line text insert, one small text insert', () => {237thisModel.tokenization.forceTokenization(5);238assert.deepStrictEqual(getAndClear(), ['Line1', 'Line2', 'Line3', 'Line4', 'Line5']);239thisModel.applyEdits([EditOperation.insert(new Position(1, 6), '\nNew line\nAnother new line')]);240thisModel.applyEdits([EditOperation.insert(new Position(5, 6), '-')]);241thisModel.tokenization.forceTokenization(7);242assert.deepStrictEqual(getAndClear(), ['Line1', 'New line', 'Another new line', 'Line2', 'Line3-', 'Line4']);243});244245test('getTokensForInvalidLines one delete text', () => {246thisModel.tokenization.forceTokenization(5);247assert.deepStrictEqual(getAndClear(), ['Line1', 'Line2', 'Line3', 'Line4', 'Line5']);248thisModel.applyEdits([EditOperation.delete(new Range(1, 1, 1, 5))]);249thisModel.tokenization.forceTokenization(5);250assert.deepStrictEqual(getAndClear(), ['1', 'Line2']);251});252253test('getTokensForInvalidLines one line delete text', () => {254thisModel.tokenization.forceTokenization(5);255assert.deepStrictEqual(getAndClear(), ['Line1', 'Line2', 'Line3', 'Line4', 'Line5']);256thisModel.applyEdits([EditOperation.delete(new Range(1, 1, 2, 1))]);257thisModel.tokenization.forceTokenization(4);258assert.deepStrictEqual(getAndClear(), ['Line2']);259});260261test('getTokensForInvalidLines multiple lines delete text', () => {262thisModel.tokenization.forceTokenization(5);263assert.deepStrictEqual(getAndClear(), ['Line1', 'Line2', 'Line3', 'Line4', 'Line5']);264thisModel.applyEdits([EditOperation.delete(new Range(1, 1, 3, 3))]);265thisModel.tokenization.forceTokenization(3);266assert.deepStrictEqual(getAndClear(), ['ne3', 'Line4']);267});268});269270271