Merge VS Code 1.23.1 (#1520)

This commit is contained in:
Matt Irvine
2018-06-05 11:24:51 -07:00
committed by GitHub
parent e3baf5c443
commit 0c58f09e59
3651 changed files with 74249 additions and 48599 deletions

View File

@@ -89,7 +89,7 @@ suite('Common Editor Config', () => {
wordWrap: <any>true
});
// {{SQL CARBON EDIT}}
assertWrapping(config, true, 89);
assertWrapping(config, true, 88);
});
test('wordWrap on', () => {
@@ -97,7 +97,7 @@ suite('Common Editor Config', () => {
wordWrap: 'on'
});
// {{SQL CARBON EDIT}}
assertWrapping(config, true, 89);
assertWrapping(config, true, 88);
});
test('wordWrap on without minimap', () => {
@@ -107,7 +107,7 @@ suite('Common Editor Config', () => {
enabled: false
}
});
assertWrapping(config, true, 89);
assertWrapping(config, true, 88);
});
test('wordWrap on does not use wordWrapColumn', () => {
@@ -116,7 +116,7 @@ suite('Common Editor Config', () => {
wordWrapColumn: 10
});
// {{SQL CARBON EDIT}}
assertWrapping(config, true, 89);
assertWrapping(config, true, 88);
});
test('wordWrap off', () => {

View File

@@ -92,6 +92,10 @@ export class ViewLineTokens implements IViewLineTokens {
public getInlineStyle(tokenIndex: number, colorMap: string[]): string {
return this._actual[tokenIndex].getInlineStyle(colorMap);
}
public findTokenIndexAtOffset(offset: number): number {
throw new Error('Not implemented');
}
}
export class ViewLineTokenFactory {

View File

@@ -673,4 +673,23 @@ suite('Editor Diff - DiffComputer', () => {
];
assertDiff(original, modified, expected, true, false);
});
test('issue #43922', () => {
let original = [
' * `yarn [install]` -- Install project NPM dependencies. This is automatically done when you first create the project. You should only need to run this if you add dependencies in `package.json`.',
];
let modified = [
' * `yarn` -- Install project NPM dependencies. You should only need to run this if you add dependencies in `package.json`.',
];
var expected = [
createLineChange(
1, 1, 1, 1,
[
createCharChange(1, 9, 1, 19, 0, 0, 0, 0),
createCharChange(1, 58, 1, 120, 0, 0, 0, 0),
]
)
];
assertDiff(original, modified, expected, true, false);
});
});

View File

@@ -5,9 +5,35 @@
'use strict';
import { TextModel } from 'vs/editor/common/model/textModel';
import { DefaultEndOfLine, ITextModelCreationOptions } from 'vs/editor/common/model';
import { LanguageIdentifier } from 'vs/editor/common/modes';
import URI from 'vs/base/common/uri';
export function withEditorModel(text: string[], callback: (model: TextModel) => void): void {
var model = TextModel.createFromString(text.join('\n'));
callback(model);
model.dispose();
}
export interface IRelaxedTextModelCreationOptions {
tabSize?: number;
insertSpaces?: boolean;
detectIndentation?: boolean;
trimAutoWhitespace?: boolean;
defaultEOL?: DefaultEndOfLine;
isForSimpleWidget?: boolean;
largeFileOptimizations?: boolean;
}
export function createTextModel(text: string, _options: IRelaxedTextModelCreationOptions = TextModel.DEFAULT_CREATION_OPTIONS, languageIdentifier: LanguageIdentifier = null, uri: URI = null): TextModel {
const options: ITextModelCreationOptions = {
tabSize: (typeof _options.tabSize === 'undefined' ? TextModel.DEFAULT_CREATION_OPTIONS.tabSize : _options.tabSize),
insertSpaces: (typeof _options.insertSpaces === 'undefined' ? TextModel.DEFAULT_CREATION_OPTIONS.insertSpaces : _options.insertSpaces),
detectIndentation: (typeof _options.detectIndentation === 'undefined' ? TextModel.DEFAULT_CREATION_OPTIONS.detectIndentation : _options.detectIndentation),
trimAutoWhitespace: (typeof _options.trimAutoWhitespace === 'undefined' ? TextModel.DEFAULT_CREATION_OPTIONS.trimAutoWhitespace : _options.trimAutoWhitespace),
defaultEOL: (typeof _options.defaultEOL === 'undefined' ? TextModel.DEFAULT_CREATION_OPTIONS.defaultEOL : _options.defaultEOL),
isForSimpleWidget: (typeof _options.isForSimpleWidget === 'undefined' ? TextModel.DEFAULT_CREATION_OPTIONS.isForSimpleWidget : _options.isForSimpleWidget),
largeFileOptimizations: (typeof _options.largeFileOptimizations === 'undefined' ? TextModel.DEFAULT_CREATION_OPTIONS.largeFileOptimizations : _options.largeFileOptimizations),
};
return TextModel.createFromString(text, options, languageIdentifier, uri);
}

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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);
});
});

