mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-15 02:48:30 -05:00
Merge VS Code 1.21 source code (#1067)
* Initial VS Code 1.21 file copy with patches * A few more merges * Post npm install * Fix batch of build breaks * Fix more build breaks * Fix more build errors * Fix more build breaks * Runtime fixes 1 * Get connection dialog working with some todos * Fix a few packaging issues * Copy several node_modules to package build to fix loader issues * Fix breaks from master * A few more fixes * Make tests pass * First pass of license header updates * Second pass of license header updates * Fix restore dialog issues * Remove add additional themes menu items * fix select box issues where the list doesn't show up * formatting * Fix editor dispose issue * Copy over node modules to correct location on all platforms
This commit is contained in:
@@ -0,0 +1,519 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { Range } from 'vs/editor/common/core/range';
|
||||
import { LinesTextBuffer, IValidatedEditOperation } from 'vs/editor/common/model/linesTextBuffer/linesTextBuffer';
|
||||
|
||||
suite('LinesTextBuffer._getInverseEdits', () => {
|
||||
|
||||
function editOp(startLineNumber: number, startColumn: number, endLineNumber: number, endColumn: number, text: string[]): IValidatedEditOperation {
|
||||
return {
|
||||
sortIndex: 0,
|
||||
identifier: null,
|
||||
range: new Range(startLineNumber, startColumn, endLineNumber, endColumn),
|
||||
rangeOffset: 0,
|
||||
rangeLength: 0,
|
||||
lines: text,
|
||||
forceMoveMarkers: false,
|
||||
isAutoWhitespaceEdit: false
|
||||
};
|
||||
}
|
||||
|
||||
function inverseEditOp(startLineNumber: number, startColumn: number, endLineNumber: number, endColumn: number): Range {
|
||||
return new Range(startLineNumber, startColumn, endLineNumber, endColumn);
|
||||
}
|
||||
|
||||
function assertInverseEdits(ops: IValidatedEditOperation[], expected: Range[]): void {
|
||||
var actual = LinesTextBuffer._getInverseEditRanges(ops);
|
||||
assert.deepEqual(actual, expected);
|
||||
}
|
||||
|
||||
test('single insert', () => {
|
||||
assertInverseEdits(
|
||||
[
|
||||
editOp(1, 1, 1, 1, ['hello'])
|
||||
],
|
||||
[
|
||||
inverseEditOp(1, 1, 1, 6)
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
test('Bug 19872: Undo is funky', () => {
|
||||
assertInverseEdits(
|
||||
[
|
||||
editOp(2, 1, 2, 2, ['']),
|
||||
editOp(3, 1, 4, 2, [''])
|
||||
],
|
||||
[
|
||||
inverseEditOp(2, 1, 2, 1),
|
||||
inverseEditOp(3, 1, 3, 1)
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
test('two single unrelated inserts', () => {
|
||||
assertInverseEdits(
|
||||
[
|
||||
editOp(1, 1, 1, 1, ['hello']),
|
||||
editOp(2, 1, 2, 1, ['world'])
|
||||
],
|
||||
[
|
||||
inverseEditOp(1, 1, 1, 6),
|
||||
inverseEditOp(2, 1, 2, 6)
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
test('two single inserts 1', () => {
|
||||
assertInverseEdits(
|
||||
[
|
||||
editOp(1, 1, 1, 1, ['hello']),
|
||||
editOp(1, 2, 1, 2, ['world'])
|
||||
],
|
||||
[
|
||||
inverseEditOp(1, 1, 1, 6),
|
||||
inverseEditOp(1, 7, 1, 12)
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
test('two single inserts 2', () => {
|
||||
assertInverseEdits(
|
||||
[
|
||||
editOp(1, 1, 1, 1, ['hello']),
|
||||
editOp(1, 4, 1, 4, ['world'])
|
||||
],
|
||||
[
|
||||
inverseEditOp(1, 1, 1, 6),
|
||||
inverseEditOp(1, 9, 1, 14)
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
test('multiline insert', () => {
|
||||
assertInverseEdits(
|
||||
[
|
||||
editOp(1, 1, 1, 1, ['hello', 'world'])
|
||||
],
|
||||
[
|
||||
inverseEditOp(1, 1, 2, 6)
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
test('two unrelated multiline inserts', () => {
|
||||
assertInverseEdits(
|
||||
[
|
||||
editOp(1, 1, 1, 1, ['hello', 'world']),
|
||||
editOp(2, 1, 2, 1, ['how', 'are', 'you?']),
|
||||
],
|
||||
[
|
||||
inverseEditOp(1, 1, 2, 6),
|
||||
inverseEditOp(3, 1, 5, 5),
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
test('two multiline inserts 1', () => {
|
||||
assertInverseEdits(
|
||||
[
|
||||
editOp(1, 1, 1, 1, ['hello', 'world']),
|
||||
editOp(1, 2, 1, 2, ['how', 'are', 'you?']),
|
||||
],
|
||||
[
|
||||
inverseEditOp(1, 1, 2, 6),
|
||||
inverseEditOp(2, 7, 4, 5),
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
test('single delete', () => {
|
||||
assertInverseEdits(
|
||||
[
|
||||
editOp(1, 1, 1, 6, null)
|
||||
],
|
||||
[
|
||||
inverseEditOp(1, 1, 1, 1)
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
test('two single unrelated deletes', () => {
|
||||
assertInverseEdits(
|
||||
[
|
||||
editOp(1, 1, 1, 6, null),
|
||||
editOp(2, 1, 2, 6, null)
|
||||
],
|
||||
[
|
||||
inverseEditOp(1, 1, 1, 1),
|
||||
inverseEditOp(2, 1, 2, 1)
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
test('two single deletes 1', () => {
|
||||
assertInverseEdits(
|
||||
[
|
||||
editOp(1, 1, 1, 6, null),
|
||||
editOp(1, 7, 1, 12, null)
|
||||
],
|
||||
[
|
||||
inverseEditOp(1, 1, 1, 1),
|
||||
inverseEditOp(1, 2, 1, 2)
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
test('two single deletes 2', () => {
|
||||
assertInverseEdits(
|
||||
[
|
||||
editOp(1, 1, 1, 6, null),
|
||||
editOp(1, 9, 1, 14, null)
|
||||
],
|
||||
[
|
||||
inverseEditOp(1, 1, 1, 1),
|
||||
inverseEditOp(1, 4, 1, 4)
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
test('multiline delete', () => {
|
||||
assertInverseEdits(
|
||||
[
|
||||
editOp(1, 1, 2, 6, null)
|
||||
],
|
||||
[
|
||||
inverseEditOp(1, 1, 1, 1)
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
test('two unrelated multiline deletes', () => {
|
||||
assertInverseEdits(
|
||||
[
|
||||
editOp(1, 1, 2, 6, null),
|
||||
editOp(3, 1, 5, 5, null),
|
||||
],
|
||||
[
|
||||
inverseEditOp(1, 1, 1, 1),
|
||||
inverseEditOp(2, 1, 2, 1),
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
test('two multiline deletes 1', () => {
|
||||
assertInverseEdits(
|
||||
[
|
||||
editOp(1, 1, 2, 6, null),
|
||||
editOp(2, 7, 4, 5, null),
|
||||
],
|
||||
[
|
||||
inverseEditOp(1, 1, 1, 1),
|
||||
inverseEditOp(1, 2, 1, 2),
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
test('single replace', () => {
|
||||
assertInverseEdits(
|
||||
[
|
||||
editOp(1, 1, 1, 6, ['Hello world'])
|
||||
],
|
||||
[
|
||||
inverseEditOp(1, 1, 1, 12)
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
test('two replaces', () => {
|
||||
assertInverseEdits(
|
||||
[
|
||||
editOp(1, 1, 1, 6, ['Hello world']),
|
||||
editOp(1, 7, 1, 8, ['How are you?']),
|
||||
],
|
||||
[
|
||||
inverseEditOp(1, 1, 1, 12),
|
||||
inverseEditOp(1, 13, 1, 25)
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
test('many edits', () => {
|
||||
assertInverseEdits(
|
||||
[
|
||||
editOp(1, 2, 1, 2, ['', ' ']),
|
||||
editOp(1, 5, 1, 6, ['']),
|
||||
editOp(1, 9, 1, 9, ['', ''])
|
||||
],
|
||||
[
|
||||
inverseEditOp(1, 2, 2, 3),
|
||||
inverseEditOp(2, 6, 2, 6),
|
||||
inverseEditOp(2, 9, 3, 1)
|
||||
]
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
suite('LinesTextBuffer._toSingleEditOperation', () => {
|
||||
|
||||
function editOp(startLineNumber: number, startColumn: number, endLineNumber: number, endColumn: number, rangeOffset: number, rangeLength: number, text: string[]): IValidatedEditOperation {
|
||||
return {
|
||||
sortIndex: 0,
|
||||
identifier: null,
|
||||
range: new Range(startLineNumber, startColumn, endLineNumber, endColumn),
|
||||
rangeOffset: rangeOffset,
|
||||
rangeLength: rangeLength,
|
||||
lines: text,
|
||||
forceMoveMarkers: false,
|
||||
isAutoWhitespaceEdit: false
|
||||
};
|
||||
}
|
||||
|
||||
function testToSingleEditOperation(original: string[], edits: IValidatedEditOperation[], expected: IValidatedEditOperation): void {
|
||||
const textBuffer = new LinesTextBuffer({
|
||||
BOM: '',
|
||||
EOL: '\n',
|
||||
containsRTL: false,
|
||||
isBasicASCII: true,
|
||||
lines: original
|
||||
});
|
||||
|
||||
const actual = textBuffer._toSingleEditOperation(edits);
|
||||
assert.deepEqual(actual, expected);
|
||||
}
|
||||
|
||||
test('one edit op is unchanged', () => {
|
||||
testToSingleEditOperation(
|
||||
[
|
||||
'My First Line',
|
||||
'\t\tMy Second Line',
|
||||
' Third Line',
|
||||
'',
|
||||
'1'
|
||||
],
|
||||
[
|
||||
editOp(1, 3, 1, 3, 2, 0, [' new line', 'No longer'])
|
||||
],
|
||||
editOp(1, 3, 1, 3, 2, 0, [' new line', 'No longer'])
|
||||
);
|
||||
});
|
||||
|
||||
test('two edits on one line', () => {
|
||||
testToSingleEditOperation([
|
||||
'My First Line',
|
||||
'\t\tMy Second Line',
|
||||
' Third Line',
|
||||
'',
|
||||
'1'
|
||||
], [
|
||||
editOp(1, 1, 1, 3, 0, 2, ['Your']),
|
||||
editOp(1, 4, 1, 4, 3, 0, ['Interesting ']),
|
||||
editOp(2, 3, 2, 6, 16, 3, null)
|
||||
],
|
||||
editOp(1, 1, 2, 6, 0, 19, [
|
||||
'Your Interesting First Line',
|
||||
'\t\t'
|
||||
]));
|
||||
});
|
||||
|
||||
test('insert multiple newlines', () => {
|
||||
testToSingleEditOperation(
|
||||
[
|
||||
'My First Line',
|
||||
'\t\tMy Second Line',
|
||||
' Third Line',
|
||||
'',
|
||||
'1'
|
||||
],
|
||||
[
|
||||
editOp(1, 3, 1, 3, 2, 0, ['', '', '', '', '']),
|
||||
editOp(3, 15, 3, 15, 45, 0, ['a', 'b'])
|
||||
],
|
||||
editOp(1, 3, 3, 15, 2, 43, [
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
' First Line',
|
||||
'\t\tMy Second Line',
|
||||
' Third Linea',
|
||||
'b'
|
||||
])
|
||||
);
|
||||
});
|
||||
|
||||
test('delete empty text', () => {
|
||||
testToSingleEditOperation(
|
||||
[
|
||||
'My First Line',
|
||||
'\t\tMy Second Line',
|
||||
' Third Line',
|
||||
'',
|
||||
'1'
|
||||
],
|
||||
[
|
||||
editOp(1, 1, 1, 1, 0, 0, [''])
|
||||
],
|
||||
editOp(1, 1, 1, 1, 0, 0, [''])
|
||||
);
|
||||
});
|
||||
|
||||
test('two unrelated edits', () => {
|
||||
testToSingleEditOperation(
|
||||
[
|
||||
'My First Line',
|
||||
'\t\tMy Second Line',
|
||||
' Third Line',
|
||||
'',
|
||||
'123'
|
||||
],
|
||||
[
|
||||
editOp(2, 1, 2, 3, 14, 2, ['\t']),
|
||||
editOp(3, 1, 3, 5, 31, 4, [''])
|
||||
],
|
||||
editOp(2, 1, 3, 5, 14, 21, ['\tMy Second Line', ''])
|
||||
);
|
||||
});
|
||||
|
||||
test('many edits', () => {
|
||||
testToSingleEditOperation(
|
||||
[
|
||||
'{"x" : 1}'
|
||||
],
|
||||
[
|
||||
editOp(1, 2, 1, 2, 1, 0, ['\n ']),
|
||||
editOp(1, 5, 1, 6, 4, 1, ['']),
|
||||
editOp(1, 9, 1, 9, 8, 0, ['\n'])
|
||||
],
|
||||
editOp(1, 2, 1, 9, 1, 7, [
|
||||
'',
|
||||
' "x": 1',
|
||||
''
|
||||
])
|
||||
);
|
||||
});
|
||||
|
||||
test('many edits reversed', () => {
|
||||
testToSingleEditOperation(
|
||||
[
|
||||
'{',
|
||||
' "x": 1',
|
||||
'}'
|
||||
],
|
||||
[
|
||||
editOp(1, 2, 2, 3, 1, 3, ['']),
|
||||
editOp(2, 6, 2, 6, 7, 0, [' ']),
|
||||
editOp(2, 9, 3, 1, 10, 1, [''])
|
||||
],
|
||||
editOp(1, 2, 3, 1, 1, 10, ['"x" : 1'])
|
||||
);
|
||||
});
|
||||
|
||||
test('replacing newlines 1', () => {
|
||||
testToSingleEditOperation(
|
||||
[
|
||||
'{',
|
||||
'"a": true,',
|
||||
'',
|
||||
'"b": true',
|
||||
'}'
|
||||
],
|
||||
[
|
||||
editOp(1, 2, 2, 1, 1, 1, ['', '\t']),
|
||||
editOp(2, 11, 4, 1, 12, 2, ['', '\t'])
|
||||
],
|
||||
editOp(1, 2, 4, 1, 1, 13, [
|
||||
'',
|
||||
'\t"a": true,',
|
||||
'\t'
|
||||
])
|
||||
);
|
||||
});
|
||||
|
||||
test('replacing newlines 2', () => {
|
||||
testToSingleEditOperation(
|
||||
[
|
||||
'some text',
|
||||
'some more text',
|
||||
'now comes an empty line',
|
||||
'',
|
||||
'after empty line',
|
||||
'and the last line'
|
||||
],
|
||||
[
|
||||
editOp(1, 5, 3, 1, 4, 21, [' text', 'some more text', 'some more text']),
|
||||
editOp(3, 2, 4, 1, 26, 23, ['o more lines', 'asd', 'asd', 'asd']),
|
||||
editOp(5, 1, 5, 6, 50, 5, ['zzzzzzzz']),
|
||||
editOp(5, 11, 6, 16, 60, 22, ['1', '2', '3', '4'])
|
||||
],
|
||||
editOp(1, 5, 6, 16, 4, 78, [
|
||||
' text',
|
||||
'some more text',
|
||||
'some more textno more lines',
|
||||
'asd',
|
||||
'asd',
|
||||
'asd',
|
||||
'zzzzzzzz empt1',
|
||||
'2',
|
||||
'3',
|
||||
'4'
|
||||
])
|
||||
);
|
||||
});
|
||||
|
||||
test('advanced', () => {
|
||||
testToSingleEditOperation(
|
||||
[
|
||||
' { "d": [',
|
||||
' null',
|
||||
' ] /*comment*/',
|
||||
' ,"e": /*comment*/ [null] }',
|
||||
],
|
||||
[
|
||||
editOp(1, 1, 1, 2, 0, 1, ['']),
|
||||
editOp(1, 3, 1, 10, 2, 7, ['', ' ']),
|
||||
editOp(1, 16, 2, 14, 15, 14, ['', ' ']),
|
||||
editOp(2, 18, 3, 9, 33, 9, ['', ' ']),
|
||||
editOp(3, 22, 4, 9, 55, 9, ['']),
|
||||
editOp(4, 10, 4, 10, 65, 0, ['', ' ']),
|
||||
editOp(4, 28, 4, 28, 83, 0, ['', ' ']),
|
||||
editOp(4, 32, 4, 32, 87, 0, ['', ' ']),
|
||||
editOp(4, 33, 4, 34, 88, 1, ['', ''])
|
||||
],
|
||||
editOp(1, 1, 4, 34, 0, 89, [
|
||||
'{',
|
||||
' "d": [',
|
||||
' null',
|
||||
' ] /*comment*/,',
|
||||
' "e": /*comment*/ [',
|
||||
' null',
|
||||
' ]',
|
||||
''
|
||||
])
|
||||
);
|
||||
});
|
||||
|
||||
test('advanced simplified', () => {
|
||||
testToSingleEditOperation(
|
||||
[
|
||||
' abc',
|
||||
' ,def'
|
||||
],
|
||||
[
|
||||
editOp(1, 1, 1, 4, 0, 3, ['']),
|
||||
editOp(1, 7, 2, 2, 6, 2, ['']),
|
||||
editOp(2, 3, 2, 3, 9, 0, ['', ''])
|
||||
],
|
||||
editOp(1, 1, 2, 3, 0, 9, [
|
||||
'abc,',
|
||||
''
|
||||
])
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,154 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { LinesTextBufferBuilder } from 'vs/editor/common/model/linesTextBuffer/linesTextBufferBuilder';
|
||||
import { ITextModelCreationOptions } from 'vs/editor/common/model';
|
||||
import { TextModel } from 'vs/editor/common/model/textModel';
|
||||
import * as strings from 'vs/base/common/strings';
|
||||
import { IRawTextSource } from 'vs/editor/common/model/linesTextBuffer/textSource';
|
||||
|
||||
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++;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
suite('ModelBuilder', () => {
|
||||
|
||||
test('no chunks', () => {
|
||||
testModelBuilder([]);
|
||||
});
|
||||
|
||||
test('single empty chunk', () => {
|
||||
testModelBuilder(['']);
|
||||
});
|
||||
|
||||
test('single line in one chunk', () => {
|
||||
testModelBuilder(['Hello world']);
|
||||
});
|
||||
|
||||
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('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?']);
|
||||
});
|
||||
|
||||
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?']);
|
||||
});
|
||||
|
||||
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?']);
|
||||
});
|
||||
|
||||
test('BOM handling', () => {
|
||||
testModelBuilder([strings.UTF8_BOM_CHARACTER + 'Hello world!']);
|
||||
});
|
||||
|
||||
test('BOM handling', () => {
|
||||
testModelBuilder([strings.UTF8_BOM_CHARACTER, 'Hello world!']);
|
||||
});
|
||||
|
||||
test('RTL handling 1', () => {
|
||||
testModelBuilder(['Hello world!', 'זוהי עובדה מבוססת שדעתו']);
|
||||
});
|
||||
|
||||
test('RTL handling 2', () => {
|
||||
testModelBuilder(['Hello world!זוהי עובדה מבוססת שדעתו']);
|
||||
});
|
||||
|
||||
test('RTL handling 3', () => {
|
||||
testModelBuilder(['Hello world!זוהי \nעובדה מבוססת שדעתו']);
|
||||
});
|
||||
|
||||
test('ASCII handling 1', () => {
|
||||
testModelBuilder(['Hello world!!\nHow do you do?']);
|
||||
});
|
||||
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']);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,97 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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++));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { CharCode } from 'vs/base/common/charCode';
|
||||
import { IIdentifiedSingleEditOperation, DefaultEndOfLine, ITextBufferBuilder, ITextBuffer } from 'vs/editor/common/model';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
|
||||
export function getRandomInt(min: number, max: number): number {
|
||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||
}
|
||||
|
||||
export function getRandomEOLSequence(): string {
|
||||
let rnd = getRandomInt(1, 3);
|
||||
if (rnd === 1) {
|
||||
return '\n';
|
||||
}
|
||||
if (rnd === 2) {
|
||||
return '\r';
|
||||
}
|
||||
return '\r\n';
|
||||
}
|
||||
|
||||
export function getRandomString(minLength: number, maxLength: number): string {
|
||||
let length = getRandomInt(minLength, maxLength);
|
||||
let r = '';
|
||||
for (let i = 0; i < length; i++) {
|
||||
r += String.fromCharCode(getRandomInt(CharCode.a, CharCode.z));
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
export function generateRandomEdits(chunks: string[], editCnt: number): IIdentifiedSingleEditOperation[] {
|
||||
let lines = [];
|
||||
for (let i = 0; i < chunks.length; i++) {
|
||||
let newLines = chunks[i].split(/\r\n|\r|\n/);
|
||||
if (lines.length === 0) {
|
||||
lines.push(...newLines);
|
||||
} else {
|
||||
newLines[0] = lines[lines.length - 1] + newLines[0];
|
||||
lines.splice(lines.length - 1, 1, ...newLines);
|
||||
}
|
||||
}
|
||||
|
||||
let ops: IIdentifiedSingleEditOperation[] = [];
|
||||
|
||||
for (let i = 0; i < editCnt; i++) {
|
||||
let line = getRandomInt(1, lines.length);
|
||||
let startColumn = getRandomInt(1, Math.max(lines[line - 1].length, 1));
|
||||
let endColumn = getRandomInt(startColumn, Math.max(lines[line - 1].length, startColumn));
|
||||
let text: string = '';
|
||||
if (Math.random() < .5) {
|
||||
text = getRandomString(5, 10);
|
||||
}
|
||||
|
||||
ops.push({
|
||||
text: text,
|
||||
range: new Range(line, startColumn, line, endColumn)
|
||||
});
|
||||
lines[line - 1] = lines[line - 1].substring(0, startColumn - 1) + text + lines[line - 1].substring(endColumn - 1);
|
||||
}
|
||||
|
||||
return ops;
|
||||
}
|
||||
|
||||
export function generateSequentialInserts(chunks: string[], editCnt: number): IIdentifiedSingleEditOperation[] {
|
||||
let lines = [];
|
||||
for (let i = 0; i < chunks.length; i++) {
|
||||
let newLines = chunks[i].split(/\r\n|\r|\n/);
|
||||
if (lines.length === 0) {
|
||||
lines.push(...newLines);
|
||||
} else {
|
||||
newLines[0] = lines[lines.length - 1] + newLines[0];
|
||||
lines.splice(lines.length - 1, 1, ...newLines);
|
||||
}
|
||||
}
|
||||
|
||||
let ops: IIdentifiedSingleEditOperation[] = [];
|
||||
|
||||
for (let i = 0; i < editCnt; i++) {
|
||||
let line = lines.length;
|
||||
let column = lines[line - 1].length + 1;
|
||||
let text: string = '';
|
||||
if (Math.random() < .5) {
|
||||
text = '\n';
|
||||
lines.push('');
|
||||
} else {
|
||||
text = getRandomString(1, 2);
|
||||
lines[line - 1] += text;
|
||||
}
|
||||
|
||||
ops.push({
|
||||
text: text,
|
||||
range: new Range(line, column, line, column)
|
||||
});
|
||||
}
|
||||
|
||||
return ops;
|
||||
}
|
||||
|
||||
export function generateRandomReplaces(chunks: string[], editCnt: number, searchStringLen: number, replaceStringLen: number): IIdentifiedSingleEditOperation[] {
|
||||
let lines = [];
|
||||
for (let i = 0; i < chunks.length; i++) {
|
||||
let newLines = chunks[i].split(/\r\n|\r|\n/);
|
||||
if (lines.length === 0) {
|
||||
lines.push(...newLines);
|
||||
} else {
|
||||
newLines[0] = lines[lines.length - 1] + newLines[0];
|
||||
lines.splice(lines.length - 1, 1, ...newLines);
|
||||
}
|
||||
}
|
||||
|
||||
let ops: IIdentifiedSingleEditOperation[] = [];
|
||||
let chunkSize = Math.max(1, Math.floor(lines.length / editCnt));
|
||||
let chunkCnt = Math.floor(lines.length / chunkSize);
|
||||
let replaceString = getRandomString(replaceStringLen, replaceStringLen);
|
||||
|
||||
let previousChunksLength = 0;
|
||||
for (let i = 0; i < chunkCnt; i++) {
|
||||
let startLine = previousChunksLength + 1;
|
||||
let endLine = previousChunksLength + chunkSize;
|
||||
let line = getRandomInt(startLine, endLine);
|
||||
let maxColumn = lines[line - 1].length + 1;
|
||||
let startColumn = getRandomInt(1, maxColumn);
|
||||
let endColumn = Math.min(maxColumn, startColumn + searchStringLen);
|
||||
|
||||
ops.push({
|
||||
text: replaceString,
|
||||
range: new Range(line, startColumn, line, endColumn)
|
||||
});
|
||||
previousChunksLength = endLine;
|
||||
}
|
||||
|
||||
return ops;
|
||||
}
|
||||
|
||||
export function createMockText(lineCount: number, minColumn: number, maxColumn: number) {
|
||||
let fixedEOL = getRandomEOLSequence();
|
||||
let lines: string[] = [];
|
||||
for (let i = 0; i < lineCount; i++) {
|
||||
if (i !== 0) {
|
||||
lines.push(fixedEOL);
|
||||
}
|
||||
lines.push(getRandomString(minColumn, maxColumn));
|
||||
}
|
||||
return lines.join('');
|
||||
}
|
||||
|
||||
export function createMockBuffer(str: string, bufferBuilder: ITextBufferBuilder): ITextBuffer {
|
||||
bufferBuilder.acceptChunk(str);
|
||||
let bufferFactory = bufferBuilder.finish();
|
||||
let buffer = bufferFactory.create(DefaultEndOfLine.LF);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
export function generateRandomChunkWithLF(minLength: number, maxLength: number): string {
|
||||
let length = getRandomInt(minLength, maxLength);
|
||||
let r = '';
|
||||
for (let i = 0; i < length; i++) {
|
||||
let randomI = getRandomInt(0, CharCode.z - CharCode.a + 1);
|
||||
if (randomI === 0 && Math.random() < 0.3) {
|
||||
r += '\n';
|
||||
} else {
|
||||
r += String.fromCharCode(randomI + CharCode.a - 1);
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
Reference in New Issue
Block a user