mirror of
https://github.com/microsoft/vscode.git
synced 2026-05-08 09:08:48 +01:00
264 lines
7.9 KiB
TypeScript
264 lines
7.9 KiB
TypeScript
/*---------------------------------------------------------------------------------------------
|
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
*--------------------------------------------------------------------------------------------*/
|
|
|
|
import * as assert from 'assert';
|
|
import { IDisposable } from 'vs/base/common/lifecycle';
|
|
import { EditOperation } from 'vs/editor/common/core/editOperation';
|
|
import { Position } from 'vs/editor/common/core/position';
|
|
import { Range } from 'vs/editor/common/core/range';
|
|
import { EncodedTokenizationResult } from 'vs/editor/common/languages/token';
|
|
import { TextModel } from 'vs/editor/common/model/textModel';
|
|
import * as modes from 'vs/editor/common/languages';
|
|
import { NullState } from 'vs/editor/common/languages/nullMode';
|
|
import { createTextModel } from 'vs/editor/test/common/testTextModel';
|
|
|
|
// --------- utils
|
|
|
|
suite('Editor Model - Model Modes 1', () => {
|
|
|
|
let calledFor: string[] = [];
|
|
|
|
function checkAndClear(arr: string[]) {
|
|
assert.deepStrictEqual(calledFor, arr);
|
|
calledFor = [];
|
|
}
|
|
|
|
const tokenizationSupport: modes.ITokenizationSupport = {
|
|
getInitialState: () => NullState,
|
|
tokenize: undefined!,
|
|
tokenizeEncoded: (line: string, hasEOL: boolean, state: modes.IState): EncodedTokenizationResult => {
|
|
calledFor.push(line.charAt(0));
|
|
return new EncodedTokenizationResult(new Uint32Array(0), state);
|
|
}
|
|
};
|
|
|
|
let thisModel: TextModel;
|
|
let languageRegistration: IDisposable;
|
|
|
|
setup(() => {
|
|
const TEXT =
|
|
'1\r\n' +
|
|
'2\n' +
|
|
'3\n' +
|
|
'4\r\n' +
|
|
'5';
|
|
const LANGUAGE_ID = 'modelModeTest1';
|
|
calledFor = [];
|
|
languageRegistration = modes.TokenizationRegistry.register(LANGUAGE_ID, tokenizationSupport);
|
|
thisModel = createTextModel(TEXT, LANGUAGE_ID);
|
|
});
|
|
|
|
teardown(() => {
|
|
thisModel.dispose();
|
|
languageRegistration.dispose();
|
|
calledFor = [];
|
|
});
|
|
|
|
test('model calls syntax highlighter 1', () => {
|
|
thisModel.forceTokenization(1);
|
|
checkAndClear(['1']);
|
|
});
|
|
|
|
test('model calls syntax highlighter 2', () => {
|
|
thisModel.forceTokenization(2);
|
|
checkAndClear(['1', '2']);
|
|
|
|
thisModel.forceTokenization(2);
|
|
checkAndClear([]);
|
|
});
|
|
|
|
test('model caches states', () => {
|
|
thisModel.forceTokenization(1);
|
|
checkAndClear(['1']);
|
|
|
|
thisModel.forceTokenization(2);
|
|
checkAndClear(['2']);
|
|
|
|
thisModel.forceTokenization(3);
|
|
checkAndClear(['3']);
|
|
|
|
thisModel.forceTokenization(4);
|
|
checkAndClear(['4']);
|
|
|
|
thisModel.forceTokenization(5);
|
|
checkAndClear(['5']);
|
|
|
|
thisModel.forceTokenization(5);
|
|
checkAndClear([]);
|
|
});
|
|
|
|
test('model invalidates states for one line insert', () => {
|
|
thisModel.forceTokenization(5);
|
|
checkAndClear(['1', '2', '3', '4', '5']);
|
|
|
|
thisModel.applyEdits([EditOperation.insert(new Position(1, 1), '-')]);
|
|
thisModel.forceTokenization(5);
|
|
checkAndClear(['-']);
|
|
|
|
thisModel.forceTokenization(5);
|
|
checkAndClear([]);
|
|
});
|
|
|
|
test('model invalidates states for many lines insert', () => {
|
|
thisModel.forceTokenization(5);
|
|
checkAndClear(['1', '2', '3', '4', '5']);
|
|
|
|
thisModel.applyEdits([EditOperation.insert(new Position(1, 1), '0\n-\n+')]);
|
|
assert.strictEqual(thisModel.getLineCount(), 7);
|
|
thisModel.forceTokenization(7);
|
|
checkAndClear(['0', '-', '+']);
|
|
|
|
thisModel.forceTokenization(7);
|
|
checkAndClear([]);
|
|
});
|
|
|
|
test('model invalidates states for one new line', () => {
|
|
thisModel.forceTokenization(5);
|
|
checkAndClear(['1', '2', '3', '4', '5']);
|
|
|
|
thisModel.applyEdits([EditOperation.insert(new Position(1, 2), '\n')]);
|
|
thisModel.applyEdits([EditOperation.insert(new Position(2, 1), 'a')]);
|
|
thisModel.forceTokenization(6);
|
|
checkAndClear(['1', 'a']);
|
|
});
|
|
|
|
test('model invalidates states for one line delete', () => {
|
|
thisModel.forceTokenization(5);
|
|
checkAndClear(['1', '2', '3', '4', '5']);
|
|
|
|
thisModel.applyEdits([EditOperation.insert(new Position(1, 2), '-')]);
|
|
thisModel.forceTokenization(5);
|
|
checkAndClear(['1']);
|
|
|
|
thisModel.applyEdits([EditOperation.delete(new Range(1, 1, 1, 2))]);
|
|
thisModel.forceTokenization(5);
|
|
checkAndClear(['-']);
|
|
|
|
thisModel.forceTokenization(5);
|
|
checkAndClear([]);
|
|
});
|
|
|
|
test('model invalidates states for many lines delete', () => {
|
|
thisModel.forceTokenization(5);
|
|
checkAndClear(['1', '2', '3', '4', '5']);
|
|
|
|
thisModel.applyEdits([EditOperation.delete(new Range(1, 1, 3, 1))]);
|
|
thisModel.forceTokenization(3);
|
|
checkAndClear(['3']);
|
|
|
|
thisModel.forceTokenization(3);
|
|
checkAndClear([]);
|
|
});
|
|
});
|
|
|
|
suite('Editor Model - Model Modes 2', () => {
|
|
|
|
class ModelState2 implements modes.IState {
|
|
prevLineContent: string;
|
|
|
|
constructor(prevLineContent: string) {
|
|
this.prevLineContent = prevLineContent;
|
|
}
|
|
|
|
clone(): modes.IState {
|
|
return new ModelState2(this.prevLineContent);
|
|
}
|
|
|
|
equals(other: modes.IState): boolean {
|
|
return (other instanceof ModelState2) && other.prevLineContent === this.prevLineContent;
|
|
}
|
|
}
|
|
|
|
let calledFor: string[] = [];
|
|
|
|
function checkAndClear(arr: string[]): void {
|
|
assert.deepStrictEqual(calledFor, arr);
|
|
calledFor = [];
|
|
}
|
|
|
|
const tokenizationSupport: modes.ITokenizationSupport = {
|
|
getInitialState: () => new ModelState2(''),
|
|
tokenize: undefined!,
|
|
tokenizeEncoded: (line: string, hasEOL: boolean, state: modes.IState): EncodedTokenizationResult => {
|
|
calledFor.push(line);
|
|
(<ModelState2>state).prevLineContent = line;
|
|
return new EncodedTokenizationResult(new Uint32Array(0), state);
|
|
}
|
|
};
|
|
|
|
let thisModel: TextModel;
|
|
let languageRegistration: IDisposable;
|
|
|
|
setup(() => {
|
|
const TEXT =
|
|
'Line1' + '\r\n' +
|
|
'Line2' + '\n' +
|
|
'Line3' + '\n' +
|
|
'Line4' + '\r\n' +
|
|
'Line5';
|
|
const LANGUAGE_ID = 'modelModeTest2';
|
|
languageRegistration = modes.TokenizationRegistry.register(LANGUAGE_ID, tokenizationSupport);
|
|
thisModel = createTextModel(TEXT, LANGUAGE_ID);
|
|
});
|
|
|
|
teardown(() => {
|
|
thisModel.dispose();
|
|
languageRegistration.dispose();
|
|
});
|
|
|
|
test('getTokensForInvalidLines one text insert', () => {
|
|
thisModel.forceTokenization(5);
|
|
checkAndClear(['Line1', 'Line2', 'Line3', 'Line4', 'Line5']);
|
|
thisModel.applyEdits([EditOperation.insert(new Position(1, 6), '-')]);
|
|
thisModel.forceTokenization(5);
|
|
checkAndClear(['Line1-', 'Line2']);
|
|
});
|
|
|
|
test('getTokensForInvalidLines two text insert', () => {
|
|
thisModel.forceTokenization(5);
|
|
checkAndClear(['Line1', 'Line2', 'Line3', 'Line4', 'Line5']);
|
|
thisModel.applyEdits([
|
|
EditOperation.insert(new Position(1, 6), '-'),
|
|
EditOperation.insert(new Position(3, 6), '-')
|
|
]);
|
|
|
|
thisModel.forceTokenization(5);
|
|
checkAndClear(['Line1-', 'Line2', 'Line3-', 'Line4']);
|
|
});
|
|
|
|
test('getTokensForInvalidLines one multi-line text insert, one small text insert', () => {
|
|
thisModel.forceTokenization(5);
|
|
checkAndClear(['Line1', 'Line2', 'Line3', 'Line4', 'Line5']);
|
|
thisModel.applyEdits([EditOperation.insert(new Position(1, 6), '\nNew line\nAnother new line')]);
|
|
thisModel.applyEdits([EditOperation.insert(new Position(5, 6), '-')]);
|
|
thisModel.forceTokenization(7);
|
|
checkAndClear(['Line1', 'New line', 'Another new line', 'Line2', 'Line3-', 'Line4']);
|
|
});
|
|
|
|
test('getTokensForInvalidLines one delete text', () => {
|
|
thisModel.forceTokenization(5);
|
|
checkAndClear(['Line1', 'Line2', 'Line3', 'Line4', 'Line5']);
|
|
thisModel.applyEdits([EditOperation.delete(new Range(1, 1, 1, 5))]);
|
|
thisModel.forceTokenization(5);
|
|
checkAndClear(['1', 'Line2']);
|
|
});
|
|
|
|
test('getTokensForInvalidLines one line delete text', () => {
|
|
thisModel.forceTokenization(5);
|
|
checkAndClear(['Line1', 'Line2', 'Line3', 'Line4', 'Line5']);
|
|
thisModel.applyEdits([EditOperation.delete(new Range(1, 1, 2, 1))]);
|
|
thisModel.forceTokenization(4);
|
|
checkAndClear(['Line2']);
|
|
});
|
|
|
|
test('getTokensForInvalidLines multiple lines delete text', () => {
|
|
thisModel.forceTokenization(5);
|
|
checkAndClear(['Line1', 'Line2', 'Line3', 'Line4', 'Line5']);
|
|
thisModel.applyEdits([EditOperation.delete(new Range(1, 1, 3, 3))]);
|
|
thisModel.forceTokenization(3);
|
|
checkAndClear(['ne3', 'Line4']);
|
|
});
|
|
});
|