View File

@@ -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();
});
});

View File

@@ -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();

View File

@@ -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);

View File

@@ -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(['123']);
test('ASCII handling 2', () => {
testTextBufferFactory('Hello world!!\nHow do you do?Züricha📚📚b', '\n', true, false);
});
});

View File

@@ -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++));
}
}

View File

@@ -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 });
});
});

View File

@@ -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', () => {

View File

@@ -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));
});
});

View File

@@ -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');

View File

@@ -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();
}

View File

@@ -17,18 +17,18 @@ suite('LanguageSelector', function () {
};
test('score, invalid selector', function () {
assert.equal(score({}, model.uri, model.language), 0);
assert.equal(score(undefined, model.uri, model.language), 0);
assert.equal(score(null, model.uri, model.language), 0);
assert.equal(score('', model.uri, model.language), 0);
assert.equal(score({}, model.uri, model.language, true), 0);
assert.equal(score(undefined, model.uri, model.language, true), 0);
assert.equal(score(null, model.uri, model.language, true), 0);
assert.equal(score('', model.uri, model.language, true), 0);
});
test('score, any language', function () {
assert.equal(score({ language: '*' }, model.uri, model.language), 5);
assert.equal(score('*', model.uri, model.language), 5);
assert.equal(score({ language: '*' }, model.uri, model.language, true), 5);
assert.equal(score('*', model.uri, model.language, true), 5);
assert.equal(score('*', URI.parse('foo:bar'), model.language), 5);
assert.equal(score('farboo', URI.parse('foo:bar'), model.language), 10);
assert.equal(score('*', URI.parse('foo:bar'), model.language, true), 5);
assert.equal(score('farboo', URI.parse('foo:bar'), model.language, true), 10);
});
test('score, default schemes', function () {
@@ -36,49 +36,64 @@ suite('LanguageSelector', function () {
const uri = URI.parse('git:foo/file.txt');
const language = 'farboo';
assert.equal(score('*', uri, language), 5);
assert.equal(score('farboo', uri, language), 10);
assert.equal(score({ language: 'farboo', scheme: '' }, uri, language), 10);
assert.equal(score({ language: 'farboo', scheme: 'git' }, uri, language), 10);
assert.equal(score({ language: 'farboo', scheme: '*' }, uri, language), 10);
assert.equal(score({ language: 'farboo' }, uri, language), 10);
assert.equal(score({ language: '*' }, uri, language), 5);
assert.equal(score('*', uri, language, true), 5);
assert.equal(score('farboo', uri, language, true), 10);
assert.equal(score({ language: 'farboo', scheme: '' }, uri, language, true), 10);
assert.equal(score({ language: 'farboo', scheme: 'git' }, uri, language, true), 10);
assert.equal(score({ language: 'farboo', scheme: '*' }, uri, language, true), 10);
assert.equal(score({ language: 'farboo' }, uri, language, true), 10);
assert.equal(score({ language: '*' }, uri, language, true), 5);
assert.equal(score({ scheme: '*' }, uri, language), 5);
assert.equal(score({ scheme: 'git' }, uri, language), 10);
assert.equal(score({ scheme: '*' }, uri, language, true), 5);
assert.equal(score({ scheme: 'git' }, uri, language, true), 10);
});
test('score, filter', function () {
assert.equal(score('farboo', model.uri, model.language), 10);
assert.equal(score({ language: 'farboo' }, model.uri, model.language), 10);
assert.equal(score({ language: 'farboo', scheme: 'file' }, model.uri, model.language), 10);
assert.equal(score({ language: 'farboo', scheme: 'http' }, model.uri, model.language), 0);
assert.equal(score('farboo', model.uri, model.language, true), 10);
assert.equal(score({ language: 'farboo' }, model.uri, model.language, true), 10);
assert.equal(score({ language: 'farboo', scheme: 'file' }, model.uri, model.language, true), 10);
assert.equal(score({ language: 'farboo', scheme: 'http' }, model.uri, model.language, true), 0);
assert.equal(score({ pattern: '**/*.fb' }, model.uri, model.language), 10);
assert.equal(score({ pattern: '**/*.fb', scheme: 'file' }, model.uri, model.language), 10);
assert.equal(score({ pattern: '**/*.fb' }, URI.parse('foo:bar'), model.language), 0);
assert.equal(score({ pattern: '**/*.fb', scheme: 'foo' }, URI.parse('foo:bar'), model.language), 0);
assert.equal(score({ pattern: '**/*.fb' }, model.uri, model.language, true), 10);
assert.equal(score({ pattern: '**/*.fb', scheme: 'file' }, model.uri, model.language, true), 10);
assert.equal(score({ pattern: '**/*.fb' }, URI.parse('foo:bar'), model.language, true), 0);
assert.equal(score({ pattern: '**/*.fb', scheme: 'foo' }, URI.parse('foo:bar'), model.language, true), 0);
let doc = {
uri: URI.parse('git:/my/file.js'),
langId: 'javascript'
};
assert.equal(score('javascript', doc.uri, doc.langId), 10); // 0;
assert.equal(score({ language: 'javascript', scheme: 'git' }, doc.uri, doc.langId), 10); // 10;
assert.equal(score('*', doc.uri, doc.langId), 5); // 5
assert.equal(score('fooLang', doc.uri, doc.langId), 0); // 0
assert.equal(score(['fooLang', '*'], doc.uri, doc.langId), 5); // 5
assert.equal(score('javascript', doc.uri, doc.langId, true), 10); // 0;
assert.equal(score({ language: 'javascript', scheme: 'git' }, doc.uri, doc.langId, true), 10); // 10;
assert.equal(score('*', doc.uri, doc.langId, true), 5); // 5
assert.equal(score('fooLang', doc.uri, doc.langId, true), 0); // 0
assert.equal(score(['fooLang', '*'], doc.uri, doc.langId, true), 5); // 5
});
test('score, max(filters)', function () {
let match = { language: 'farboo', scheme: 'file' };
let fail = { language: 'farboo', scheme: 'http' };
assert.equal(score(match, model.uri, model.language), 10);
assert.equal(score(fail, model.uri, model.language), 0);
assert.equal(score([match, fail], model.uri, model.language), 10);
assert.equal(score([fail, fail], model.uri, model.language), 0);
assert.equal(score(['farboo', '*'], model.uri, model.language), 10);
assert.equal(score(['*', 'farboo'], model.uri, model.language), 10);
assert.equal(score(match, model.uri, model.language, true), 10);
assert.equal(score(fail, model.uri, model.language, true), 0);
assert.equal(score([match, fail], model.uri, model.language, true), 10);
assert.equal(score([fail, fail], model.uri, model.language, true), 0);
assert.equal(score(['farboo', '*'], model.uri, model.language, true), 10);
assert.equal(score(['*', 'farboo'], model.uri, model.language, true), 10);
});
test('score hasAccessToAllModels', function () {
let doc = {
uri: URI.parse('file:/my/file.js'),
langId: 'javascript'
};
assert.equal(score('javascript', doc.uri, doc.langId, false), 0);
assert.equal(score({ language: 'javascript', scheme: 'file' }, doc.uri, doc.langId, false), 0);
assert.equal(score('*', doc.uri, doc.langId, false), 0);
assert.equal(score('fooLang', doc.uri, doc.langId, false), 0);
assert.equal(score(['fooLang', '*'], doc.uri, doc.langId, false), 0);
assert.equal(score({ language: 'javascript', scheme: 'file', hasAccessToAllModels: true }, doc.uri, doc.langId, false), 10);
assert.equal(score(['fooLang', '*', { language: '*', hasAccessToAllModels: true }], doc.uri, doc.langId, false), 5);
});
});

View File

@@ -32,7 +32,7 @@ suite('EditorSimpleWorker', () => {
let model: ICommonModel;
setup(() => {
worker = new WorkerWithModels();
worker = new WorkerWithModels(null);
model = worker.addModel([
'This is line one', //16
'and this is line number two', //27
@@ -168,4 +168,25 @@ suite('EditorSimpleWorker', () => {
assert.equal(suggestions[0].label, 'foobar');
});
});
test('get words via iterator, issue #46930', function () {
let model = worker.addModel([
'one line', // 1
'two line', // 2
'',
'past empty',
'single',
'',
'and now we are done'
]);
let words: string[] = [];
for (let iter = model.createWordIterator(/[a-z]+/img), e = iter.next(); !e.done; e = iter.next()) {
words.push(e.value);
}
assert.deepEqual(words, ['one', 'line', 'two', 'line', 'past', 'empty', 'single', 'and', 'now', 'we', 'are', 'done']);
});
});

View File

@@ -93,7 +93,7 @@ suite('ModelService', () => {
const actual = ModelServiceImpl._computeEdits(model, textBuffer);
assert.deepEqual(actual, [
EditOperation.replace(new Range(1, 1, 2, 1), 'This is line One\n')
EditOperation.replaceMove(new Range(1, 1, 2, 1), 'This is line One\n')
]);
});
@@ -147,7 +147,7 @@ suite('ModelService', () => {
const actual = ModelServiceImpl._computeEdits(model, textBuffer);
assert.deepEqual(actual, [
EditOperation.replace(
EditOperation.replaceMove(
new Range(1, 1, 4, 1),
[
'This is line One',
@@ -182,7 +182,7 @@ suite('ModelService', () => {
const actual = ModelServiceImpl._computeEdits(model, textBuffer);
assert.deepEqual(actual, [
EditOperation.replace(new Range(3, 2, 3, 2), '\r\n')
EditOperation.replaceMove(new Range(3, 2, 3, 2), '\r\n')
]);
});

View File

@@ -58,7 +58,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => {
renderMinimap: RenderMinimap.None,
minimapLeft: 0,
minimapWidth: 0,
viewportColumn: 99,
viewportColumn: 98,
verticalScrollbarWidth: 0,
horizontalScrollbarHeight: 0,
@@ -174,7 +174,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => {
renderMinimap: RenderMinimap.None,
minimapLeft: 0,
minimapWidth: 0,
viewportColumn: 89,
viewportColumn: 88,
verticalScrollbarWidth: 0,
horizontalScrollbarHeight: 0,
@@ -232,7 +232,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => {
renderMinimap: RenderMinimap.None,
minimapLeft: 0,
minimapWidth: 0,
viewportColumn: 89,
viewportColumn: 88,
verticalScrollbarWidth: 0,
horizontalScrollbarHeight: 0,
@@ -290,7 +290,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => {
renderMinimap: RenderMinimap.None,
minimapLeft: 0,
minimapWidth: 0,
viewportColumn: 89,
viewportColumn: 88,
verticalScrollbarWidth: 0,
horizontalScrollbarHeight: 0,
@@ -348,7 +348,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => {
renderMinimap: RenderMinimap.None,
minimapLeft: 0,
minimapWidth: 0,
viewportColumn: 84,
viewportColumn: 83,
verticalScrollbarWidth: 0,
horizontalScrollbarHeight: 0,
@@ -406,7 +406,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => {
renderMinimap: RenderMinimap.None,
minimapLeft: 0,
minimapWidth: 0,
viewportColumn: 84,
viewportColumn: 83,
verticalScrollbarWidth: 0,
horizontalScrollbarHeight: 0,
@@ -464,7 +464,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => {
renderMinimap: RenderMinimap.None,
minimapLeft: 0,
minimapWidth: 0,
viewportColumn: 83,
viewportColumn: 82,
verticalScrollbarWidth: 0,
horizontalScrollbarHeight: 0,
@@ -522,7 +522,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => {
renderMinimap: RenderMinimap.None,
minimapLeft: 0,
minimapWidth: 0,
viewportColumn: 172,
viewportColumn: 171,
verticalScrollbarWidth: 0,
horizontalScrollbarHeight: 0,
@@ -580,7 +580,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => {
renderMinimap: RenderMinimap.None,
minimapLeft: 0,
minimapWidth: 0,
viewportColumn: 170,
viewportColumn: 169,
verticalScrollbarWidth: 0,
horizontalScrollbarHeight: 0,
@@ -632,13 +632,13 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => {
decorationsHeight: 800,
contentLeft: 10,
contentWidth: 900,
contentWidth: 901,
contentHeight: 800,
renderMinimap: RenderMinimap.Small,
minimapLeft: 910,
minimapWidth: 90,
viewportColumn: 90,
minimapLeft: 911,
minimapWidth: 89,
viewportColumn: 89,
verticalScrollbarWidth: 0,
horizontalScrollbarHeight: 0,
@@ -690,13 +690,13 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => {
decorationsHeight: 800,
contentLeft: 10,
contentWidth: 900,
contentWidth: 901,
contentHeight: 800,
renderMinimap: RenderMinimap.Large,
minimapLeft: 910,
minimapWidth: 90,
viewportColumn: 90,
minimapLeft: 911,
minimapWidth: 89,
viewportColumn: 89,
verticalScrollbarWidth: 0,
horizontalScrollbarHeight: 0,
@@ -825,4 +825,63 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => {
}
});
});
test('issue #31312: When wrapping, leave 2px for the cursor', () => {
doTest({
outerWidth: 1201,
outerHeight: 422,
showGlyphMargin: true,
lineHeight: 30,
showLineNumbers: true,
lineNumbersMinChars: 3,
lineNumbersDigitCount: 1,
lineDecorationsWidth: 26,
typicalHalfwidthCharacterWidth: 12.04296875,
maxDigitWidth: 12.04296875,
verticalScrollbarWidth: 14,
horizontalScrollbarHeight: 10,
scrollbarArrowSize: 11,
verticalScrollbarHasArrows: false,
minimap: true,
minimapSide: 'right',
minimapRenderCharacters: true,
minimapMaxColumn: 120,
pixelRatio: 2
}, {
width: 1201,
height: 422,
glyphMarginLeft: 0,
glyphMarginWidth: 30,
glyphMarginHeight: 422,
lineNumbersLeft: 30,
lineNumbersWidth: 36,
lineNumbersHeight: 422,
decorationsLeft: 66,
decorationsWidth: 26,
decorationsHeight: 422,
contentLeft: 92,
contentWidth: 1026,
contentHeight: 422,
renderMinimap: RenderMinimap.Large,
minimapLeft: 1104,
minimapWidth: 83,
viewportColumn: 83,
verticalScrollbarWidth: 14,
horizontalScrollbarHeight: 10,
overviewRuler: {
top: 0,
width: 14,
height: 422,
right: 0
}
});
});
});

View File

@@ -12,6 +12,7 @@ import { MetadataConsts } from 'vs/editor/common/modes';
import { LineDecoration } from 'vs/editor/common/viewLayout/lineDecorations';
import { InlineDecorationType } from 'vs/editor/common/viewModel/viewModel';
import { IViewLineTokens } from 'vs/editor/common/core/lineTokens';
import * as strings from 'vs/base/common/strings';
function createViewLineTokens(viewLineTokens: ViewLineToken[]): IViewLineTokens {
return new ViewLineTokens(viewLineTokens);
@@ -29,6 +30,7 @@ suite('viewLineRenderer.renderLine', () => {
let _actual = renderViewLine(new RenderLineInput(
false,
lineContent,
strings.isBasicASCII(lineContent),
false,
0,
createViewLineTokens([new ViewLineToken(lineContent.length, 0)]),
@@ -75,6 +77,7 @@ suite('viewLineRenderer.renderLine', () => {
let _actual = renderViewLine(new RenderLineInput(
false,
lineContent,
true,
false,
0,
createViewLineTokens(parts),
@@ -111,6 +114,7 @@ suite('viewLineRenderer.renderLine', () => {
let _actual = renderViewLine(new RenderLineInput(
false,
'Hello world!',
true,
false,
0,
createViewLineTokens([
@@ -212,6 +216,7 @@ suite('viewLineRenderer.renderLine', () => {
let _actual = renderViewLine(new RenderLineInput(
false,
lineText,
true,
false,
0,
lineParts,
@@ -271,6 +276,7 @@ suite('viewLineRenderer.renderLine', () => {
let _actual = renderViewLine(new RenderLineInput(
false,
lineText,
true,
false,
0,
lineParts,
@@ -330,6 +336,7 @@ suite('viewLineRenderer.renderLine', () => {
let _actual = renderViewLine(new RenderLineInput(
false,
lineText,
true,
false,
0,
lineParts,
@@ -366,6 +373,7 @@ suite('viewLineRenderer.renderLine', () => {
let _actual = renderViewLine(new RenderLineInput(
false,
lineText,
false,
true,
0,
lineParts,
@@ -393,6 +401,7 @@ suite('viewLineRenderer.renderLine', () => {
let actual = renderViewLine(new RenderLineInput(
false,
lineText,
true,
false,
0,
lineParts,
@@ -490,6 +499,7 @@ suite('viewLineRenderer.renderLine', () => {
let actual = renderViewLine(new RenderLineInput(
false,
lineText,
true,
false,
0,
lineParts,
@@ -524,6 +534,7 @@ suite('viewLineRenderer.renderLine', () => {
false,
lineText,
false,
false,
0,
lineParts,
[],
@@ -535,11 +546,7 @@ suite('viewLineRenderer.renderLine', () => {
false
));
let expectedOutput = [
'<span class="mtk1">a𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷</span>',
'<span class="mtk1">𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷</span>',
'<span class="mtk1">𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷</span>',
'<span class="mtk1">𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷</span>',
'<span class="mtk1">𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷</span>',
'<span class="mtk1">a𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷</span>',
];
assert.equal(actual.html, '<span>' + expectedOutput.join('') + '</span>');
});
@@ -553,6 +560,7 @@ suite('viewLineRenderer.renderLine', () => {
let actual = renderViewLine(new RenderLineInput(
false,
lineText,
false,
true,
0,
lineParts,
@@ -596,6 +604,7 @@ suite('viewLineRenderer.renderLine', () => {
let _actual = renderViewLine(new RenderLineInput(
true,
lineText,
true,
false,
4,
lineParts,
@@ -676,6 +685,7 @@ suite('viewLineRenderer.renderLine 2', () => {
let actual = renderViewLine(new RenderLineInput(
fontIsMonospace,
lineContent,
true,
false,
fauxIndentLength,
createViewLineTokens(tokens),
@@ -698,6 +708,7 @@ suite('viewLineRenderer.renderLine 2', () => {
let actual = renderViewLine(new RenderLineInput(
false,
lineContent,
true,
false,
0,
createViewLineTokens([createPart(21, 3)]),
@@ -726,6 +737,7 @@ suite('viewLineRenderer.renderLine 2', () => {
let actual = renderViewLine(new RenderLineInput(
true,
lineContent,
true,
false,
0,
createViewLineTokens([
@@ -990,6 +1002,7 @@ suite('viewLineRenderer.renderLine 2', () => {
let actual = renderViewLine(new RenderLineInput(
false,
'Hello world',
true,
false,
0,
createViewLineTokens([createPart(11, 0)]),
@@ -1031,6 +1044,7 @@ suite('viewLineRenderer.renderLine 2', () => {
let actual = renderViewLine(new RenderLineInput(
false,
lineContent,
true,
false,
0,
createViewLineTokens([createPart(4, 3)]),
@@ -1060,6 +1074,7 @@ suite('viewLineRenderer.renderLine 2', () => {
let actual = renderViewLine(new RenderLineInput(
false,
lineContent,
true,
false,
0,
createViewLineTokens([createPart(4, 3)]),
@@ -1090,6 +1105,7 @@ suite('viewLineRenderer.renderLine 2', () => {
let actual = renderViewLine(new RenderLineInput(
false,
lineContent,
true,
false,
0,
createViewLineTokens([createPart(0, 3)]),
@@ -1117,6 +1133,7 @@ suite('viewLineRenderer.renderLine 2', () => {
true,
' 1. 🙏',
false,
false,
0,
createViewLineTokens([createPart(7, 3)]),
[new LineDecoration(7, 8, 'inline-folded', InlineDecorationType.After)],
@@ -1143,6 +1160,7 @@ suite('viewLineRenderer.renderLine 2', () => {
let actual = renderViewLine(new RenderLineInput(
true,
'',
true,
false,
0,
createViewLineTokens([createPart(0, 3)]),
@@ -1172,6 +1190,7 @@ suite('viewLineRenderer.renderLine 2', () => {
let actual = renderViewLine(new RenderLineInput(
true,
'\t}',
true,
false,
0,
createViewLineTokens([createPart(2, 3)]),
@@ -1203,6 +1222,7 @@ suite('viewLineRenderer.renderLine 2', () => {
true,
'asd = "擦"\t\t#asd',
false,
false,
0,
createViewLineTokens([createPart(15, 3)]),
[],
@@ -1229,6 +1249,7 @@ suite('viewLineRenderer.renderLine 2', () => {
true,
'asd = "擦"\t\t#asd',
false,
false,
0,
createViewLineTokens([createPart(15, 3)]),
[],
@@ -1255,10 +1276,96 @@ suite('viewLineRenderer.renderLine 2', () => {
assert.deepEqual(actual.html, expected);
});
test('issue #22352: COMBINING ACUTE ACCENT (U+0301)', () => {
let actual = renderViewLine(new RenderLineInput(
true,
'12345689012345678901234568901234567890123456890abába',
false,
false,
0,
createViewLineTokens([createPart(53, 3)]),
[],
4,
10,
10000,
'none',
false,
false
));
let expected = [
'<span>',
'<span class="mtk3">12345689012345678901234568901234567890123456890abába</span>',
'</span>'
].join('');
assert.deepEqual(actual.html, expected);
});
test('issue #22352: Partially Broken Complex Script Rendering of Tamil', () => {
let actual = renderViewLine(new RenderLineInput(
true,
' JoyShareல் பின்தொடர்ந்து, விடீயோ, ஜோக்குகள், அனிமேசன், நகைச்சுவை படங்கள் மற்றும் செய்திகளை பெறுவீர்',
false,
false,
0,
createViewLineTokens([createPart(100, 3)]),
[],
4,
10,
10000,
'none',
false,
false
));
let expected = [
'<span>',
'<span class="mtk3">\u00a0JoyShareல்\u00a0பின்தொடர்ந்து,\u00a0விடீயோ,\u00a0ஜோக்குகள்,\u00a0அனிமேசன்,\u00a0நகைச்சுவை\u00a0படங்கள்\u00a0மற்றும்\u00a0செய்திகளை\u00a0பெறுவீர்</span>',
'</span>'
].join('');
let _expected = expected.split('').map(c => c.charCodeAt(0));
let _actual = actual.html.split('').map(c => c.charCodeAt(0));
assert.deepEqual(_actual, _expected);
assert.deepEqual(actual.html, expected);
});
test('issue #42700: Hindi characters are not being rendered properly', () => {
let actual = renderViewLine(new RenderLineInput(
true,
' वो ऐसा क्या है जो हमारे अंदर भी है और बाहर भी है। जिसकी वजह से हम सब हैं। जिसने इस सृष्टि की रचना की है।',
false,
false,
0,
createViewLineTokens([createPart(105, 3)]),
[],
4,
10,
10000,
'none',
false,
false
));
let expected = [
'<span>',
'<span class="mtk3">\u00a0वो\u00a0ऐसा\u00a0क्या\u00a0है\u00a0जो\u00a0हमारे\u00a0अंदर\u00a0भी\u00a0है\u00a0और\u00a0बाहर\u00a0भी\u00a0है।\u00a0जिसकी\u00a0वजह\u00a0से\u00a0हम\u00a0सब\u00a0हैं।\u00a0जिसने\u00a0इस\u00a0सृष्टि\u00a0की\u00a0रचना\u00a0की\u00a0है।</span>',
'</span>'
].join('');
assert.deepEqual(actual.html, expected);
});
function createTestGetColumnOfLinePartOffset(lineContent: string, tabSize: number, parts: ViewLineToken[], expectedPartLengths: number[]): (partIndex: number, partLength: number, offset: number, expected: number) => void {
let renderLineOutput = renderViewLine(new RenderLineInput(
false,
lineContent,
true,
false,
0,
createViewLineTokens(parts),

View File

@@ -780,6 +780,9 @@ function createModel(text: string): ISimpleModel {
getLineContent: (lineNumber: number) => {
return text;
},
getLineLength: (lineNumber: number) => {
return text.length;
},
getLineMinColumn: (lineNumber: number) => {
return 1;
},

View File

@@ -7,6 +7,7 @@
import * as assert from 'assert';
import { Range } from 'vs/editor/common/core/range';
import { testViewModel } from 'vs/editor/test/common/viewModel/testViewModel';
import { EndOfLineSequence } from 'vs/editor/common/model';
suite('ViewModel', () => {
@@ -109,7 +110,7 @@ suite('ViewModel', () => {
function assertGetPlainTextToCopy(text: string[], ranges: Range[], emptySelectionClipboard: boolean, expected: string | string[]): void {
testViewModel(text, {}, (viewModel, model) => {
let actual = viewModel.getPlainTextToCopy(ranges, emptySelectionClipboard);
let actual = viewModel.getPlainTextToCopy(ranges, emptySelectionClipboard, false);
assert.deepEqual(actual, expected);
});
}
@@ -250,4 +251,12 @@ suite('ViewModel', () => {
'line2\nline3\n'
);
});
test('issue #22688 - always use CRLF for clipboard on Windows', () => {
testViewModel(USUAL_TEXT, {}, (viewModel, model) => {
model.setEOL(EndOfLineSequence.LF);
let actual = viewModel.getPlainTextToCopy([new Range(2, 1, 5, 1)], true, true);
assert.deepEqual(actual, 'line2\r\nline3\r\nline4\r\n');
});
});
});