mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-09 17:52:34 -05:00
Merge VS Code 1.23.1 (#1520)
This commit is contained in:
@@ -4,9 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ITextBufferBuilder, ITextBufferFactory, ITextBuffer, DefaultEndOfLine } from 'vs/editor/common/model';
|
||||
import { LinesTextBufferBuilder } from 'vs/editor/common/model/linesTextBuffer/linesTextBufferBuilder';
|
||||
import { PieceTreeTextBufferBuilder } from 'vs/editor/common/model/pieceTreeTextBuffer/pieceTreeTextBufferBuilder';
|
||||
import { ChunksTextBufferBuilder } from 'vs/editor/common/model/chunksTextBuffer/chunksTextBufferBuilder';
|
||||
|
||||
export function doBenchmark<T>(id: string, ts: T[], fn: (t: T) => void) {
|
||||
let columns: string[] = [id];
|
||||
@@ -57,7 +55,7 @@ export class BenchmarkSuite {
|
||||
for (let i = 0; i < this.benchmarks.length; i++) {
|
||||
let benchmark = this.benchmarks[i];
|
||||
let columns: string[] = [benchmark.name];
|
||||
[new LinesTextBufferBuilder(), new PieceTreeTextBufferBuilder(), new ChunksTextBufferBuilder()].forEach((builder: ITextBufferBuilder) => {
|
||||
[new PieceTreeTextBufferBuilder()].forEach((builder: ITextBufferBuilder) => {
|
||||
let timeDiffTotal = 0.0;
|
||||
for (let j = 0; j < this.iterations; j++) {
|
||||
let factory = benchmark.buildBuffer(builder);
|
||||
|
||||
@@ -4,13 +4,11 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import { LinesTextBufferBuilder } from 'vs/editor/common/model/linesTextBuffer/linesTextBufferBuilder';
|
||||
import { PieceTreeTextBufferBuilder } from 'vs/editor/common/model/pieceTreeTextBuffer/pieceTreeTextBufferBuilder';
|
||||
import { ITextBufferBuilder } from 'vs/editor/common/model';
|
||||
import { generateRandomChunkWithLF } from 'vs/editor/test/common/model/linesTextBuffer/textBufferAutoTestUtils';
|
||||
import { doBenchmark } from 'vs/editor/test/common/model/benchmark/benchmarkUtils';
|
||||
|
||||
let linesTextBufferBuilder = new LinesTextBufferBuilder();
|
||||
let pieceTreeTextBufferBuilder = new PieceTreeTextBufferBuilder();
|
||||
let chunks = [];
|
||||
|
||||
@@ -30,5 +28,5 @@ let modelBuildBenchmark = function (id: string, builders: ITextBufferBuilder[],
|
||||
console.log(`|model builder\t|line buffer\t|piece table\t|`);
|
||||
console.log('|---|---|---|');
|
||||
for (let i of [10, 100]) {
|
||||
modelBuildBenchmark(`${i} random chunks`, [linesTextBufferBuilder, pieceTreeTextBufferBuilder], i);
|
||||
modelBuildBenchmark(`${i} random chunks`, [pieceTreeTextBufferBuilder], i);
|
||||
}
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { BufferPiece } from 'vs/editor/common/model/chunksTextBuffer/bufferPiece';
|
||||
|
||||
suite('BufferPiece', () => {
|
||||
test('findLineStartBeforeOffset', () => {
|
||||
let piece = new BufferPiece([
|
||||
'Line1\r\n',
|
||||
'l2\n',
|
||||
'another\r',
|
||||
'and\r\n',
|
||||
'finally\n',
|
||||
'last'
|
||||
].join(''));
|
||||
|
||||
assert.equal(piece.length(), 35);
|
||||
assert.deepEqual(piece.findLineStartBeforeOffset(0), -1);
|
||||
assert.deepEqual(piece.findLineStartBeforeOffset(1), -1);
|
||||
assert.deepEqual(piece.findLineStartBeforeOffset(2), -1);
|
||||
assert.deepEqual(piece.findLineStartBeforeOffset(3), -1);
|
||||
assert.deepEqual(piece.findLineStartBeforeOffset(4), -1);
|
||||
assert.deepEqual(piece.findLineStartBeforeOffset(5), -1);
|
||||
assert.deepEqual(piece.findLineStartBeforeOffset(6), -1);
|
||||
assert.deepEqual(piece.findLineStartBeforeOffset(7), 0);
|
||||
assert.deepEqual(piece.findLineStartBeforeOffset(8), 0);
|
||||
assert.deepEqual(piece.findLineStartBeforeOffset(9), 0);
|
||||
assert.deepEqual(piece.findLineStartBeforeOffset(10), 1);
|
||||
assert.deepEqual(piece.findLineStartBeforeOffset(11), 1);
|
||||
assert.deepEqual(piece.findLineStartBeforeOffset(12), 1);
|
||||
assert.deepEqual(piece.findLineStartBeforeOffset(13), 1);
|
||||
assert.deepEqual(piece.findLineStartBeforeOffset(14), 1);
|
||||
assert.deepEqual(piece.findLineStartBeforeOffset(15), 1);
|
||||
assert.deepEqual(piece.findLineStartBeforeOffset(16), 1);
|
||||
assert.deepEqual(piece.findLineStartBeforeOffset(17), 1);
|
||||
assert.deepEqual(piece.findLineStartBeforeOffset(18), 2);
|
||||
assert.deepEqual(piece.findLineStartBeforeOffset(19), 2);
|
||||
assert.deepEqual(piece.findLineStartBeforeOffset(20), 2);
|
||||
assert.deepEqual(piece.findLineStartBeforeOffset(21), 2);
|
||||
assert.deepEqual(piece.findLineStartBeforeOffset(22), 2);
|
||||
assert.deepEqual(piece.findLineStartBeforeOffset(23), 3);
|
||||
assert.deepEqual(piece.findLineStartBeforeOffset(24), 3);
|
||||
assert.deepEqual(piece.findLineStartBeforeOffset(25), 3);
|
||||
assert.deepEqual(piece.findLineStartBeforeOffset(26), 3);
|
||||
assert.deepEqual(piece.findLineStartBeforeOffset(27), 3);
|
||||
assert.deepEqual(piece.findLineStartBeforeOffset(28), 3);
|
||||
assert.deepEqual(piece.findLineStartBeforeOffset(29), 3);
|
||||
assert.deepEqual(piece.findLineStartBeforeOffset(30), 3);
|
||||
assert.deepEqual(piece.findLineStartBeforeOffset(31), 4);
|
||||
assert.deepEqual(piece.findLineStartBeforeOffset(32), 4);
|
||||
assert.deepEqual(piece.findLineStartBeforeOffset(33), 4);
|
||||
assert.deepEqual(piece.findLineStartBeforeOffset(34), 4);
|
||||
assert.deepEqual(piece.findLineStartBeforeOffset(35), 4);
|
||||
assert.deepEqual(piece.findLineStartBeforeOffset(36), 4);
|
||||
});
|
||||
});
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { EndOfLineSequence, IIdentifiedSingleEditOperation } from 'vs/editor/common/model';
|
||||
import { EndOfLineSequence, IIdentifiedSingleEditOperation, EndOfLinePreference } from 'vs/editor/common/model';
|
||||
import { TextModel } from 'vs/editor/common/model/textModel';
|
||||
import { MirrorTextModel } from 'vs/editor/common/model/mirrorTextModel';
|
||||
import { assertSyncedModels, testApplyEditsWithSyncedModels } from 'vs/editor/test/common/model/editableTextModelTestUtils';
|
||||
@@ -1069,4 +1069,48 @@ suite('EditorModel - EditableTextModel.applyEdits', () => {
|
||||
model.dispose();
|
||||
mirrorModel2.dispose();
|
||||
});
|
||||
|
||||
test('issue #47733: Undo mangles unicode characters', () => {
|
||||
let model = createEditableTextModelFromString('\'👁\'');
|
||||
|
||||
model.applyEdits([
|
||||
{ range: new Range(1, 1, 1, 1), text: '"' },
|
||||
{ range: new Range(1, 2, 1, 2), text: '"' },
|
||||
]);
|
||||
|
||||
assert.equal(model.getValue(EndOfLinePreference.LF), '"\'"👁\'');
|
||||
|
||||
assert.deepEqual(model.validateRange(new Range(1, 3, 1, 4)), new Range(1, 3, 1, 4));
|
||||
|
||||
model.applyEdits([
|
||||
{ range: new Range(1, 1, 1, 2), text: null },
|
||||
{ range: new Range(1, 3, 1, 4), text: null },
|
||||
]);
|
||||
|
||||
assert.equal(model.getValue(EndOfLinePreference.LF), '\'👁\'');
|
||||
|
||||
model.dispose();
|
||||
});
|
||||
|
||||
test('issue #48741: Broken undo stack with move lines up with multiple cursors', () => {
|
||||
let model = createEditableTextModelFromString([
|
||||
'line1',
|
||||
'line2',
|
||||
'line3',
|
||||
'',
|
||||
].join('\n'));
|
||||
|
||||
const undoEdits = model.applyEdits([
|
||||
{ range: new Range(4, 1, 4, 1), text: 'line3', },
|
||||
{ range: new Range(3, 1, 3, 6), text: null, },
|
||||
{ range: new Range(2, 1, 3, 1), text: null, },
|
||||
{ range: new Range(3, 6, 3, 6), text: '\nline2' }
|
||||
]);
|
||||
|
||||
model.applyEdits(undoEdits);
|
||||
|
||||
assert.deepEqual(model.getValue(), 'line1\nline2\nline3\n');
|
||||
|
||||
model.dispose();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -31,8 +31,17 @@ export function testApplyEditsWithSyncedModels(original: string[], edits: IIdent
|
||||
assert.deepEqual(model.getValue(EndOfLinePreference.LF), originalStr);
|
||||
|
||||
if (!inputEditsAreInvalid) {
|
||||
const simplifyEdit = (edit: IIdentifiedSingleEditOperation) => {
|
||||
return {
|
||||
identifier: edit.identifier,
|
||||
range: edit.range,
|
||||
text: edit.text,
|
||||
forceMoveMarkers: edit.forceMoveMarkers,
|
||||
isAutoWhitespaceEdit: edit.isAutoWhitespaceEdit
|
||||
};
|
||||
};
|
||||
// Assert the inverse of the inverse edits are the original edits
|
||||
assert.deepEqual(inverseInverseEdits, edits);
|
||||
assert.deepEqual(inverseInverseEdits.map(simplifyEdit), edits.map(simplifyEdit));
|
||||
}
|
||||
|
||||
assertMirrorModels();
|
||||
|
||||
@@ -7,9 +7,11 @@
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { LinesTextBuffer, IValidatedEditOperation } from 'vs/editor/common/model/linesTextBuffer/linesTextBuffer';
|
||||
import { PieceTreeTextBuffer, IValidatedEditOperation } from 'vs/editor/common/model/pieceTreeTextBuffer/pieceTreeTextBuffer';
|
||||
import { createTextBufferFactory } from 'vs/editor/common/model/textModel';
|
||||
import { DefaultEndOfLine } from 'vs/editor/common/model';
|
||||
|
||||
suite('LinesTextBuffer._getInverseEdits', () => {
|
||||
suite('PieceTreeTextBuffer._getInverseEdits', () => {
|
||||
|
||||
function editOp(startLineNumber: number, startColumn: number, endLineNumber: number, endColumn: number, text: string[]): IValidatedEditOperation {
|
||||
return {
|
||||
@@ -29,7 +31,7 @@ suite('LinesTextBuffer._getInverseEdits', () => {
|
||||
}
|
||||
|
||||
function assertInverseEdits(ops: IValidatedEditOperation[], expected: Range[]): void {
|
||||
var actual = LinesTextBuffer._getInverseEditRanges(ops);
|
||||
var actual = PieceTreeTextBuffer._getInverseEditRanges(ops);
|
||||
assert.deepEqual(actual, expected);
|
||||
}
|
||||
|
||||
@@ -260,7 +262,7 @@ suite('LinesTextBuffer._getInverseEdits', () => {
|
||||
});
|
||||
});
|
||||
|
||||
suite('LinesTextBuffer._toSingleEditOperation', () => {
|
||||
suite('PieceTreeTextBuffer._toSingleEditOperation', () => {
|
||||
|
||||
function editOp(startLineNumber: number, startColumn: number, endLineNumber: number, endColumn: number, rangeOffset: number, rangeLength: number, text: string[]): IValidatedEditOperation {
|
||||
return {
|
||||
@@ -276,13 +278,7 @@ suite('LinesTextBuffer._toSingleEditOperation', () => {
|
||||
}
|
||||
|
||||
function testToSingleEditOperation(original: string[], edits: IValidatedEditOperation[], expected: IValidatedEditOperation): void {
|
||||
const textBuffer = new LinesTextBuffer({
|
||||
BOM: '',
|
||||
EOL: '\n',
|
||||
containsRTL: false,
|
||||
isBasicASCII: true,
|
||||
lines: original
|
||||
});
|
||||
const textBuffer = <PieceTreeTextBuffer>createTextBufferFactory(original.join('\n')).create(DefaultEndOfLine.LF);
|
||||
|
||||
const actual = textBuffer._toSingleEditOperation(edits);
|
||||
assert.deepEqual(actual, expected);
|
||||
|
||||
@@ -5,150 +5,69 @@
|
||||
'use strict';
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { LinesTextBufferBuilder } from 'vs/editor/common/model/linesTextBuffer/linesTextBufferBuilder';
|
||||
import { ITextModelCreationOptions } from 'vs/editor/common/model';
|
||||
import { TextModel } from 'vs/editor/common/model/textModel';
|
||||
import { DefaultEndOfLine } from 'vs/editor/common/model';
|
||||
import { createTextBufferFactory } from 'vs/editor/common/model/textModel';
|
||||
import * as strings from 'vs/base/common/strings';
|
||||
import { IRawTextSource } from 'vs/editor/common/model/linesTextBuffer/textSource';
|
||||
import { PieceTreeTextBuffer } from 'vs/editor/common/model/pieceTreeTextBuffer/pieceTreeTextBuffer';
|
||||
|
||||
class RawTextSource {
|
||||
public static fromString(rawText: string): IRawTextSource {
|
||||
// Count the number of lines that end with \r\n
|
||||
let carriageReturnCnt = 0;
|
||||
let lastCarriageReturnIndex = -1;
|
||||
while ((lastCarriageReturnIndex = rawText.indexOf('\r', lastCarriageReturnIndex + 1)) !== -1) {
|
||||
carriageReturnCnt++;
|
||||
}
|
||||
export function testTextBufferFactory(text: string, eol: string, mightContainNonBasicASCII: boolean, mightContainRTL: boolean): void {
|
||||
const textBuffer = <PieceTreeTextBuffer>createTextBufferFactory(text).create(DefaultEndOfLine.LF);
|
||||
|
||||
const containsRTL = strings.containsRTL(rawText);
|
||||
const isBasicASCII = (containsRTL ? false : strings.isBasicASCII(rawText));
|
||||
|
||||
// Split the text into lines
|
||||
const lines = rawText.split(/\r\n|\r|\n/);
|
||||
|
||||
// Remove the BOM (if present)
|
||||
let BOM = '';
|
||||
if (strings.startsWithUTF8BOM(lines[0])) {
|
||||
BOM = strings.UTF8_BOM_CHARACTER;
|
||||
lines[0] = lines[0].substr(1);
|
||||
}
|
||||
|
||||
return {
|
||||
BOM: BOM,
|
||||
lines: lines,
|
||||
containsRTL: containsRTL,
|
||||
isBasicASCII: isBasicASCII,
|
||||
totalCRCount: carriageReturnCnt
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export function testModelBuilder(chunks: string[], opts: ITextModelCreationOptions = TextModel.DEFAULT_CREATION_OPTIONS): void {
|
||||
let expectedTextSource = RawTextSource.fromString(chunks.join(''));
|
||||
|
||||
let builder = new LinesTextBufferBuilder();
|
||||
for (let i = 0, len = chunks.length; i < len; i++) {
|
||||
builder.acceptChunk(chunks[i]);
|
||||
}
|
||||
let actual = builder.finish();
|
||||
|
||||
assert.deepEqual(actual.rawTextSource, expectedTextSource);
|
||||
assert.equal(textBuffer.mightContainNonBasicASCII(), mightContainNonBasicASCII);
|
||||
assert.equal(textBuffer.mightContainRTL(), mightContainRTL);
|
||||
assert.equal(textBuffer.getEOL(), eol);
|
||||
}
|
||||
|
||||
suite('ModelBuilder', () => {
|
||||
|
||||
test('no chunks', () => {
|
||||
testModelBuilder([]);
|
||||
test('t1', () => {
|
||||
testTextBufferFactory('', '\n', false, false);
|
||||
});
|
||||
|
||||
test('single empty chunk', () => {
|
||||
testModelBuilder(['']);
|
||||
test('t2', () => {
|
||||
testTextBufferFactory('Hello world', '\n', false, false);
|
||||
});
|
||||
|
||||
test('single line in one chunk', () => {
|
||||
testModelBuilder(['Hello world']);
|
||||
test('t3', () => {
|
||||
testTextBufferFactory('Hello world\nHow are you?', '\n', false, false);
|
||||
});
|
||||
|
||||
test('single line in multiple chunks', () => {
|
||||
testModelBuilder(['Hello', ' ', 'world']);
|
||||
});
|
||||
|
||||
test('two lines in single chunk', () => {
|
||||
testModelBuilder(['Hello world\nHow are you?']);
|
||||
});
|
||||
|
||||
test('two lines in multiple chunks 1', () => {
|
||||
testModelBuilder(['Hello worl', 'd\nHow are you?']);
|
||||
});
|
||||
|
||||
test('two lines in multiple chunks 2', () => {
|
||||
testModelBuilder(['Hello worl', 'd', '\n', 'H', 'ow are you?']);
|
||||
});
|
||||
|
||||
test('two lines in multiple chunks 3', () => {
|
||||
testModelBuilder(['Hello worl', 'd', '\nHow are you?']);
|
||||
});
|
||||
|
||||
test('multiple lines in single chunks', () => {
|
||||
testModelBuilder(['Hello world\nHow are you?\nIs everything good today?\nDo you enjoy the weather?']);
|
||||
});
|
||||
|
||||
test('multiple lines in multiple chunks 1', () => {
|
||||
testModelBuilder(['Hello world\nHow are you', '?\nIs everything good today?\nDo you enjoy the weather?']);
|
||||
});
|
||||
|
||||
test('multiple lines in multiple chunks 1', () => {
|
||||
testModelBuilder(['Hello world', '\nHow are you', '?\nIs everything good today?', '\nDo you enjoy the weather?']);
|
||||
});
|
||||
|
||||
test('multiple lines in multiple chunks 1', () => {
|
||||
testModelBuilder(['Hello world\n', 'How are you', '?\nIs everything good today?', '\nDo you enjoy the weather?']);
|
||||
test('t4', () => {
|
||||
testTextBufferFactory('Hello world\nHow are you?\nIs everything good today?\nDo you enjoy the weather?', '\n', false, false);
|
||||
});
|
||||
|
||||
test('carriage return detection (1 \\r\\n 2 \\n)', () => {
|
||||
testModelBuilder(['Hello world\r\n', 'How are you', '?\nIs everything good today?', '\nDo you enjoy the weather?']);
|
||||
testTextBufferFactory('Hello world\r\nHow are you?\nIs everything good today?\nDo you enjoy the weather?', '\n', false, false);
|
||||
});
|
||||
|
||||
test('carriage return detection (2 \\r\\n 1 \\n)', () => {
|
||||
testModelBuilder(['Hello world\r\n', 'How are you', '?\r\nIs everything good today?', '\nDo you enjoy the weather?']);
|
||||
testTextBufferFactory('Hello world\r\nHow are you?\r\nIs everything good today?\nDo you enjoy the weather?', '\r\n', false, false);
|
||||
});
|
||||
|
||||
test('carriage return detection (3 \\r\\n 0 \\n)', () => {
|
||||
testModelBuilder(['Hello world\r\n', 'How are you', '?\r\nIs everything good today?', '\r\nDo you enjoy the weather?']);
|
||||
});
|
||||
|
||||
test('carriage return detection (isolated \\r)', () => {
|
||||
testModelBuilder(['Hello world', '\r', '\n', 'How are you', '?', '\r', '\n', 'Is everything good today?', '\r', '\n', 'Do you enjoy the weather?']);
|
||||
testTextBufferFactory('Hello world\r\nHow are you?\r\nIs everything good today?\r\nDo you enjoy the weather?', '\r\n', false, false);
|
||||
});
|
||||
|
||||
test('BOM handling', () => {
|
||||
testModelBuilder([strings.UTF8_BOM_CHARACTER + 'Hello world!']);
|
||||
testTextBufferFactory(strings.UTF8_BOM_CHARACTER + 'Hello world!', '\n', false, false);
|
||||
});
|
||||
|
||||
test('BOM handling', () => {
|
||||
testModelBuilder([strings.UTF8_BOM_CHARACTER, 'Hello world!']);
|
||||
});
|
||||
|
||||
test('RTL handling 1', () => {
|
||||
testModelBuilder(['Hello world!', 'זוהי עובדה מבוססת שדעתו']);
|
||||
testTextBufferFactory(strings.UTF8_BOM_CHARACTER + 'Hello world!', '\n', false, false);
|
||||
});
|
||||
|
||||
test('RTL handling 2', () => {
|
||||
testModelBuilder(['Hello world!זוהי עובדה מבוססת שדעתו']);
|
||||
testTextBufferFactory('Hello world!זוהי עובדה מבוססת שדעתו', '\n', true, true);
|
||||
});
|
||||
|
||||
test('RTL handling 3', () => {
|
||||
testModelBuilder(['Hello world!זוהי \nעובדה מבוססת שדעתו']);
|
||||
testTextBufferFactory('Hello world!זוהי \nעובדה מבוססת שדעתו', '\n', true, true);
|
||||
});
|
||||
|
||||
test('ASCII handling 1', () => {
|
||||
testModelBuilder(['Hello world!!\nHow do you do?']);
|
||||
testTextBufferFactory('Hello world!!\nHow do you do?', '\n', false, false);
|
||||
});
|
||||
test('ASCII handling 1', () => {
|
||||
testModelBuilder(['Hello world!!\nHow do you do?Züricha📚📚b']);
|
||||
});
|
||||
|
||||
test('issue #32819: some special string cannot be displayed completely', () => {
|
||||
testModelBuilder(['AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA123']);
|
||||
test('ASCII handling 2', () => {
|
||||
testTextBufferFactory('Hello world!!\nHow do you do?Züricha📚📚b', '\n', true, false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,97 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import { testModelBuilder } from './linesTextBufferBuilder.test';
|
||||
import { getRandomInt, getRandomEOLSequence, getRandomString } from 'vs/editor/test/common/model/linesTextBuffer/textBufferAutoTestUtils';
|
||||
|
||||
const GENERATE_TESTS = false;
|
||||
|
||||
suite('ModelBuilder Auto Tests', () => {
|
||||
|
||||
test('auto1', () => {
|
||||
testModelBuilder(['sarjniow', '\r', '\nbpb', 'ofb', '\njzldgxx', '\r\nkzwfjysng']);
|
||||
});
|
||||
|
||||
test('auto2', () => {
|
||||
testModelBuilder(['i', 'yyernubi\r\niimgn\n', 'ut\r']);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
function generateRandomFile(): string {
|
||||
let lineCount = getRandomInt(1, 10);
|
||||
let mixedEOLSequence = getRandomInt(1, 2) === 1 ? true : false;
|
||||
let fixedEOL = getRandomEOLSequence();
|
||||
let lines: string[] = [];
|
||||
for (let i = 0; i < lineCount; i++) {
|
||||
if (i !== 0) {
|
||||
if (mixedEOLSequence) {
|
||||
lines.push(getRandomEOLSequence());
|
||||
} else {
|
||||
lines.push(fixedEOL);
|
||||
}
|
||||
}
|
||||
lines.push(getRandomString(0, 10));
|
||||
|
||||
}
|
||||
return lines.join('');
|
||||
}
|
||||
|
||||
function generateRandomChunks(file: string): string[] {
|
||||
let result: string[] = [];
|
||||
let cnt = getRandomInt(1, 20);
|
||||
|
||||
let maxOffset = file.length;
|
||||
|
||||
while (cnt > 0 && maxOffset > 0) {
|
||||
|
||||
let offset = getRandomInt(0, maxOffset);
|
||||
result.unshift(file.substring(offset, maxOffset));
|
||||
// let length = getRandomInt(0, maxOffset - offset);
|
||||
// let text = generateFile(true);
|
||||
|
||||
// result.push({
|
||||
// offset: offset,
|
||||
// length: length,
|
||||
// text: text
|
||||
// });
|
||||
|
||||
maxOffset = offset;
|
||||
cnt--;
|
||||
}
|
||||
if (maxOffset !== 0) {
|
||||
result.unshift(file.substring(0, maxOffset));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function testRandomFile(file: string): boolean {
|
||||
let tests = getRandomInt(5, 10);
|
||||
for (let i = 0; i < tests; i++) {
|
||||
let chunks = generateRandomChunks(file);
|
||||
try {
|
||||
testModelBuilder(chunks);
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
console.log(JSON.stringify(chunks));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (GENERATE_TESTS) {
|
||||
let number = 1;
|
||||
while (true) {
|
||||
console.log('------BEGIN NEW TEST: ' + number);
|
||||
|
||||
if (!testRandomFile(generateRandomFile())) {
|
||||
break;
|
||||
}
|
||||
|
||||
console.log('------END NEW TEST: ' + (number++));
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,12 @@ import {
|
||||
ModelRawLinesDeleted, ModelRawLinesInserted
|
||||
} from 'vs/editor/common/model/textModelEvents';
|
||||
import { TextModel } from 'vs/editor/common/model/textModel';
|
||||
import { LanguageIdentifier, TokenizationRegistry, IState, MetadataConsts } from 'vs/editor/common/modes';
|
||||
import { MockMode } from 'vs/editor/test/common/mocks/mockMode';
|
||||
import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry';
|
||||
import { TokenizationResult2 } from 'vs/editor/common/core/token';
|
||||
import { NULL_STATE } from 'vs/editor/common/modes/nullMode';
|
||||
import { dispose, Disposable } from 'vs/base/common/lifecycle';
|
||||
|
||||
// --------- utils
|
||||
|
||||
@@ -103,7 +109,7 @@ suite('Editor Model - Model', () => {
|
||||
let e: ModelRawContentChangedEvent = null;
|
||||
thisModel.onDidChangeRawContent((_e) => {
|
||||
if (e !== null) {
|
||||
assert.fail();
|
||||
assert.fail('Unexpected assertion error');
|
||||
}
|
||||
e = _e;
|
||||
});
|
||||
@@ -122,7 +128,7 @@ suite('Editor Model - Model', () => {
|
||||
let e: ModelRawContentChangedEvent = null;
|
||||
thisModel.onDidChangeRawContent((_e) => {
|
||||
if (e !== null) {
|
||||
assert.fail();
|
||||
assert.fail('Unexpected assertion error');
|
||||
}
|
||||
e = _e;
|
||||
});
|
||||
@@ -199,7 +205,7 @@ suite('Editor Model - Model', () => {
|
||||
let e: ModelRawContentChangedEvent = null;
|
||||
thisModel.onDidChangeRawContent((_e) => {
|
||||
if (e !== null) {
|
||||
assert.fail();
|
||||
assert.fail('Unexpected assertion error');
|
||||
}
|
||||
e = _e;
|
||||
});
|
||||
@@ -218,7 +224,7 @@ suite('Editor Model - Model', () => {
|
||||
let e: ModelRawContentChangedEvent = null;
|
||||
thisModel.onDidChangeRawContent((_e) => {
|
||||
if (e !== null) {
|
||||
assert.fail();
|
||||
assert.fail('Unexpected assertion error');
|
||||
}
|
||||
e = _e;
|
||||
});
|
||||
@@ -237,7 +243,7 @@ suite('Editor Model - Model', () => {
|
||||
let e: ModelRawContentChangedEvent = null;
|
||||
thisModel.onDidChangeRawContent((_e) => {
|
||||
if (e !== null) {
|
||||
assert.fail();
|
||||
assert.fail('Unexpected assertion error');
|
||||
}
|
||||
e = _e;
|
||||
});
|
||||
@@ -257,7 +263,7 @@ suite('Editor Model - Model', () => {
|
||||
let e: ModelRawContentChangedEvent = null;
|
||||
thisModel.onDidChangeRawContent((_e) => {
|
||||
if (e !== null) {
|
||||
assert.fail();
|
||||
assert.fail('Unexpected assertion error');
|
||||
}
|
||||
e = _e;
|
||||
});
|
||||
@@ -308,7 +314,7 @@ suite('Editor Model - Model', () => {
|
||||
let e: ModelRawContentChangedEvent = null;
|
||||
thisModel.onDidChangeRawContent((_e) => {
|
||||
if (e !== null) {
|
||||
assert.fail();
|
||||
assert.fail('Unexpected assertion error');
|
||||
}
|
||||
e = _e;
|
||||
});
|
||||
@@ -322,6 +328,16 @@ suite('Editor Model - Model', () => {
|
||||
false
|
||||
));
|
||||
});
|
||||
|
||||
test('issue #46342: Maintain edit operation order in applyEdits', () => {
|
||||
let res = thisModel.applyEdits([
|
||||
{ range: new Range(2, 1, 2, 1), text: 'a' },
|
||||
{ range: new Range(1, 1, 1, 1), text: 'b' },
|
||||
]);
|
||||
|
||||
assert.deepEqual(res[0].range, new Range(2, 1, 2, 2));
|
||||
assert.deepEqual(res[1].range, new Range(1, 1, 1, 2));
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -365,18 +381,62 @@ suite('Editor Model - Model Line Separators', () => {
|
||||
|
||||
suite('Editor Model - Words', () => {
|
||||
|
||||
var thisModel: TextModel;
|
||||
const OUTER_LANGUAGE_ID = new LanguageIdentifier('outerMode', 3);
|
||||
const INNER_LANGUAGE_ID = new LanguageIdentifier('innerMode', 4);
|
||||
|
||||
class OuterMode extends MockMode {
|
||||
constructor() {
|
||||
super(OUTER_LANGUAGE_ID);
|
||||
this._register(LanguageConfigurationRegistry.register(this.getLanguageIdentifier(), {}));
|
||||
|
||||
this._register(TokenizationRegistry.register(this.getLanguageIdentifier().language, {
|
||||
getInitialState: (): IState => NULL_STATE,
|
||||
tokenize: undefined,
|
||||
tokenize2: (line: string, state: IState): TokenizationResult2 => {
|
||||
const tokensArr: number[] = [];
|
||||
let prevLanguageId: LanguageIdentifier = undefined;
|
||||
for (let i = 0; i < line.length; i++) {
|
||||
const languageId = (line.charAt(i) === 'x' ? INNER_LANGUAGE_ID : OUTER_LANGUAGE_ID);
|
||||
if (prevLanguageId !== languageId) {
|
||||
tokensArr.push(i);
|
||||
tokensArr.push((languageId.id << MetadataConsts.LANGUAGEID_OFFSET));
|
||||
}
|
||||
prevLanguageId = languageId;
|
||||
}
|
||||
|
||||
const tokens = new Uint32Array(tokensArr.length);
|
||||
for (let i = 0; i < tokens.length; i++) {
|
||||
tokens[i] = tokensArr[i];
|
||||
}
|
||||
return new TokenizationResult2(tokens, state);
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
class InnerMode extends MockMode {
|
||||
constructor() {
|
||||
super(INNER_LANGUAGE_ID);
|
||||
this._register(LanguageConfigurationRegistry.register(this.getLanguageIdentifier(), {}));
|
||||
}
|
||||
}
|
||||
|
||||
let disposables: Disposable[] = [];
|
||||
|
||||
setup(() => {
|
||||
var text = ['This text has some words. '];
|
||||
thisModel = TextModel.createFromString(text.join('\n'));
|
||||
disposables = [];
|
||||
});
|
||||
|
||||
teardown(() => {
|
||||
thisModel.dispose();
|
||||
dispose(disposables);
|
||||
disposables = [];
|
||||
});
|
||||
|
||||
test('Get word at position', () => {
|
||||
const text = ['This text has some words. '];
|
||||
const thisModel = TextModel.createFromString(text.join('\n'));
|
||||
disposables.push(thisModel);
|
||||
|
||||
assert.deepEqual(thisModel.getWordAtPosition(new Position(1, 1)), { word: 'This', startColumn: 1, endColumn: 5 });
|
||||
assert.deepEqual(thisModel.getWordAtPosition(new Position(1, 2)), { word: 'This', startColumn: 1, endColumn: 5 });
|
||||
assert.deepEqual(thisModel.getWordAtPosition(new Position(1, 4)), { word: 'This', startColumn: 1, endColumn: 5 });
|
||||
@@ -389,4 +449,21 @@ suite('Editor Model - Words', () => {
|
||||
assert.deepEqual(thisModel.getWordAtPosition(new Position(1, 27)), null);
|
||||
assert.deepEqual(thisModel.getWordAtPosition(new Position(1, 28)), null);
|
||||
});
|
||||
|
||||
test('getWordAtPosition at embedded language boundaries', () => {
|
||||
const outerMode = new OuterMode();
|
||||
const innerMode = new InnerMode();
|
||||
disposables.push(outerMode, innerMode);
|
||||
|
||||
const model = TextModel.createFromString('ab<xx>ab<x>', undefined, outerMode.getLanguageIdentifier());
|
||||
disposables.push(model);
|
||||
|
||||
assert.deepEqual(model.getWordAtPosition(new Position(1, 1)), { word: 'ab', startColumn: 1, endColumn: 3 });
|
||||
assert.deepEqual(model.getWordAtPosition(new Position(1, 2)), { word: 'ab', startColumn: 1, endColumn: 3 });
|
||||
assert.deepEqual(model.getWordAtPosition(new Position(1, 3)), { word: 'ab', startColumn: 1, endColumn: 3 });
|
||||
assert.deepEqual(model.getWordAtPosition(new Position(1, 4)), { word: 'xx', startColumn: 4, endColumn: 6 });
|
||||
assert.deepEqual(model.getWordAtPosition(new Position(1, 5)), { word: 'xx', startColumn: 4, endColumn: 6 });
|
||||
assert.deepEqual(model.getWordAtPosition(new Position(1, 6)), { word: 'xx', startColumn: 4, endColumn: 6 });
|
||||
assert.deepEqual(model.getWordAtPosition(new Position(1, 7)), { word: 'ab', startColumn: 7, endColumn: 9 });
|
||||
});
|
||||
});
|
||||
|
||||
@@ -68,7 +68,16 @@ suite('Editor Model - Model Edit Operation', () => {
|
||||
assert.equal(model.getLineContent(4), LINE4);
|
||||
assert.equal(model.getLineContent(5), LINE5);
|
||||
|
||||
assert.deepEqual(originalOp, editOp);
|
||||
const simplifyEdit = (edit: IIdentifiedSingleEditOperation) => {
|
||||
return {
|
||||
identifier: edit.identifier,
|
||||
range: edit.range,
|
||||
text: edit.text,
|
||||
forceMoveMarkers: edit.forceMoveMarkers,
|
||||
isAutoWhitespaceEdit: edit.isAutoWhitespaceEdit
|
||||
};
|
||||
};
|
||||
assert.deepEqual(originalOp.map(simplifyEdit), editOp.map(simplifyEdit));
|
||||
}
|
||||
|
||||
test('Insert inline', () => {
|
||||
|
||||
@@ -12,6 +12,10 @@ import { DefaultEndOfLine } from 'vs/editor/common/model';
|
||||
import { PieceTreeBase } from 'vs/editor/common/model/pieceTreeTextBuffer/pieceTreeBase';
|
||||
import { SENTINEL, NodeColor, TreeNode } from 'vs/editor/common/model/pieceTreeTextBuffer/rbTreeBase';
|
||||
import { PieceTreeTextBuffer } from 'vs/editor/common/model/pieceTreeTextBuffer/pieceTreeTextBuffer';
|
||||
import { TextModel } from 'vs/editor/common/model/textModel';
|
||||
import { ITextSnapshot } from 'vs/platform/files/common/files';
|
||||
import { SearchData } from 'vs/editor/common/model/textModelSearch';
|
||||
import { WordCharacterClassifier } from 'vs/editor/common/controller/wordCharacterClassifier';
|
||||
|
||||
const alphabet = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\r\n';
|
||||
|
||||
@@ -1441,11 +1445,44 @@ suite('centralized lineStarts with CRLF', () => {
|
||||
});
|
||||
|
||||
suite('random is unsupervised', () => {
|
||||
test('splitting large change buffer', function () {
|
||||
let pieceTable = createTextBuffer([''], false);
|
||||
let str = '';
|
||||
|
||||
pieceTable.insert(0, 'WUZ\nXVZY\n');
|
||||
str = str.substring(0, 0) + 'WUZ\nXVZY\n' + str.substring(0);
|
||||
pieceTable.insert(8, '\r\r\nZXUWVW');
|
||||
str = str.substring(0, 8) + '\r\r\nZXUWVW' + str.substring(8);
|
||||
pieceTable.delete(10, 7);
|
||||
str = str.substring(0, 10) + str.substring(10 + 7);
|
||||
pieceTable.delete(10, 1);
|
||||
str = str.substring(0, 10) + str.substring(10 + 1);
|
||||
pieceTable.insert(4, 'VX\r\r\nWZVZ');
|
||||
str = str.substring(0, 4) + 'VX\r\r\nWZVZ' + str.substring(4);
|
||||
pieceTable.delete(11, 3);
|
||||
str = str.substring(0, 11) + str.substring(11 + 3);
|
||||
pieceTable.delete(12, 4);
|
||||
str = str.substring(0, 12) + str.substring(12 + 4);
|
||||
pieceTable.delete(8, 0);
|
||||
str = str.substring(0, 8) + str.substring(8 + 0);
|
||||
pieceTable.delete(10, 2);
|
||||
str = str.substring(0, 10) + str.substring(10 + 2);
|
||||
pieceTable.insert(0, 'VZXXZYZX\r');
|
||||
str = str.substring(0, 0) + 'VZXXZYZX\r' + str.substring(0);
|
||||
|
||||
assert.equal(pieceTable.getLinesRawContent(), str);
|
||||
|
||||
testLineStarts(str, pieceTable);
|
||||
testLinesContent(str, pieceTable);
|
||||
assertTreeInvariants(pieceTable);
|
||||
});
|
||||
|
||||
test('random insert delete', function () {
|
||||
this.timeout(500000);
|
||||
let str = '';
|
||||
let pieceTable = createTextBuffer([str], false);
|
||||
|
||||
// let output = '';
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
if (Math.random() < 0.6) {
|
||||
// insert
|
||||
@@ -1453,6 +1490,8 @@ suite('random is unsupervised', () => {
|
||||
let pos = randomInt(str.length + 1);
|
||||
pieceTable.insert(pos, text);
|
||||
str = str.substring(0, pos) + text + str.substring(pos);
|
||||
// output += `pieceTable.insert(${pos}, '${text.replace(/\n/g, '\\n').replace(/\r/g, '\\r')}');\n`;
|
||||
// output += `str = str.substring(0, ${pos}) + '${text.replace(/\n/g, '\\n').replace(/\r/g, '\\r')}' + str.substring(${pos});\n`;
|
||||
} else {
|
||||
// delete
|
||||
let pos = randomInt(str.length);
|
||||
@@ -1462,8 +1501,12 @@ suite('random is unsupervised', () => {
|
||||
);
|
||||
pieceTable.delete(pos, length);
|
||||
str = str.substring(0, pos) + str.substring(pos + length);
|
||||
// output += `pieceTable.delete(${pos}, ${length});\n`;
|
||||
// output += `str = str.substring(0, ${pos}) + str.substring(${pos} + ${length});\n`
|
||||
|
||||
}
|
||||
}
|
||||
// console.log(output);
|
||||
|
||||
assert.equal(pieceTable.getLinesRawContent(), str);
|
||||
|
||||
@@ -1567,6 +1610,37 @@ suite('buffer api', () => {
|
||||
|
||||
assert(!a.equal(b));
|
||||
});
|
||||
|
||||
test('getLineCharCode - issue #45735', () => {
|
||||
let pieceTable = createTextBuffer(['LINE1\nline2']);
|
||||
assert.equal(pieceTable.getLineCharCode(1, 0), 'L'.charCodeAt(0), 'L');
|
||||
assert.equal(pieceTable.getLineCharCode(1, 1), 'I'.charCodeAt(0), 'I');
|
||||
assert.equal(pieceTable.getLineCharCode(1, 2), 'N'.charCodeAt(0), 'N');
|
||||
assert.equal(pieceTable.getLineCharCode(1, 3), 'E'.charCodeAt(0), 'E');
|
||||
assert.equal(pieceTable.getLineCharCode(1, 4), '1'.charCodeAt(0), '1');
|
||||
assert.equal(pieceTable.getLineCharCode(1, 5), '\n'.charCodeAt(0), '\\n');
|
||||
assert.equal(pieceTable.getLineCharCode(2, 0), 'l'.charCodeAt(0), 'l');
|
||||
assert.equal(pieceTable.getLineCharCode(2, 1), 'i'.charCodeAt(0), 'i');
|
||||
assert.equal(pieceTable.getLineCharCode(2, 2), 'n'.charCodeAt(0), 'n');
|
||||
assert.equal(pieceTable.getLineCharCode(2, 3), 'e'.charCodeAt(0), 'e');
|
||||
assert.equal(pieceTable.getLineCharCode(2, 4), '2'.charCodeAt(0), '2');
|
||||
});
|
||||
|
||||
|
||||
test('getLineCharCode - issue #47733', () => {
|
||||
let pieceTable = createTextBuffer(['', 'LINE1\n', 'line2']);
|
||||
assert.equal(pieceTable.getLineCharCode(1, 0), 'L'.charCodeAt(0), 'L');
|
||||
assert.equal(pieceTable.getLineCharCode(1, 1), 'I'.charCodeAt(0), 'I');
|
||||
assert.equal(pieceTable.getLineCharCode(1, 2), 'N'.charCodeAt(0), 'N');
|
||||
assert.equal(pieceTable.getLineCharCode(1, 3), 'E'.charCodeAt(0), 'E');
|
||||
assert.equal(pieceTable.getLineCharCode(1, 4), '1'.charCodeAt(0), '1');
|
||||
assert.equal(pieceTable.getLineCharCode(1, 5), '\n'.charCodeAt(0), '\\n');
|
||||
assert.equal(pieceTable.getLineCharCode(2, 0), 'l'.charCodeAt(0), 'l');
|
||||
assert.equal(pieceTable.getLineCharCode(2, 1), 'i'.charCodeAt(0), 'i');
|
||||
assert.equal(pieceTable.getLineCharCode(2, 2), 'n'.charCodeAt(0), 'n');
|
||||
assert.equal(pieceTable.getLineCharCode(2, 3), 'e'.charCodeAt(0), 'e');
|
||||
assert.equal(pieceTable.getLineCharCode(2, 4), '2'.charCodeAt(0), '2');
|
||||
});
|
||||
});
|
||||
|
||||
suite('search offset cache', () => {
|
||||
@@ -1674,4 +1748,154 @@ suite('search offset cache', () => {
|
||||
assertTreeInvariants(pieceTable);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
function getValueInSnapshot(snapshot: ITextSnapshot) {
|
||||
let ret = '';
|
||||
let tmp = snapshot.read();
|
||||
|
||||
while (tmp !== null) {
|
||||
ret += tmp;
|
||||
tmp = snapshot.read();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
suite('snapshot', () => {
|
||||
test('bug #45564, piece tree pieces should be immutable', () => {
|
||||
const model = TextModel.createFromString('\n');
|
||||
model.applyEdits([
|
||||
{
|
||||
range: new Range(2, 1, 2, 1),
|
||||
text: '!'
|
||||
}
|
||||
]);
|
||||
const snapshot = model.createSnapshot();
|
||||
const snapshot1 = model.createSnapshot();
|
||||
assert.equal(model.getLinesContent().join('\n'), getValueInSnapshot(snapshot));
|
||||
|
||||
model.applyEdits([
|
||||
{
|
||||
range: new Range(2, 1, 2, 2),
|
||||
text: ''
|
||||
}
|
||||
]);
|
||||
model.applyEdits([
|
||||
{
|
||||
range: new Range(2, 1, 2, 1),
|
||||
text: '!'
|
||||
}
|
||||
]);
|
||||
|
||||
assert.equal(model.getLinesContent().join('\n'), getValueInSnapshot(snapshot1));
|
||||
});
|
||||
|
||||
test('immutable snapshot 1', () => {
|
||||
const model = TextModel.createFromString('abc\ndef');
|
||||
const snapshot = model.createSnapshot();
|
||||
model.applyEdits([
|
||||
{
|
||||
range: new Range(2, 1, 2, 4),
|
||||
text: ''
|
||||
}
|
||||
]);
|
||||
|
||||
model.applyEdits([
|
||||
{
|
||||
range: new Range(1, 1, 2, 1),
|
||||
text: 'abc\ndef'
|
||||
}
|
||||
]);
|
||||
|
||||
assert.equal(model.getLinesContent().join('\n'), getValueInSnapshot(snapshot));
|
||||
});
|
||||
|
||||
test('immutable snapshot 2', () => {
|
||||
const model = TextModel.createFromString('abc\ndef');
|
||||
const snapshot = model.createSnapshot();
|
||||
model.applyEdits([
|
||||
{
|
||||
range: new Range(2, 1, 2, 1),
|
||||
text: '!'
|
||||
}
|
||||
]);
|
||||
|
||||
model.applyEdits([
|
||||
{
|
||||
range: new Range(2, 1, 2, 2),
|
||||
text: ''
|
||||
}
|
||||
]);
|
||||
|
||||
assert.equal(model.getLinesContent().join('\n'), getValueInSnapshot(snapshot));
|
||||
});
|
||||
|
||||
test('immutable snapshot 3', () => {
|
||||
const model = TextModel.createFromString('abc\ndef');
|
||||
model.applyEdits([
|
||||
{
|
||||
range: new Range(2, 4, 2, 4),
|
||||
text: '!'
|
||||
}
|
||||
]);
|
||||
const snapshot = model.createSnapshot();
|
||||
model.applyEdits([
|
||||
{
|
||||
range: new Range(2, 5, 2, 5),
|
||||
text: '!'
|
||||
}
|
||||
]);
|
||||
|
||||
assert.notEqual(model.getLinesContent().join('\n'), getValueInSnapshot(snapshot));
|
||||
});
|
||||
});
|
||||
|
||||
suite('chunk based search', () => {
|
||||
test('#45892. For some cases, the buffer is empty but we still try to search', () => {
|
||||
let pieceTree = createTextBuffer(['']);
|
||||
pieceTree.delete(0, 1);
|
||||
let ret = pieceTree.findMatchesLineByLine(new Range(1, 1, 1, 1), new SearchData(/abc/, new WordCharacterClassifier(',./'), 'abc'), true, 1000);
|
||||
assert.equal(ret.length, 0);
|
||||
});
|
||||
|
||||
test('#45770. FindInNode should not cross node boundary.', () => {
|
||||
let pieceTree = createTextBuffer([
|
||||
[
|
||||
'balabalababalabalababalabalaba',
|
||||
'balabalababalabalababalabalaba',
|
||||
'',
|
||||
'* [ ] task1',
|
||||
'* [x] task2 balabalaba',
|
||||
'* [ ] task 3'
|
||||
].join('\n')
|
||||
]);
|
||||
pieceTree.delete(0, 62);
|
||||
pieceTree.delete(16, 1);
|
||||
|
||||
pieceTree.insert(16, ' ');
|
||||
let ret = pieceTree.findMatchesLineByLine(new Range(1, 1, 4, 13), new SearchData(/\[/gi, new WordCharacterClassifier(',./'), '['), true, 1000);
|
||||
assert.equal(ret.length, 3);
|
||||
|
||||
assert.deepEqual(ret[0].range, new Range(2, 3, 2, 4));
|
||||
assert.deepEqual(ret[1].range, new Range(3, 3, 3, 4));
|
||||
assert.deepEqual(ret[2].range, new Range(4, 3, 4, 4));
|
||||
});
|
||||
|
||||
test('search searching from the middle', () => {
|
||||
let pieceTree = createTextBuffer([
|
||||
[
|
||||
'def',
|
||||
'dbcabc'
|
||||
].join('\n')
|
||||
]);
|
||||
pieceTree.delete(4, 1);
|
||||
let ret = pieceTree.findMatchesLineByLine(new Range(2, 3, 2, 6), new SearchData(/a/gi, null, 'a'), true, 1000);
|
||||
assert.equal(ret.length, 1);
|
||||
assert.deepEqual(ret[0].range, new Range(2, 3, 2, 4));
|
||||
|
||||
pieceTree.delete(4, 1);
|
||||
ret = pieceTree.findMatchesLineByLine(new Range(2, 2, 2, 5), new SearchData(/a/gi, null, 'a'), true, 1000);
|
||||
assert.equal(ret.length, 1);
|
||||
assert.deepEqual(ret[0].range, new Range(2, 2, 2, 3));
|
||||
});
|
||||
});
|
||||
@@ -8,18 +8,16 @@ import * as assert from 'assert';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { TextModel, createTextBuffer } from 'vs/editor/common/model/textModel';
|
||||
import { DefaultEndOfLine } from 'vs/editor/common/model';
|
||||
import { UTF8_BOM_CHARACTER } from 'vs/base/common/strings';
|
||||
import { createTextModel } from 'vs/editor/test/common/editorTestUtils';
|
||||
|
||||
function testGuessIndentation(defaultInsertSpaces: boolean, defaultTabSize: number, expectedInsertSpaces: boolean, expectedTabSize: number, text: string[], msg?: string): void {
|
||||
var m = TextModel.createFromString(
|
||||
var m = createTextModel(
|
||||
text.join('\n'),
|
||||
{
|
||||
tabSize: defaultTabSize,
|
||||
insertSpaces: defaultInsertSpaces,
|
||||
detectIndentation: true,
|
||||
defaultEOL: DefaultEndOfLine.LF,
|
||||
trimAutoWhitespace: true
|
||||
detectIndentation: true
|
||||
}
|
||||
);
|
||||
var r = m.getOptions();
|
||||
@@ -705,13 +703,9 @@ suite('Editor Model - TextModel', () => {
|
||||
});
|
||||
|
||||
test('normalizeIndentation 1', () => {
|
||||
let model = TextModel.createFromString('',
|
||||
let model = createTextModel('',
|
||||
{
|
||||
detectIndentation: false,
|
||||
tabSize: 4,
|
||||
insertSpaces: false,
|
||||
trimAutoWhitespace: true,
|
||||
defaultEOL: DefaultEndOfLine.LF
|
||||
insertSpaces: false
|
||||
}
|
||||
);
|
||||
|
||||
@@ -741,15 +735,7 @@ suite('Editor Model - TextModel', () => {
|
||||
});
|
||||
|
||||
test('normalizeIndentation 2', () => {
|
||||
let model = TextModel.createFromString('',
|
||||
{
|
||||
detectIndentation: false,
|
||||
tabSize: 4,
|
||||
insertSpaces: true,
|
||||
trimAutoWhitespace: true,
|
||||
defaultEOL: DefaultEndOfLine.LF
|
||||
}
|
||||
);
|
||||
let model = createTextModel('');
|
||||
|
||||
assert.equal(model.normalizeIndentation('\ta'), ' a');
|
||||
assert.equal(model.normalizeIndentation(' a'), ' a');
|
||||
|
||||
@@ -366,6 +366,31 @@ suite('TextModelWithTokens regression tests', () => {
|
||||
model.dispose();
|
||||
registration.dispose();
|
||||
});
|
||||
|
||||
test('issue #11856: Bracket matching does not work as expected if the opening brace symbol is contained in the closing brace symbol', () => {
|
||||
|
||||
const languageIdentifier = new LanguageIdentifier('testMode', LanguageId.PlainText);
|
||||
|
||||
let registration = LanguageConfigurationRegistry.register(languageIdentifier, {
|
||||
brackets: [
|
||||
['sequence', 'endsequence'],
|
||||
['feature', 'endfeature']
|
||||
]
|
||||
});
|
||||
|
||||
let model = TextModel.createFromString([
|
||||
'sequence "outer"',
|
||||
' sequence "inner"',
|
||||
' endsequence',
|
||||
'endsequence',
|
||||
].join('\n'), undefined, languageIdentifier);
|
||||
|
||||
let actual = model.matchBracket(new Position(3, 9));
|
||||
assert.deepEqual(actual, [new Range(3, 6, 3, 17), new Range(2, 6, 2, 14)]);
|
||||
|
||||
model.dispose();
|
||||
registration.dispose();
|
||||
});
|
||||
});
|
||||
|
||||
suite('TextModel.getLineIndentGuide', () => {
|
||||
@@ -380,10 +405,39 @@ suite('TextModel.getLineIndentGuide', () => {
|
||||
actual[line - 1] = [actualIndents[line - 1], model.getLineContent(line)];
|
||||
}
|
||||
|
||||
// let expected = lines.map(l => l[0]);
|
||||
|
||||
assert.deepEqual(actual, lines);
|
||||
|
||||
// Also test getActiveIndentGuide
|
||||
for (let lineNumber = 1; lineNumber <= model.getLineCount(); lineNumber++) {
|
||||
let startLineNumber = lineNumber;
|
||||
let endLineNumber = lineNumber;
|
||||
let indent = actualIndents[lineNumber - 1];
|
||||
|
||||
if (indent !== 0) {
|
||||
for (let i = lineNumber - 1; i >= 1; i--) {
|
||||
const currIndent = actualIndents[i - 1];
|
||||
if (currIndent >= indent) {
|
||||
startLineNumber = i;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (let i = lineNumber + 1; i <= model.getLineCount(); i++) {
|
||||
const currIndent = actualIndents[i - 1];
|
||||
if (currIndent >= indent) {
|
||||
endLineNumber = i;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const expected = { startLineNumber, endLineNumber, indent };
|
||||
const actual = model.getActiveIndentGuide(lineNumber, 1, model.getLineCount());
|
||||
|
||||
assert.deepEqual(actual, expected, `line number ${lineNumber}`);
|
||||
}
|
||||
|
||||
model.dispose();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user