mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-13 19:48:37 -05:00
SQL Operations Studio Public Preview 1 (0.23) release source code
This commit is contained in:
94
src/vs/editor/test/common/commands/commandTestUtils.ts
Normal file
94
src/vs/editor/test/common/commands/commandTestUtils.ts
Normal file
@@ -0,0 +1,94 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { Selection } from 'vs/editor/common/core/selection';
|
||||
import * as editorCommon from 'vs/editor/common/editorCommon';
|
||||
import { Model } from 'vs/editor/common/model/model';
|
||||
import { LanguageIdentifier } from 'vs/editor/common/modes';
|
||||
import { withMockCodeEditor } from 'vs/editor/test/common/mocks/mockCodeEditor';
|
||||
|
||||
export function testCommand(
|
||||
lines: string[],
|
||||
languageIdentifier: LanguageIdentifier,
|
||||
selection: Selection,
|
||||
commandFactory: (selection: Selection) => editorCommon.ICommand,
|
||||
expectedLines: string[],
|
||||
expectedSelection: Selection
|
||||
): void {
|
||||
let model = Model.createFromString(lines.join('\n'), undefined, languageIdentifier);
|
||||
withMockCodeEditor(null, { model: model }, (editor, cursor) => {
|
||||
|
||||
cursor.setSelections('tests', [selection]);
|
||||
|
||||
cursor.trigger('tests', editorCommon.Handler.ExecuteCommand, commandFactory(cursor.getSelection()));
|
||||
|
||||
assert.deepEqual(model.getLinesContent(), expectedLines);
|
||||
|
||||
let actualSelection = cursor.getSelection();
|
||||
assert.deepEqual(actualSelection.toString(), expectedSelection.toString());
|
||||
|
||||
});
|
||||
model.dispose();
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract edit operations if command `command` were to execute on model `model`
|
||||
*/
|
||||
export function getEditOperation(model: editorCommon.IModel, command: editorCommon.ICommand): editorCommon.IIdentifiedSingleEditOperation[] {
|
||||
var operations: editorCommon.IIdentifiedSingleEditOperation[] = [];
|
||||
var editOperationBuilder: editorCommon.IEditOperationBuilder = {
|
||||
addEditOperation: (range: Range, text: string) => {
|
||||
operations.push({
|
||||
identifier: null,
|
||||
range: range,
|
||||
text: text,
|
||||
forceMoveMarkers: false
|
||||
});
|
||||
},
|
||||
|
||||
addTrackedEditOperation: (range: Range, text: string) => {
|
||||
operations.push({
|
||||
identifier: null,
|
||||
range: range,
|
||||
text: text,
|
||||
forceMoveMarkers: false
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
trackSelection: (selection: Selection) => {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
command.getEditOperations(model, editOperationBuilder);
|
||||
return operations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create single edit operation
|
||||
*/
|
||||
export function createSingleEditOp(text: string, positionLineNumber: number, positionColumn: number, selectionLineNumber: number = positionLineNumber, selectionColumn: number = positionColumn): editorCommon.IIdentifiedSingleEditOperation {
|
||||
return {
|
||||
identifier: null,
|
||||
range: new Range(selectionLineNumber, selectionColumn, positionLineNumber, positionColumn),
|
||||
text: text,
|
||||
forceMoveMarkers: false
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create single edit operation
|
||||
*/
|
||||
export function createInsertDeleteSingleEditOp(text: string, positionLineNumber: number, positionColumn: number, selectionLineNumber: number = positionLineNumber, selectionColumn: number = positionColumn): editorCommon.IIdentifiedSingleEditOperation {
|
||||
return {
|
||||
identifier: null,
|
||||
range: new Range(selectionLineNumber, selectionColumn, positionLineNumber, positionColumn),
|
||||
text: text,
|
||||
forceMoveMarkers: true
|
||||
};
|
||||
}
|
||||
987
src/vs/editor/test/common/commands/shiftCommand.test.ts
Normal file
987
src/vs/editor/test/common/commands/shiftCommand.test.ts
Normal file
@@ -0,0 +1,987 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { ShiftCommand } from 'vs/editor/common/commands/shiftCommand';
|
||||
import { Selection } from 'vs/editor/common/core/selection';
|
||||
import { IIdentifiedSingleEditOperation } from 'vs/editor/common/editorCommon';
|
||||
import { IndentAction } from 'vs/editor/common/modes/languageConfiguration';
|
||||
import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry';
|
||||
import { createSingleEditOp, getEditOperation, testCommand } from 'vs/editor/test/common/commands/commandTestUtils';
|
||||
import { withEditorModel } from 'vs/editor/test/common/editorTestUtils';
|
||||
import { MockMode } from 'vs/editor/test/common/mocks/mockMode';
|
||||
import { LanguageIdentifier } from 'vs/editor/common/modes';
|
||||
|
||||
class DocBlockCommentMode extends MockMode {
|
||||
|
||||
private static _id = new LanguageIdentifier('commentMode', 3);
|
||||
|
||||
constructor() {
|
||||
super(DocBlockCommentMode._id);
|
||||
this._register(LanguageConfigurationRegistry.register(this.getLanguageIdentifier(), {
|
||||
brackets: [
|
||||
['(', ')'],
|
||||
['{', '}'],
|
||||
['[', ']']
|
||||
],
|
||||
|
||||
onEnterRules: [
|
||||
{
|
||||
// e.g. /** | */
|
||||
beforeText: /^\s*\/\*\*(?!\/)([^\*]|\*(?!\/))*$/,
|
||||
afterText: /^\s*\*\/$/,
|
||||
action: { indentAction: IndentAction.IndentOutdent, appendText: ' * ' }
|
||||
},
|
||||
{
|
||||
// e.g. /** ...|
|
||||
beforeText: /^\s*\/\*\*(?!\/)([^\*]|\*(?!\/))*$/,
|
||||
action: { indentAction: IndentAction.None, appendText: ' * ' }
|
||||
},
|
||||
{
|
||||
// e.g. * ...|
|
||||
beforeText: /^(\t|(\ \ ))*\ \*(\ ([^\*]|\*(?!\/))*)?$/,
|
||||
action: { indentAction: IndentAction.None, appendText: '* ' }
|
||||
},
|
||||
{
|
||||
// e.g. */|
|
||||
beforeText: /^(\t|(\ \ ))*\ \*\/\s*$/,
|
||||
action: { indentAction: IndentAction.None, removeText: 1 }
|
||||
},
|
||||
{
|
||||
// e.g. *-----*/|
|
||||
beforeText: /^(\t|(\ \ ))*\ \*[^/]*\*\/\s*$/,
|
||||
action: { indentAction: IndentAction.None, removeText: 1 }
|
||||
}
|
||||
]
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
function testShiftCommand(lines: string[], languageIdentifier: LanguageIdentifier, useTabStops: boolean, selection: Selection, expectedLines: string[], expectedSelection: Selection): void {
|
||||
testCommand(lines, languageIdentifier, selection, (sel) => new ShiftCommand(sel, {
|
||||
isUnshift: false,
|
||||
tabSize: 4,
|
||||
oneIndent: '\t',
|
||||
useTabStops: useTabStops,
|
||||
}), expectedLines, expectedSelection);
|
||||
}
|
||||
|
||||
function testUnshiftCommand(lines: string[], languageIdentifier: LanguageIdentifier, useTabStops: boolean, selection: Selection, expectedLines: string[], expectedSelection: Selection): void {
|
||||
testCommand(lines, languageIdentifier, selection, (sel) => new ShiftCommand(sel, {
|
||||
isUnshift: true,
|
||||
tabSize: 4,
|
||||
oneIndent: '\t',
|
||||
useTabStops: useTabStops,
|
||||
}), expectedLines, expectedSelection);
|
||||
}
|
||||
|
||||
function withDockBlockCommentMode(callback: (mode: DocBlockCommentMode) => void): void {
|
||||
let mode = new DocBlockCommentMode();
|
||||
callback(mode);
|
||||
mode.dispose();
|
||||
}
|
||||
|
||||
suite('Editor Commands - ShiftCommand', () => {
|
||||
|
||||
// --------- shift
|
||||
|
||||
test('Bug 9503: Shifting without any selection', () => {
|
||||
testShiftCommand(
|
||||
[
|
||||
'My First Line',
|
||||
'\t\tMy Second Line',
|
||||
' Third Line',
|
||||
'',
|
||||
'123'
|
||||
],
|
||||
null,
|
||||
true,
|
||||
new Selection(1, 1, 1, 1),
|
||||
[
|
||||
'\tMy First Line',
|
||||
'\t\tMy Second Line',
|
||||
' Third Line',
|
||||
'',
|
||||
'123'
|
||||
],
|
||||
new Selection(1, 1, 1, 2)
|
||||
);
|
||||
});
|
||||
|
||||
test('shift on single line selection 1', () => {
|
||||
testShiftCommand(
|
||||
[
|
||||
'My First Line',
|
||||
'\t\tMy Second Line',
|
||||
' Third Line',
|
||||
'',
|
||||
'123'
|
||||
],
|
||||
null,
|
||||
true,
|
||||
new Selection(1, 3, 1, 1),
|
||||
[
|
||||
'\tMy First Line',
|
||||
'\t\tMy Second Line',
|
||||
' Third Line',
|
||||
'',
|
||||
'123'
|
||||
],
|
||||
new Selection(1, 4, 1, 1)
|
||||
);
|
||||
});
|
||||
|
||||
test('shift on single line selection 2', () => {
|
||||
testShiftCommand(
|
||||
[
|
||||
'My First Line',
|
||||
'\t\tMy Second Line',
|
||||
' Third Line',
|
||||
'',
|
||||
'123'
|
||||
],
|
||||
null,
|
||||
true,
|
||||
new Selection(1, 1, 1, 3),
|
||||
[
|
||||
'\tMy First Line',
|
||||
'\t\tMy Second Line',
|
||||
' Third Line',
|
||||
'',
|
||||
'123'
|
||||
],
|
||||
new Selection(1, 1, 1, 4)
|
||||
);
|
||||
});
|
||||
|
||||
test('simple shift', () => {
|
||||
testShiftCommand(
|
||||
[
|
||||
'My First Line',
|
||||
'\t\tMy Second Line',
|
||||
' Third Line',
|
||||
'',
|
||||
'123'
|
||||
],
|
||||
null,
|
||||
true,
|
||||
new Selection(1, 1, 2, 1),
|
||||
[
|
||||
'\tMy First Line',
|
||||
'\t\tMy Second Line',
|
||||
' Third Line',
|
||||
'',
|
||||
'123'
|
||||
],
|
||||
new Selection(1, 1, 2, 1)
|
||||
);
|
||||
});
|
||||
|
||||
test('shifting on two separate lines', () => {
|
||||
testShiftCommand(
|
||||
[
|
||||
'My First Line',
|
||||
'\t\tMy Second Line',
|
||||
' Third Line',
|
||||
'',
|
||||
'123'
|
||||
],
|
||||
null,
|
||||
true,
|
||||
new Selection(1, 1, 2, 1),
|
||||
[
|
||||
'\tMy First Line',
|
||||
'\t\tMy Second Line',
|
||||
' Third Line',
|
||||
'',
|
||||
'123'
|
||||
],
|
||||
new Selection(1, 1, 2, 1)
|
||||
);
|
||||
|
||||
testShiftCommand(
|
||||
[
|
||||
'\tMy First Line',
|
||||
'\t\tMy Second Line',
|
||||
' Third Line',
|
||||
'',
|
||||
'123'
|
||||
],
|
||||
null,
|
||||
true,
|
||||
new Selection(2, 1, 3, 1),
|
||||
[
|
||||
'\tMy First Line',
|
||||
'\t\t\tMy Second Line',
|
||||
' Third Line',
|
||||
'',
|
||||
'123'
|
||||
],
|
||||
new Selection(2, 1, 3, 1)
|
||||
);
|
||||
});
|
||||
|
||||
test('shifting on two lines', () => {
|
||||
testShiftCommand(
|
||||
[
|
||||
'My First Line',
|
||||
'\t\tMy Second Line',
|
||||
' Third Line',
|
||||
'',
|
||||
'123'
|
||||
],
|
||||
null,
|
||||
true,
|
||||
new Selection(1, 2, 2, 2),
|
||||
[
|
||||
'\tMy First Line',
|
||||
'\t\t\tMy Second Line',
|
||||
' Third Line',
|
||||
'',
|
||||
'123'
|
||||
],
|
||||
new Selection(1, 3, 2, 2)
|
||||
);
|
||||
});
|
||||
|
||||
test('shifting on two lines again', () => {
|
||||
testShiftCommand(
|
||||
[
|
||||
'My First Line',
|
||||
'\t\tMy Second Line',
|
||||
' Third Line',
|
||||
'',
|
||||
'123'
|
||||
],
|
||||
null,
|
||||
true,
|
||||
new Selection(2, 2, 1, 2),
|
||||
[
|
||||
'\tMy First Line',
|
||||
'\t\t\tMy Second Line',
|
||||
' Third Line',
|
||||
'',
|
||||
'123'
|
||||
],
|
||||
new Selection(2, 2, 1, 3)
|
||||
);
|
||||
});
|
||||
|
||||
test('shifting at end of file', () => {
|
||||
testShiftCommand(
|
||||
[
|
||||
'My First Line',
|
||||
'\t\tMy Second Line',
|
||||
' Third Line',
|
||||
'',
|
||||
'123'
|
||||
],
|
||||
null,
|
||||
true,
|
||||
new Selection(4, 1, 5, 2),
|
||||
[
|
||||
'My First Line',
|
||||
'\t\tMy Second Line',
|
||||
' Third Line',
|
||||
'',
|
||||
'\t123'
|
||||
],
|
||||
new Selection(4, 1, 5, 3)
|
||||
);
|
||||
});
|
||||
|
||||
test('issue #1120 TAB should not indent empty lines in a multi-line selection', () => {
|
||||
testShiftCommand(
|
||||
[
|
||||
'My First Line',
|
||||
'\t\tMy Second Line',
|
||||
' Third Line',
|
||||
'',
|
||||
'123'
|
||||
],
|
||||
null,
|
||||
true,
|
||||
new Selection(1, 1, 5, 2),
|
||||
[
|
||||
'\tMy First Line',
|
||||
'\t\t\tMy Second Line',
|
||||
'\t\tThird Line',
|
||||
'',
|
||||
'\t123'
|
||||
],
|
||||
new Selection(1, 1, 5, 3)
|
||||
);
|
||||
|
||||
testShiftCommand(
|
||||
[
|
||||
'My First Line',
|
||||
'\t\tMy Second Line',
|
||||
' Third Line',
|
||||
'',
|
||||
'123'
|
||||
],
|
||||
null,
|
||||
true,
|
||||
new Selection(4, 1, 5, 1),
|
||||
[
|
||||
'My First Line',
|
||||
'\t\tMy Second Line',
|
||||
' Third Line',
|
||||
'\t',
|
||||
'123'
|
||||
],
|
||||
new Selection(4, 1, 5, 1)
|
||||
);
|
||||
});
|
||||
|
||||
// --------- unshift
|
||||
|
||||
test('unshift on single line selection 1', () => {
|
||||
testShiftCommand(
|
||||
[
|
||||
'My First Line',
|
||||
'\t\tMy Second Line',
|
||||
' Third Line',
|
||||
'',
|
||||
'123'
|
||||
],
|
||||
null,
|
||||
true,
|
||||
new Selection(2, 3, 2, 1),
|
||||
[
|
||||
'My First Line',
|
||||
'\t\t\tMy Second Line',
|
||||
' Third Line',
|
||||
'',
|
||||
'123'
|
||||
],
|
||||
new Selection(2, 3, 2, 1)
|
||||
);
|
||||
});
|
||||
|
||||
test('unshift on single line selection 2', () => {
|
||||
testShiftCommand(
|
||||
[
|
||||
'My First Line',
|
||||
'\t\tMy Second Line',
|
||||
' Third Line',
|
||||
'',
|
||||
'123'
|
||||
],
|
||||
null,
|
||||
true,
|
||||
new Selection(2, 1, 2, 3),
|
||||
[
|
||||
'My First Line',
|
||||
'\t\t\tMy Second Line',
|
||||
' Third Line',
|
||||
'',
|
||||
'123'
|
||||
],
|
||||
new Selection(2, 1, 2, 3)
|
||||
);
|
||||
});
|
||||
|
||||
test('simple unshift', () => {
|
||||
testUnshiftCommand(
|
||||
[
|
||||
'My First Line',
|
||||
'\t\tMy Second Line',
|
||||
' Third Line',
|
||||
'',
|
||||
'123'
|
||||
],
|
||||
null,
|
||||
true,
|
||||
new Selection(1, 1, 2, 1),
|
||||
[
|
||||
'My First Line',
|
||||
'\t\tMy Second Line',
|
||||
' Third Line',
|
||||
'',
|
||||
'123'
|
||||
],
|
||||
new Selection(1, 1, 2, 1)
|
||||
);
|
||||
});
|
||||
|
||||
test('unshifting on two lines 1', () => {
|
||||
testUnshiftCommand(
|
||||
[
|
||||
'My First Line',
|
||||
'\t\tMy Second Line',
|
||||
' Third Line',
|
||||
'',
|
||||
'123'
|
||||
],
|
||||
null,
|
||||
true,
|
||||
new Selection(1, 2, 2, 2),
|
||||
[
|
||||
'My First Line',
|
||||
'\tMy Second Line',
|
||||
' Third Line',
|
||||
'',
|
||||
'123'
|
||||
],
|
||||
new Selection(1, 2, 2, 2)
|
||||
);
|
||||
});
|
||||
|
||||
test('unshifting on two lines 2', () => {
|
||||
testUnshiftCommand(
|
||||
[
|
||||
'My First Line',
|
||||
'\t\tMy Second Line',
|
||||
' Third Line',
|
||||
'',
|
||||
'123'
|
||||
],
|
||||
null,
|
||||
true,
|
||||
new Selection(2, 3, 2, 1),
|
||||
[
|
||||
'My First Line',
|
||||
'\tMy Second Line',
|
||||
' Third Line',
|
||||
'',
|
||||
'123'
|
||||
],
|
||||
new Selection(2, 2, 2, 1)
|
||||
);
|
||||
});
|
||||
|
||||
test('unshifting at the end of the file', () => {
|
||||
testUnshiftCommand(
|
||||
[
|
||||
'My First Line',
|
||||
'\t\tMy Second Line',
|
||||
' Third Line',
|
||||
'',
|
||||
'123'
|
||||
],
|
||||
null,
|
||||
true,
|
||||
new Selection(4, 1, 5, 2),
|
||||
[
|
||||
'My First Line',
|
||||
'\t\tMy Second Line',
|
||||
' Third Line',
|
||||
'',
|
||||
'123'
|
||||
],
|
||||
new Selection(4, 1, 5, 2)
|
||||
);
|
||||
});
|
||||
|
||||
test('unshift many times + shift', () => {
|
||||
testUnshiftCommand(
|
||||
[
|
||||
'My First Line',
|
||||
'\t\tMy Second Line',
|
||||
' Third Line',
|
||||
'',
|
||||
'123'
|
||||
],
|
||||
null,
|
||||
true,
|
||||
new Selection(1, 1, 5, 4),
|
||||
[
|
||||
'My First Line',
|
||||
'\tMy Second Line',
|
||||
'Third Line',
|
||||
'',
|
||||
'123'
|
||||
],
|
||||
new Selection(1, 1, 5, 4)
|
||||
);
|
||||
|
||||
testUnshiftCommand(
|
||||
[
|
||||
'My First Line',
|
||||
'\tMy Second Line',
|
||||
'Third Line',
|
||||
'',
|
||||
'123'
|
||||
],
|
||||
null,
|
||||
true,
|
||||
new Selection(1, 1, 5, 4),
|
||||
[
|
||||
'My First Line',
|
||||
'My Second Line',
|
||||
'Third Line',
|
||||
'',
|
||||
'123'
|
||||
],
|
||||
new Selection(1, 1, 5, 4)
|
||||
);
|
||||
|
||||
testShiftCommand(
|
||||
[
|
||||
'My First Line',
|
||||
'My Second Line',
|
||||
'Third Line',
|
||||
'',
|
||||
'123'
|
||||
],
|
||||
null,
|
||||
true,
|
||||
new Selection(1, 1, 5, 4),
|
||||
[
|
||||
'\tMy First Line',
|
||||
'\tMy Second Line',
|
||||
'\tThird Line',
|
||||
'',
|
||||
'\t123'
|
||||
],
|
||||
new Selection(1, 1, 5, 5)
|
||||
);
|
||||
});
|
||||
|
||||
test('Bug 9119: Unshift from first column doesn\'t work', () => {
|
||||
testUnshiftCommand(
|
||||
[
|
||||
'My First Line',
|
||||
'\t\tMy Second Line',
|
||||
' Third Line',
|
||||
'',
|
||||
'123'
|
||||
],
|
||||
null,
|
||||
true,
|
||||
new Selection(2, 1, 2, 1),
|
||||
[
|
||||
'My First Line',
|
||||
'\tMy Second Line',
|
||||
' Third Line',
|
||||
'',
|
||||
'123'
|
||||
],
|
||||
new Selection(2, 1, 2, 1)
|
||||
);
|
||||
});
|
||||
|
||||
test('issue #348: indenting around doc block comments', () => {
|
||||
withDockBlockCommentMode((mode) => {
|
||||
|
||||
testShiftCommand(
|
||||
[
|
||||
'',
|
||||
'/**',
|
||||
' * a doc comment',
|
||||
' */',
|
||||
'function hello() {}'
|
||||
],
|
||||
mode.getLanguageIdentifier(),
|
||||
true,
|
||||
new Selection(1, 1, 5, 20),
|
||||
[
|
||||
'',
|
||||
'\t/**',
|
||||
'\t * a doc comment',
|
||||
'\t */',
|
||||
'\tfunction hello() {}'
|
||||
],
|
||||
new Selection(1, 1, 5, 21)
|
||||
);
|
||||
|
||||
testUnshiftCommand(
|
||||
[
|
||||
'',
|
||||
'/**',
|
||||
' * a doc comment',
|
||||
' */',
|
||||
'function hello() {}'
|
||||
],
|
||||
mode.getLanguageIdentifier(),
|
||||
true,
|
||||
new Selection(1, 1, 5, 20),
|
||||
[
|
||||
'',
|
||||
'/**',
|
||||
' * a doc comment',
|
||||
' */',
|
||||
'function hello() {}'
|
||||
],
|
||||
new Selection(1, 1, 5, 20)
|
||||
);
|
||||
|
||||
testUnshiftCommand(
|
||||
[
|
||||
'\t',
|
||||
'\t/**',
|
||||
'\t * a doc comment',
|
||||
'\t */',
|
||||
'\tfunction hello() {}'
|
||||
],
|
||||
mode.getLanguageIdentifier(),
|
||||
true,
|
||||
new Selection(1, 1, 5, 21),
|
||||
[
|
||||
'',
|
||||
'/**',
|
||||
' * a doc comment',
|
||||
' */',
|
||||
'function hello() {}'
|
||||
],
|
||||
new Selection(1, 1, 5, 20)
|
||||
);
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
test('issue #1609: Wrong indentation of block comments', () => {
|
||||
withDockBlockCommentMode((mode) => {
|
||||
testShiftCommand(
|
||||
[
|
||||
'',
|
||||
'/**',
|
||||
' * test',
|
||||
' *',
|
||||
' * @type {number}',
|
||||
' */',
|
||||
'var foo = 0;'
|
||||
],
|
||||
mode.getLanguageIdentifier(),
|
||||
true,
|
||||
new Selection(1, 1, 7, 13),
|
||||
[
|
||||
'',
|
||||
'\t/**',
|
||||
'\t * test',
|
||||
'\t *',
|
||||
'\t * @type {number}',
|
||||
'\t */',
|
||||
'\tvar foo = 0;'
|
||||
],
|
||||
new Selection(1, 1, 7, 14)
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
test('issue #1620: a) Line indent doesn\'t handle leading whitespace properly', () => {
|
||||
testCommand(
|
||||
[
|
||||
' Written | Numeric',
|
||||
' one | 1',
|
||||
' two | 2',
|
||||
' three | 3',
|
||||
' four | 4',
|
||||
' five | 5',
|
||||
' six | 6',
|
||||
' seven | 7',
|
||||
' eight | 8',
|
||||
' nine | 9',
|
||||
' ten | 10',
|
||||
' eleven | 11',
|
||||
'',
|
||||
],
|
||||
null,
|
||||
new Selection(1, 1, 13, 1),
|
||||
(sel) => new ShiftCommand(sel, {
|
||||
isUnshift: false,
|
||||
tabSize: 4,
|
||||
oneIndent: ' ',
|
||||
useTabStops: false
|
||||
}),
|
||||
[
|
||||
' Written | Numeric',
|
||||
' one | 1',
|
||||
' two | 2',
|
||||
' three | 3',
|
||||
' four | 4',
|
||||
' five | 5',
|
||||
' six | 6',
|
||||
' seven | 7',
|
||||
' eight | 8',
|
||||
' nine | 9',
|
||||
' ten | 10',
|
||||
' eleven | 11',
|
||||
'',
|
||||
],
|
||||
new Selection(1, 1, 13, 1)
|
||||
);
|
||||
});
|
||||
|
||||
test('issue #1620: b) Line indent doesn\'t handle leading whitespace properly', () => {
|
||||
testCommand(
|
||||
[
|
||||
' Written | Numeric',
|
||||
' one | 1',
|
||||
' two | 2',
|
||||
' three | 3',
|
||||
' four | 4',
|
||||
' five | 5',
|
||||
' six | 6',
|
||||
' seven | 7',
|
||||
' eight | 8',
|
||||
' nine | 9',
|
||||
' ten | 10',
|
||||
' eleven | 11',
|
||||
'',
|
||||
],
|
||||
null,
|
||||
new Selection(1, 1, 13, 1),
|
||||
(sel) => new ShiftCommand(sel, {
|
||||
isUnshift: true,
|
||||
tabSize: 4,
|
||||
oneIndent: ' ',
|
||||
useTabStops: false
|
||||
}),
|
||||
[
|
||||
' Written | Numeric',
|
||||
' one | 1',
|
||||
' two | 2',
|
||||
' three | 3',
|
||||
' four | 4',
|
||||
' five | 5',
|
||||
' six | 6',
|
||||
' seven | 7',
|
||||
' eight | 8',
|
||||
' nine | 9',
|
||||
' ten | 10',
|
||||
' eleven | 11',
|
||||
'',
|
||||
],
|
||||
new Selection(1, 1, 13, 1)
|
||||
);
|
||||
});
|
||||
|
||||
test('issue #1620: c) Line indent doesn\'t handle leading whitespace properly', () => {
|
||||
testCommand(
|
||||
[
|
||||
' Written | Numeric',
|
||||
' one | 1',
|
||||
' two | 2',
|
||||
' three | 3',
|
||||
' four | 4',
|
||||
' five | 5',
|
||||
' six | 6',
|
||||
' seven | 7',
|
||||
' eight | 8',
|
||||
' nine | 9',
|
||||
' ten | 10',
|
||||
' eleven | 11',
|
||||
'',
|
||||
],
|
||||
null,
|
||||
new Selection(1, 1, 13, 1),
|
||||
(sel) => new ShiftCommand(sel, {
|
||||
isUnshift: true,
|
||||
tabSize: 4,
|
||||
oneIndent: '\t',
|
||||
useTabStops: false
|
||||
}),
|
||||
[
|
||||
' Written | Numeric',
|
||||
' one | 1',
|
||||
' two | 2',
|
||||
' three | 3',
|
||||
' four | 4',
|
||||
' five | 5',
|
||||
' six | 6',
|
||||
' seven | 7',
|
||||
' eight | 8',
|
||||
' nine | 9',
|
||||
' ten | 10',
|
||||
' eleven | 11',
|
||||
'',
|
||||
],
|
||||
new Selection(1, 1, 13, 1)
|
||||
);
|
||||
});
|
||||
|
||||
test('issue #1620: d) Line indent doesn\'t handle leading whitespace properly', () => {
|
||||
testCommand(
|
||||
[
|
||||
'\t Written | Numeric',
|
||||
'\t one | 1',
|
||||
'\t two | 2',
|
||||
'\t three | 3',
|
||||
'\t four | 4',
|
||||
'\t five | 5',
|
||||
'\t six | 6',
|
||||
'\t seven | 7',
|
||||
'\t eight | 8',
|
||||
'\t nine | 9',
|
||||
'\t ten | 10',
|
||||
'\t eleven | 11',
|
||||
'',
|
||||
],
|
||||
null,
|
||||
new Selection(1, 1, 13, 1),
|
||||
(sel) => new ShiftCommand(sel, {
|
||||
isUnshift: true,
|
||||
tabSize: 4,
|
||||
oneIndent: ' ',
|
||||
useTabStops: false
|
||||
}),
|
||||
[
|
||||
' Written | Numeric',
|
||||
' one | 1',
|
||||
' two | 2',
|
||||
' three | 3',
|
||||
' four | 4',
|
||||
' five | 5',
|
||||
' six | 6',
|
||||
' seven | 7',
|
||||
' eight | 8',
|
||||
' nine | 9',
|
||||
' ten | 10',
|
||||
' eleven | 11',
|
||||
'',
|
||||
],
|
||||
new Selection(1, 1, 13, 1)
|
||||
);
|
||||
});
|
||||
|
||||
test('issue Microsoft/monaco-editor#443: Indentation of a single row deletes selected text in some cases', () => {
|
||||
testCommand(
|
||||
[
|
||||
'Hello world!',
|
||||
'another line'
|
||||
],
|
||||
null,
|
||||
new Selection(1, 1, 1, 13),
|
||||
(sel) => new ShiftCommand(sel, {
|
||||
isUnshift: false,
|
||||
tabSize: 4,
|
||||
oneIndent: '\t',
|
||||
useTabStops: true
|
||||
}),
|
||||
[
|
||||
'\tHello world!',
|
||||
'another line'
|
||||
],
|
||||
new Selection(1, 1, 1, 14)
|
||||
);
|
||||
});
|
||||
|
||||
test('bug #16815:Shift+Tab doesn\'t go back to tabstop', () => {
|
||||
|
||||
var repeatStr = (str: string, cnt: number): string => {
|
||||
var r = '';
|
||||
for (var i = 0; i < cnt; i++) {
|
||||
r += str;
|
||||
}
|
||||
return r;
|
||||
};
|
||||
|
||||
var testOutdent = (tabSize: number, oneIndent: string, lineText: string, expectedIndents: number) => {
|
||||
var expectedIndent = repeatStr(oneIndent, expectedIndents);
|
||||
if (lineText.length > 0) {
|
||||
_assertUnshiftCommand(tabSize, oneIndent, [lineText + 'aaa'], [createSingleEditOp(expectedIndent, 1, 1, 1, lineText.length + 1)]);
|
||||
} else {
|
||||
_assertUnshiftCommand(tabSize, oneIndent, [lineText + 'aaa'], []);
|
||||
}
|
||||
};
|
||||
|
||||
var testIndent = (tabSize: number, oneIndent: string, lineText: string, expectedIndents: number) => {
|
||||
var expectedIndent = repeatStr(oneIndent, expectedIndents);
|
||||
_assertShiftCommand(tabSize, oneIndent, [lineText + 'aaa'], [createSingleEditOp(expectedIndent, 1, 1, 1, lineText.length + 1)]);
|
||||
};
|
||||
|
||||
var testIndentation = (tabSize: number, lineText: string, expectedOnOutdent: number, expectedOnIndent: number) => {
|
||||
var spaceIndent = '';
|
||||
for (var i = 0; i < tabSize; i++) {
|
||||
spaceIndent += ' ';
|
||||
}
|
||||
|
||||
testOutdent(tabSize, spaceIndent, lineText, expectedOnOutdent);
|
||||
testOutdent(tabSize, '\t', lineText, expectedOnOutdent);
|
||||
|
||||
testIndent(tabSize, spaceIndent, lineText, expectedOnIndent);
|
||||
testIndent(tabSize, '\t', lineText, expectedOnIndent);
|
||||
};
|
||||
|
||||
// insertSpaces: true
|
||||
// 0 => 0
|
||||
testIndentation(4, '', 0, 1);
|
||||
|
||||
// 1 => 0
|
||||
testIndentation(4, '\t', 0, 2);
|
||||
testIndentation(4, ' ', 0, 1);
|
||||
testIndentation(4, ' \t', 0, 2);
|
||||
testIndentation(4, ' ', 0, 1);
|
||||
testIndentation(4, ' \t', 0, 2);
|
||||
testIndentation(4, ' ', 0, 1);
|
||||
testIndentation(4, ' \t', 0, 2);
|
||||
testIndentation(4, ' ', 0, 2);
|
||||
|
||||
// 2 => 1
|
||||
testIndentation(4, '\t\t', 1, 3);
|
||||
testIndentation(4, '\t ', 1, 2);
|
||||
testIndentation(4, '\t \t', 1, 3);
|
||||
testIndentation(4, '\t ', 1, 2);
|
||||
testIndentation(4, '\t \t', 1, 3);
|
||||
testIndentation(4, '\t ', 1, 2);
|
||||
testIndentation(4, '\t \t', 1, 3);
|
||||
testIndentation(4, '\t ', 1, 3);
|
||||
testIndentation(4, ' \t\t', 1, 3);
|
||||
testIndentation(4, ' \t ', 1, 2);
|
||||
testIndentation(4, ' \t \t', 1, 3);
|
||||
testIndentation(4, ' \t ', 1, 2);
|
||||
testIndentation(4, ' \t \t', 1, 3);
|
||||
testIndentation(4, ' \t ', 1, 2);
|
||||
testIndentation(4, ' \t \t', 1, 3);
|
||||
testIndentation(4, ' \t ', 1, 3);
|
||||
testIndentation(4, ' \t\t', 1, 3);
|
||||
testIndentation(4, ' \t ', 1, 2);
|
||||
testIndentation(4, ' \t \t', 1, 3);
|
||||
testIndentation(4, ' \t ', 1, 2);
|
||||
testIndentation(4, ' \t \t', 1, 3);
|
||||
testIndentation(4, ' \t ', 1, 2);
|
||||
testIndentation(4, ' \t \t', 1, 3);
|
||||
testIndentation(4, ' \t ', 1, 3);
|
||||
testIndentation(4, ' \t\t', 1, 3);
|
||||
testIndentation(4, ' \t ', 1, 2);
|
||||
testIndentation(4, ' \t \t', 1, 3);
|
||||
testIndentation(4, ' \t ', 1, 2);
|
||||
testIndentation(4, ' \t \t', 1, 3);
|
||||
testIndentation(4, ' \t ', 1, 2);
|
||||
testIndentation(4, ' \t \t', 1, 3);
|
||||
testIndentation(4, ' \t ', 1, 3);
|
||||
testIndentation(4, ' \t', 1, 3);
|
||||
testIndentation(4, ' ', 1, 2);
|
||||
testIndentation(4, ' \t', 1, 3);
|
||||
testIndentation(4, ' ', 1, 2);
|
||||
testIndentation(4, ' \t', 1, 3);
|
||||
testIndentation(4, ' ', 1, 2);
|
||||
testIndentation(4, ' \t', 1, 3);
|
||||
testIndentation(4, ' ', 1, 3);
|
||||
|
||||
// 3 => 2
|
||||
testIndentation(4, ' ', 2, 3);
|
||||
|
||||
function _assertUnshiftCommand(tabSize: number, oneIndent: string, text: string[], expected: IIdentifiedSingleEditOperation[]): void {
|
||||
return withEditorModel(text, (model) => {
|
||||
var op = new ShiftCommand(new Selection(1, 1, text.length + 1, 1), {
|
||||
isUnshift: true,
|
||||
tabSize: tabSize,
|
||||
oneIndent: oneIndent,
|
||||
useTabStops: true
|
||||
});
|
||||
var actual = getEditOperation(model, op);
|
||||
assert.deepEqual(actual, expected);
|
||||
});
|
||||
}
|
||||
|
||||
function _assertShiftCommand(tabSize: number, oneIndent: string, text: string[], expected: IIdentifiedSingleEditOperation[]): void {
|
||||
return withEditorModel(text, (model) => {
|
||||
var op = new ShiftCommand(new Selection(1, 1, text.length + 1, 1), {
|
||||
isUnshift: false,
|
||||
tabSize: tabSize,
|
||||
oneIndent: oneIndent,
|
||||
useTabStops: true
|
||||
});
|
||||
var actual = getEditOperation(model, op);
|
||||
assert.deepEqual(actual, expected);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
208
src/vs/editor/test/common/commands/sideEditing.test.ts
Normal file
208
src/vs/editor/test/common/commands/sideEditing.test.ts
Normal file
@@ -0,0 +1,208 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { EditOperation } from 'vs/editor/common/core/editOperation';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { Selection } from 'vs/editor/common/core/selection';
|
||||
import { IIdentifiedSingleEditOperation } from 'vs/editor/common/editorCommon';
|
||||
import { ILineEdit, ModelLine, LineMarker, MarkersTracker } from 'vs/editor/common/model/modelLine';
|
||||
import { withMockCodeEditor } from 'vs/editor/test/common/mocks/mockCodeEditor';
|
||||
|
||||
const NO_TAB_SIZE = 0;
|
||||
|
||||
function testCommand(lines: string[], selections: Selection[], edits: IIdentifiedSingleEditOperation[], expectedLines: string[], expectedSelections: Selection[]): void {
|
||||
withMockCodeEditor(lines, {}, (editor, cursor) => {
|
||||
const model = editor.getModel();
|
||||
|
||||
cursor.setSelections('tests', selections);
|
||||
|
||||
model.applyEdits(edits);
|
||||
|
||||
assert.deepEqual(model.getLinesContent(), expectedLines);
|
||||
|
||||
let actualSelections = cursor.getSelections();
|
||||
assert.deepEqual(actualSelections.map(s => s.toString()), expectedSelections.map(s => s.toString()));
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
function testLineEditMarker(text: string, column: number, stickToPreviousCharacter: boolean, edit: ILineEdit, expectedColumn: number): void {
|
||||
var line = new ModelLine(text, NO_TAB_SIZE);
|
||||
line.addMarker(new LineMarker('1', 0, new Position(0, column), stickToPreviousCharacter));
|
||||
|
||||
line.applyEdits(new MarkersTracker(), [edit], NO_TAB_SIZE);
|
||||
|
||||
assert.equal(line.getMarkers()[0].position.column, expectedColumn);
|
||||
}
|
||||
|
||||
suite('Editor Side Editing - collapsed selection', () => {
|
||||
|
||||
test('replace at selection', () => {
|
||||
testCommand(
|
||||
[
|
||||
'first',
|
||||
'second line',
|
||||
'third line',
|
||||
'fourth'
|
||||
],
|
||||
[new Selection(1, 1, 1, 1)],
|
||||
[
|
||||
EditOperation.replace(new Selection(1, 1, 1, 1), 'something ')
|
||||
],
|
||||
[
|
||||
'something first',
|
||||
'second line',
|
||||
'third line',
|
||||
'fourth'
|
||||
],
|
||||
[new Selection(1, 1, 1, 11)]
|
||||
);
|
||||
});
|
||||
|
||||
test('replace at selection 2', () => {
|
||||
testCommand(
|
||||
[
|
||||
'first',
|
||||
'second line',
|
||||
'third line',
|
||||
'fourth'
|
||||
],
|
||||
[new Selection(1, 1, 1, 6)],
|
||||
[
|
||||
EditOperation.replace(new Selection(1, 1, 1, 6), 'something')
|
||||
],
|
||||
[
|
||||
'something',
|
||||
'second line',
|
||||
'third line',
|
||||
'fourth'
|
||||
],
|
||||
[new Selection(1, 1, 1, 10)]
|
||||
);
|
||||
});
|
||||
|
||||
test('ModelLine.applyEdits uses `isReplace`', () => {
|
||||
testLineEditMarker('something', 1, true, { startColumn: 1, endColumn: 1, text: 'asd', forceMoveMarkers: false }, 1);
|
||||
testLineEditMarker('something', 1, true, { startColumn: 1, endColumn: 1, text: 'asd', forceMoveMarkers: true }, 4);
|
||||
|
||||
testLineEditMarker('something', 1, false, { startColumn: 1, endColumn: 1, text: 'asd', forceMoveMarkers: false }, 4);
|
||||
testLineEditMarker('something', 1, false, { startColumn: 1, endColumn: 1, text: 'asd', forceMoveMarkers: true }, 4);
|
||||
});
|
||||
|
||||
test('insert at selection', () => {
|
||||
testCommand(
|
||||
[
|
||||
'first',
|
||||
'second line',
|
||||
'third line',
|
||||
'fourth'
|
||||
],
|
||||
[new Selection(1, 1, 1, 1)],
|
||||
[
|
||||
EditOperation.insert(new Position(1, 1), 'something ')
|
||||
],
|
||||
[
|
||||
'something first',
|
||||
'second line',
|
||||
'third line',
|
||||
'fourth'
|
||||
],
|
||||
[new Selection(1, 11, 1, 11)]
|
||||
);
|
||||
});
|
||||
|
||||
test('insert at selection sitting on max column', () => {
|
||||
testCommand(
|
||||
[
|
||||
'first',
|
||||
'second line',
|
||||
'third line',
|
||||
'fourth'
|
||||
],
|
||||
[new Selection(1, 6, 1, 6)],
|
||||
[
|
||||
EditOperation.insert(new Position(1, 6), ' something\nnew ')
|
||||
],
|
||||
[
|
||||
'first something',
|
||||
'new ',
|
||||
'second line',
|
||||
'third line',
|
||||
'fourth'
|
||||
],
|
||||
[new Selection(2, 5, 2, 5)]
|
||||
);
|
||||
});
|
||||
|
||||
test('issue #3994: replace on top of selection', () => {
|
||||
testCommand(
|
||||
[
|
||||
'$obj = New-Object "system.col"'
|
||||
],
|
||||
[new Selection(1, 30, 1, 30)],
|
||||
[
|
||||
EditOperation.replaceMove(new Range(1, 19, 1, 31), '"System.Collections"')
|
||||
],
|
||||
[
|
||||
'$obj = New-Object "System.Collections"'
|
||||
],
|
||||
[new Selection(1, 39, 1, 39)]
|
||||
);
|
||||
});
|
||||
|
||||
test('issue #15267: Suggestion that adds a line - cursor goes to the wrong line ', () => {
|
||||
testCommand(
|
||||
[
|
||||
'package main',
|
||||
'',
|
||||
'import (',
|
||||
' "fmt"',
|
||||
')',
|
||||
'',
|
||||
'func main(',
|
||||
' fmt.Println(strings.Con)',
|
||||
'}'
|
||||
],
|
||||
[new Selection(8, 25, 8, 25)],
|
||||
[
|
||||
EditOperation.replaceMove(new Range(5, 1, 5, 1), '\t\"strings\"\n')
|
||||
],
|
||||
[
|
||||
'package main',
|
||||
'',
|
||||
'import (',
|
||||
' "fmt"',
|
||||
' "strings"',
|
||||
')',
|
||||
'',
|
||||
'func main(',
|
||||
' fmt.Println(strings.Con)',
|
||||
'}'
|
||||
],
|
||||
[new Selection(9, 25, 9, 25)]
|
||||
);
|
||||
});
|
||||
|
||||
test('issue #15236: Selections broke after deleting text using vscode.TextEditor.edit ', () => {
|
||||
testCommand(
|
||||
[
|
||||
'foofoofoo, foofoofoo, bar'
|
||||
],
|
||||
[new Selection(1, 1, 1, 10), new Selection(1, 12, 1, 21)],
|
||||
[
|
||||
EditOperation.replace(new Range(1, 1, 1, 10), ''),
|
||||
EditOperation.replace(new Range(1, 12, 1, 21), ''),
|
||||
],
|
||||
[
|
||||
', , bar'
|
||||
],
|
||||
[new Selection(1, 1, 1, 1), new Selection(1, 3, 1, 3)]
|
||||
);
|
||||
});
|
||||
|
||||
});
|
||||
@@ -0,0 +1,82 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { TrimTrailingWhitespaceCommand, trimTrailingWhitespace } from 'vs/editor/common/commands/trimTrailingWhitespaceCommand';
|
||||
import { Selection } from 'vs/editor/common/core/selection';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { IIdentifiedSingleEditOperation } from 'vs/editor/common/editorCommon';
|
||||
import { createInsertDeleteSingleEditOp, createSingleEditOp, getEditOperation } from 'vs/editor/test/common/commands/commandTestUtils';
|
||||
import { withEditorModel } from 'vs/editor/test/common/editorTestUtils';
|
||||
|
||||
function assertTrimTrailingWhitespaceCommand(text: string[], expected: IIdentifiedSingleEditOperation[]): void {
|
||||
return withEditorModel(text, (model) => {
|
||||
var op = new TrimTrailingWhitespaceCommand(new Selection(1, 1, 1, 1));
|
||||
var actual = getEditOperation(model, op);
|
||||
assert.deepEqual(actual, expected);
|
||||
});
|
||||
}
|
||||
|
||||
function assertTrimTrailingWhitespace(text: string[], cursors: Position[], expected: IIdentifiedSingleEditOperation[]): void {
|
||||
return withEditorModel(text, (model) => {
|
||||
var actual = trimTrailingWhitespace(model, cursors);
|
||||
assert.deepEqual(actual, expected);
|
||||
});
|
||||
}
|
||||
|
||||
suite('Editor Commands - Trim Trailing Whitespace Command', () => {
|
||||
|
||||
test('remove trailing whitespace', function () {
|
||||
assertTrimTrailingWhitespaceCommand([''], []);
|
||||
assertTrimTrailingWhitespaceCommand(['text'], []);
|
||||
assertTrimTrailingWhitespaceCommand(['text '], [createSingleEditOp(null, 1, 5, 1, 8)]);
|
||||
assertTrimTrailingWhitespaceCommand(['text\t '], [createSingleEditOp(null, 1, 5, 1, 9)]);
|
||||
assertTrimTrailingWhitespaceCommand(['\t '], [createSingleEditOp(null, 1, 1, 1, 5)]);
|
||||
assertTrimTrailingWhitespaceCommand(['text\t'], [createSingleEditOp(null, 1, 5, 1, 6)]);
|
||||
assertTrimTrailingWhitespaceCommand([
|
||||
'some text\t',
|
||||
'some more text',
|
||||
'\t ',
|
||||
'even more text ',
|
||||
'and some mixed\t \t'
|
||||
], [
|
||||
createSingleEditOp(null, 1, 10, 1, 11),
|
||||
createSingleEditOp(null, 3, 1, 3, 4),
|
||||
createSingleEditOp(null, 4, 15, 4, 17),
|
||||
createSingleEditOp(null, 5, 15, 5, 20)
|
||||
]);
|
||||
|
||||
|
||||
assertTrimTrailingWhitespace(['text '], [new Position(1, 1), new Position(1, 2), new Position(1, 3)], [createInsertDeleteSingleEditOp(null, 1, 5, 1, 8)]);
|
||||
assertTrimTrailingWhitespace(['text '], [new Position(1, 1), new Position(1, 5)], [createInsertDeleteSingleEditOp(null, 1, 5, 1, 8)]);
|
||||
assertTrimTrailingWhitespace(['text '], [new Position(1, 1), new Position(1, 5), new Position(1, 6)], [createInsertDeleteSingleEditOp(null, 1, 6, 1, 8)]);
|
||||
assertTrimTrailingWhitespace([
|
||||
'some text\t',
|
||||
'some more text',
|
||||
'\t ',
|
||||
'even more text ',
|
||||
'and some mixed\t \t'
|
||||
], [], [
|
||||
createInsertDeleteSingleEditOp(null, 1, 10, 1, 11),
|
||||
createInsertDeleteSingleEditOp(null, 3, 1, 3, 4),
|
||||
createInsertDeleteSingleEditOp(null, 4, 15, 4, 17),
|
||||
createInsertDeleteSingleEditOp(null, 5, 15, 5, 20)
|
||||
]);
|
||||
assertTrimTrailingWhitespace([
|
||||
'some text\t',
|
||||
'some more text',
|
||||
'\t ',
|
||||
'even more text ',
|
||||
'and some mixed\t \t'
|
||||
], [new Position(1, 11), new Position(3, 2), new Position(5, 1), new Position(4, 1), new Position(5, 10)], [
|
||||
createInsertDeleteSingleEditOp(null, 3, 2, 3, 4),
|
||||
createInsertDeleteSingleEditOp(null, 4, 15, 4, 17),
|
||||
createInsertDeleteSingleEditOp(null, 5, 15, 5, 20)
|
||||
]);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
21
src/vs/editor/test/common/commentMode.ts
Normal file
21
src/vs/editor/test/common/commentMode.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry';
|
||||
import { CommentRule } from 'vs/editor/common/modes/languageConfiguration';
|
||||
import { LanguageIdentifier } from 'vs/editor/common/modes';
|
||||
import { MockMode } from 'vs/editor/test/common/mocks/mockMode';
|
||||
|
||||
export class CommentMode extends MockMode {
|
||||
private static _id = new LanguageIdentifier('commentMode', 3);
|
||||
|
||||
constructor(commentsConfig: CommentRule) {
|
||||
super(CommentMode._id);
|
||||
this._register(LanguageConfigurationRegistry.register(this.getLanguageIdentifier(), {
|
||||
comments: commentsConfig
|
||||
}));
|
||||
}
|
||||
}
|
||||
182
src/vs/editor/test/common/config/commonEditorConfig.test.ts
Normal file
182
src/vs/editor/test/common/config/commonEditorConfig.test.ts
Normal file
@@ -0,0 +1,182 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { EditorZoom } from 'vs/editor/common/config/editorZoom';
|
||||
import { TestConfiguration } from 'vs/editor/test/common/mocks/testConfiguration';
|
||||
import { IEnvConfiguration } from 'vs/editor/common/config/commonEditorConfig';
|
||||
import { AccessibilitySupport } from 'vs/base/common/platform';
|
||||
|
||||
suite('Common Editor Config', () => {
|
||||
test('Zoom Level', () => {
|
||||
|
||||
//Zoom levels are defined to go between -9, 9 inclusive
|
||||
var zoom = EditorZoom;
|
||||
|
||||
zoom.setZoomLevel(0);
|
||||
assert.equal(zoom.getZoomLevel(), 0);
|
||||
|
||||
zoom.setZoomLevel(-0);
|
||||
assert.equal(zoom.getZoomLevel(), 0);
|
||||
|
||||
zoom.setZoomLevel(5);
|
||||
assert.equal(zoom.getZoomLevel(), 5);
|
||||
|
||||
zoom.setZoomLevel(-1);
|
||||
assert.equal(zoom.getZoomLevel(), -1);
|
||||
|
||||
zoom.setZoomLevel(9);
|
||||
assert.equal(zoom.getZoomLevel(), 9);
|
||||
|
||||
zoom.setZoomLevel(-9);
|
||||
assert.equal(zoom.getZoomLevel(), -9);
|
||||
|
||||
zoom.setZoomLevel(10);
|
||||
assert.equal(zoom.getZoomLevel(), 9);
|
||||
|
||||
zoom.setZoomLevel(-10);
|
||||
assert.equal(zoom.getZoomLevel(), -9);
|
||||
|
||||
zoom.setZoomLevel(9.1);
|
||||
assert.equal(zoom.getZoomLevel(), 9);
|
||||
|
||||
zoom.setZoomLevel(-9.1);
|
||||
assert.equal(zoom.getZoomLevel(), -9);
|
||||
|
||||
zoom.setZoomLevel(Infinity);
|
||||
assert.equal(zoom.getZoomLevel(), 9);
|
||||
|
||||
zoom.setZoomLevel(Number.NEGATIVE_INFINITY);
|
||||
assert.equal(zoom.getZoomLevel(), -9);
|
||||
});
|
||||
|
||||
class TestWrappingConfiguration extends TestConfiguration {
|
||||
protected _getEnvConfiguration(): IEnvConfiguration {
|
||||
return {
|
||||
extraEditorClassName: '',
|
||||
outerWidth: 1000,
|
||||
outerHeight: 100,
|
||||
emptySelectionClipboard: true,
|
||||
pixelRatio: 1,
|
||||
zoomLevel: 0,
|
||||
accessibilitySupport: AccessibilitySupport.Unknown
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function assertWrapping(config: TestConfiguration, isViewportWrapping: boolean, wrappingColumn: number): void {
|
||||
assert.equal(config.editor.wrappingInfo.isViewportWrapping, isViewportWrapping);
|
||||
assert.equal(config.editor.wrappingInfo.wrappingColumn, wrappingColumn);
|
||||
}
|
||||
|
||||
test('wordWrap default', () => {
|
||||
let config = new TestWrappingConfiguration({});
|
||||
assertWrapping(config, false, -1);
|
||||
});
|
||||
|
||||
test('wordWrap compat false', () => {
|
||||
let config = new TestWrappingConfiguration({
|
||||
wordWrap: <any>false
|
||||
});
|
||||
assertWrapping(config, false, -1);
|
||||
});
|
||||
|
||||
test('wordWrap compat true', () => {
|
||||
let config = new TestWrappingConfiguration({
|
||||
wordWrap: <any>true
|
||||
});
|
||||
// {{SQL CARBON EDIT}}
|
||||
assertWrapping(config, true, 89);
|
||||
});
|
||||
|
||||
test('wordWrap on', () => {
|
||||
let config = new TestWrappingConfiguration({
|
||||
wordWrap: 'on'
|
||||
});
|
||||
// {{SQL CARBON EDIT}}
|
||||
assertWrapping(config, true, 89);
|
||||
});
|
||||
|
||||
test('wordWrap on without minimap', () => {
|
||||
let config = new TestWrappingConfiguration({
|
||||
wordWrap: 'on',
|
||||
minimap: {
|
||||
enabled: false
|
||||
}
|
||||
});
|
||||
assertWrapping(config, true, 89);
|
||||
});
|
||||
|
||||
test('wordWrap on does not use wordWrapColumn', () => {
|
||||
let config = new TestWrappingConfiguration({
|
||||
wordWrap: 'on',
|
||||
wordWrapColumn: 10
|
||||
});
|
||||
// {{SQL CARBON EDIT}}
|
||||
assertWrapping(config, true, 89);
|
||||
});
|
||||
|
||||
test('wordWrap off', () => {
|
||||
let config = new TestWrappingConfiguration({
|
||||
wordWrap: 'off'
|
||||
});
|
||||
assertWrapping(config, false, -1);
|
||||
});
|
||||
|
||||
test('wordWrap off does not use wordWrapColumn', () => {
|
||||
let config = new TestWrappingConfiguration({
|
||||
wordWrap: 'off',
|
||||
wordWrapColumn: 10
|
||||
});
|
||||
assertWrapping(config, false, -1);
|
||||
});
|
||||
|
||||
test('wordWrap wordWrapColumn uses default wordWrapColumn', () => {
|
||||
let config = new TestWrappingConfiguration({
|
||||
wordWrap: 'wordWrapColumn'
|
||||
});
|
||||
assertWrapping(config, false, 80);
|
||||
});
|
||||
|
||||
test('wordWrap wordWrapColumn uses wordWrapColumn', () => {
|
||||
let config = new TestWrappingConfiguration({
|
||||
wordWrap: 'wordWrapColumn',
|
||||
wordWrapColumn: 100
|
||||
});
|
||||
assertWrapping(config, false, 100);
|
||||
});
|
||||
|
||||
test('wordWrap wordWrapColumn validates wordWrapColumn', () => {
|
||||
let config = new TestWrappingConfiguration({
|
||||
wordWrap: 'wordWrapColumn',
|
||||
wordWrapColumn: -1
|
||||
});
|
||||
assertWrapping(config, false, 1);
|
||||
});
|
||||
|
||||
test('wordWrap bounded uses default wordWrapColumn', () => {
|
||||
let config = new TestWrappingConfiguration({
|
||||
wordWrap: 'bounded'
|
||||
});
|
||||
assertWrapping(config, true, 80);
|
||||
});
|
||||
|
||||
test('wordWrap bounded uses wordWrapColumn', () => {
|
||||
let config = new TestWrappingConfiguration({
|
||||
wordWrap: 'bounded',
|
||||
wordWrapColumn: 40
|
||||
});
|
||||
assertWrapping(config, true, 40);
|
||||
});
|
||||
|
||||
test('wordWrap bounded validates wordWrapColumn', () => {
|
||||
let config = new TestWrappingConfiguration({
|
||||
wordWrap: 'bounded',
|
||||
wordWrapColumn: -1
|
||||
});
|
||||
assertWrapping(config, true, 1);
|
||||
});
|
||||
});
|
||||
3702
src/vs/editor/test/common/controller/cursor.test.ts
Normal file
3702
src/vs/editor/test/common/controller/cursor.test.ts
Normal file
File diff suppressed because it is too large
Load Diff
512
src/vs/editor/test/common/controller/cursorMoveCommand.test.ts
Normal file
512
src/vs/editor/test/common/controller/cursorMoveCommand.test.ts
Normal file
@@ -0,0 +1,512 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { Cursor } from 'vs/editor/common/controller/cursor';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { Model } from 'vs/editor/common/model/model';
|
||||
import { TestConfiguration } from 'vs/editor/test/common/mocks/testConfiguration';
|
||||
import { CursorMove } from 'vs/editor/common/controller/cursorMoveCommands';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { Selection } from 'vs/editor/common/core/selection';
|
||||
import { CoreNavigationCommands } from 'vs/editor/common/controller/coreCommands';
|
||||
import { ViewModel } from 'vs/editor/common/viewModel/viewModelImpl';
|
||||
|
||||
suite('Cursor move command test', () => {
|
||||
|
||||
let thisModel: Model;
|
||||
let thisConfiguration: TestConfiguration;
|
||||
let thisViewModel: ViewModel;
|
||||
let thisCursor: Cursor;
|
||||
|
||||
setup(() => {
|
||||
let text = [
|
||||
' \tMy First Line\t ',
|
||||
'\tMy Second Line',
|
||||
' Third Line🐶',
|
||||
'',
|
||||
'1'
|
||||
].join('\n');
|
||||
|
||||
thisModel = Model.createFromString(text);
|
||||
thisConfiguration = new TestConfiguration(null);
|
||||
thisViewModel = new ViewModel(0, thisConfiguration, thisModel, null);
|
||||
thisCursor = new Cursor(thisConfiguration, thisModel, thisViewModel);
|
||||
});
|
||||
|
||||
teardown(() => {
|
||||
thisCursor.dispose();
|
||||
thisViewModel.dispose();
|
||||
thisModel.dispose();
|
||||
thisConfiguration.dispose();
|
||||
});
|
||||
|
||||
test('move left should move to left character', () => {
|
||||
moveTo(thisCursor, 1, 8);
|
||||
|
||||
moveLeft(thisCursor);
|
||||
|
||||
cursorEqual(thisCursor, 1, 7);
|
||||
});
|
||||
|
||||
test('move left should move to left by n characters', () => {
|
||||
moveTo(thisCursor, 1, 8);
|
||||
|
||||
moveLeft(thisCursor, 3);
|
||||
|
||||
cursorEqual(thisCursor, 1, 5);
|
||||
});
|
||||
|
||||
test('move left should move to left by half line', () => {
|
||||
moveTo(thisCursor, 1, 8);
|
||||
|
||||
moveLeft(thisCursor, 1, CursorMove.RawUnit.HalfLine);
|
||||
|
||||
cursorEqual(thisCursor, 1, 1);
|
||||
});
|
||||
|
||||
test('move left moves to previous line', () => {
|
||||
moveTo(thisCursor, 2, 3);
|
||||
|
||||
moveLeft(thisCursor, 10);
|
||||
|
||||
cursorEqual(thisCursor, 1, 21);
|
||||
});
|
||||
|
||||
test('move right should move to right character', () => {
|
||||
moveTo(thisCursor, 1, 5);
|
||||
|
||||
moveRight(thisCursor);
|
||||
|
||||
cursorEqual(thisCursor, 1, 6);
|
||||
});
|
||||
|
||||
test('move right should move to right by n characters', () => {
|
||||
moveTo(thisCursor, 1, 2);
|
||||
|
||||
moveRight(thisCursor, 6);
|
||||
|
||||
cursorEqual(thisCursor, 1, 8);
|
||||
});
|
||||
|
||||
test('move right should move to right by half line', () => {
|
||||
moveTo(thisCursor, 1, 4);
|
||||
|
||||
moveRight(thisCursor, 1, CursorMove.RawUnit.HalfLine);
|
||||
|
||||
cursorEqual(thisCursor, 1, 14);
|
||||
});
|
||||
|
||||
test('move right moves to next line', () => {
|
||||
moveTo(thisCursor, 1, 8);
|
||||
|
||||
moveRight(thisCursor, 100);
|
||||
|
||||
cursorEqual(thisCursor, 2, 1);
|
||||
});
|
||||
|
||||
test('move to first character of line from middle', () => {
|
||||
moveTo(thisCursor, 1, 8);
|
||||
moveToLineStart(thisCursor);
|
||||
cursorEqual(thisCursor, 1, 1);
|
||||
});
|
||||
|
||||
test('move to first character of line from first non white space character', () => {
|
||||
moveTo(thisCursor, 1, 6);
|
||||
|
||||
moveToLineStart(thisCursor);
|
||||
|
||||
cursorEqual(thisCursor, 1, 1);
|
||||
});
|
||||
|
||||
test('move to first character of line from first character', () => {
|
||||
moveTo(thisCursor, 1, 1);
|
||||
|
||||
moveToLineStart(thisCursor);
|
||||
|
||||
cursorEqual(thisCursor, 1, 1);
|
||||
});
|
||||
|
||||
test('move to first non white space character of line from middle', () => {
|
||||
moveTo(thisCursor, 1, 8);
|
||||
|
||||
moveToLineFirstNonWhiteSpaceCharacter(thisCursor);
|
||||
|
||||
cursorEqual(thisCursor, 1, 6);
|
||||
});
|
||||
|
||||
test('move to first non white space character of line from first non white space character', () => {
|
||||
moveTo(thisCursor, 1, 6);
|
||||
|
||||
moveToLineFirstNonWhiteSpaceCharacter(thisCursor);
|
||||
|
||||
cursorEqual(thisCursor, 1, 6);
|
||||
});
|
||||
|
||||
test('move to first non white space character of line from first character', () => {
|
||||
moveTo(thisCursor, 1, 1);
|
||||
|
||||
moveToLineFirstNonWhiteSpaceCharacter(thisCursor);
|
||||
|
||||
cursorEqual(thisCursor, 1, 6);
|
||||
});
|
||||
|
||||
test('move to end of line from middle', () => {
|
||||
moveTo(thisCursor, 1, 8);
|
||||
|
||||
moveToLineEnd(thisCursor);
|
||||
|
||||
cursorEqual(thisCursor, 1, 21);
|
||||
});
|
||||
|
||||
test('move to end of line from last non white space character', () => {
|
||||
moveTo(thisCursor, 1, 19);
|
||||
|
||||
moveToLineEnd(thisCursor);
|
||||
|
||||
cursorEqual(thisCursor, 1, 21);
|
||||
});
|
||||
|
||||
test('move to end of line from line end', () => {
|
||||
moveTo(thisCursor, 1, 21);
|
||||
|
||||
moveToLineEnd(thisCursor);
|
||||
|
||||
cursorEqual(thisCursor, 1, 21);
|
||||
});
|
||||
|
||||
test('move to last non white space character from middle', () => {
|
||||
moveTo(thisCursor, 1, 8);
|
||||
|
||||
moveToLineLastNonWhiteSpaceCharacter(thisCursor);
|
||||
|
||||
cursorEqual(thisCursor, 1, 19);
|
||||
});
|
||||
|
||||
test('move to last non white space character from last non white space character', () => {
|
||||
moveTo(thisCursor, 1, 19);
|
||||
|
||||
moveToLineLastNonWhiteSpaceCharacter(thisCursor);
|
||||
|
||||
cursorEqual(thisCursor, 1, 19);
|
||||
});
|
||||
|
||||
test('move to last non white space character from line end', () => {
|
||||
moveTo(thisCursor, 1, 21);
|
||||
|
||||
moveToLineLastNonWhiteSpaceCharacter(thisCursor);
|
||||
|
||||
cursorEqual(thisCursor, 1, 19);
|
||||
});
|
||||
|
||||
test('move to center of line not from center', () => {
|
||||
moveTo(thisCursor, 1, 8);
|
||||
|
||||
moveToLineCenter(thisCursor);
|
||||
|
||||
cursorEqual(thisCursor, 1, 11);
|
||||
});
|
||||
|
||||
test('move to center of line from center', () => {
|
||||
moveTo(thisCursor, 1, 11);
|
||||
|
||||
moveToLineCenter(thisCursor);
|
||||
|
||||
cursorEqual(thisCursor, 1, 11);
|
||||
});
|
||||
|
||||
test('move to center of line from start', () => {
|
||||
moveToLineStart(thisCursor);
|
||||
|
||||
moveToLineCenter(thisCursor);
|
||||
|
||||
cursorEqual(thisCursor, 1, 11);
|
||||
});
|
||||
|
||||
test('move to center of line from end', () => {
|
||||
moveToLineEnd(thisCursor);
|
||||
|
||||
moveToLineCenter(thisCursor);
|
||||
|
||||
cursorEqual(thisCursor, 1, 11);
|
||||
});
|
||||
|
||||
test('move up by cursor move command', () => {
|
||||
|
||||
moveTo(thisCursor, 3, 5);
|
||||
cursorEqual(thisCursor, 3, 5);
|
||||
|
||||
moveUp(thisCursor, 2);
|
||||
cursorEqual(thisCursor, 1, 5);
|
||||
|
||||
moveUp(thisCursor, 1);
|
||||
cursorEqual(thisCursor, 1, 1);
|
||||
});
|
||||
|
||||
test('move up by model line cursor move command', () => {
|
||||
|
||||
moveTo(thisCursor, 3, 5);
|
||||
cursorEqual(thisCursor, 3, 5);
|
||||
|
||||
moveUpByModelLine(thisCursor, 2);
|
||||
cursorEqual(thisCursor, 1, 5);
|
||||
|
||||
moveUpByModelLine(thisCursor, 1);
|
||||
cursorEqual(thisCursor, 1, 1);
|
||||
});
|
||||
|
||||
test('move down by model line cursor move command', () => {
|
||||
|
||||
moveTo(thisCursor, 3, 5);
|
||||
cursorEqual(thisCursor, 3, 5);
|
||||
|
||||
moveDownByModelLine(thisCursor, 2);
|
||||
cursorEqual(thisCursor, 5, 2);
|
||||
|
||||
moveDownByModelLine(thisCursor, 1);
|
||||
cursorEqual(thisCursor, 5, 2);
|
||||
});
|
||||
|
||||
test('move up with selection by cursor move command', () => {
|
||||
|
||||
moveTo(thisCursor, 3, 5);
|
||||
cursorEqual(thisCursor, 3, 5);
|
||||
|
||||
moveUp(thisCursor, 1, true);
|
||||
cursorEqual(thisCursor, 2, 2, 3, 5);
|
||||
|
||||
moveUp(thisCursor, 1, true);
|
||||
cursorEqual(thisCursor, 1, 5, 3, 5);
|
||||
});
|
||||
|
||||
test('move up and down with tabs by cursor move command', () => {
|
||||
|
||||
moveTo(thisCursor, 1, 5);
|
||||
cursorEqual(thisCursor, 1, 5);
|
||||
|
||||
moveDown(thisCursor, 4);
|
||||
cursorEqual(thisCursor, 5, 2);
|
||||
|
||||
moveUp(thisCursor, 1);
|
||||
cursorEqual(thisCursor, 4, 1);
|
||||
|
||||
moveUp(thisCursor, 1);
|
||||
cursorEqual(thisCursor, 3, 5);
|
||||
|
||||
moveUp(thisCursor, 1);
|
||||
cursorEqual(thisCursor, 2, 2);
|
||||
|
||||
moveUp(thisCursor, 1);
|
||||
cursorEqual(thisCursor, 1, 5);
|
||||
});
|
||||
|
||||
test('move up and down with end of lines starting from a long one by cursor move command', () => {
|
||||
|
||||
moveToEndOfLine(thisCursor);
|
||||
cursorEqual(thisCursor, 1, 21);
|
||||
|
||||
moveToEndOfLine(thisCursor);
|
||||
cursorEqual(thisCursor, 1, 21);
|
||||
|
||||
moveDown(thisCursor, 2);
|
||||
cursorEqual(thisCursor, 3, 17);
|
||||
|
||||
moveDown(thisCursor, 1);
|
||||
cursorEqual(thisCursor, 4, 1);
|
||||
|
||||
moveDown(thisCursor, 1);
|
||||
cursorEqual(thisCursor, 5, 2);
|
||||
|
||||
moveUp(thisCursor, 4);
|
||||
cursorEqual(thisCursor, 1, 21);
|
||||
});
|
||||
|
||||
test('move to view top line moves to first visible line if it is first line', () => {
|
||||
thisViewModel.getCompletelyVisibleViewRange = () => new Range(1, 1, 10, 1);
|
||||
|
||||
moveTo(thisCursor, 2, 2);
|
||||
moveToTop(thisCursor);
|
||||
|
||||
cursorEqual(thisCursor, 1, 6);
|
||||
});
|
||||
|
||||
test('move to view top line moves to top visible line when first line is not visible', () => {
|
||||
thisViewModel.getCompletelyVisibleViewRange = () => new Range(2, 1, 10, 1);
|
||||
|
||||
moveTo(thisCursor, 4, 1);
|
||||
moveToTop(thisCursor);
|
||||
|
||||
cursorEqual(thisCursor, 2, 2);
|
||||
});
|
||||
|
||||
test('move to view top line moves to nth line from top', () => {
|
||||
thisViewModel.getCompletelyVisibleViewRange = () => new Range(1, 1, 10, 1);
|
||||
|
||||
moveTo(thisCursor, 4, 1);
|
||||
moveToTop(thisCursor, 3);
|
||||
|
||||
cursorEqual(thisCursor, 3, 5);
|
||||
});
|
||||
|
||||
test('move to view top line moves to last line if n is greater than last visible line number', () => {
|
||||
thisViewModel.getCompletelyVisibleViewRange = () => new Range(1, 1, 3, 1);
|
||||
|
||||
moveTo(thisCursor, 2, 2);
|
||||
moveToTop(thisCursor, 4);
|
||||
|
||||
cursorEqual(thisCursor, 3, 5);
|
||||
});
|
||||
|
||||
test('move to view center line moves to the center line', () => {
|
||||
thisViewModel.getCompletelyVisibleViewRange = () => new Range(3, 1, 3, 1);
|
||||
|
||||
moveTo(thisCursor, 2, 2);
|
||||
moveToCenter(thisCursor);
|
||||
|
||||
cursorEqual(thisCursor, 3, 5);
|
||||
});
|
||||
|
||||
test('move to view bottom line moves to last visible line if it is last line', () => {
|
||||
thisViewModel.getCompletelyVisibleViewRange = () => new Range(1, 1, 5, 1);
|
||||
|
||||
moveTo(thisCursor, 2, 2);
|
||||
moveToBottom(thisCursor);
|
||||
|
||||
cursorEqual(thisCursor, 5, 1);
|
||||
});
|
||||
|
||||
test('move to view bottom line moves to last visible line when last line is not visible', () => {
|
||||
thisViewModel.getCompletelyVisibleViewRange = () => new Range(2, 1, 3, 1);
|
||||
|
||||
moveTo(thisCursor, 2, 2);
|
||||
moveToBottom(thisCursor);
|
||||
|
||||
cursorEqual(thisCursor, 3, 5);
|
||||
});
|
||||
|
||||
test('move to view bottom line moves to nth line from bottom', () => {
|
||||
thisViewModel.getCompletelyVisibleViewRange = () => new Range(1, 1, 5, 1);
|
||||
|
||||
moveTo(thisCursor, 4, 1);
|
||||
moveToBottom(thisCursor, 3);
|
||||
|
||||
cursorEqual(thisCursor, 3, 5);
|
||||
});
|
||||
|
||||
test('move to view bottom line moves to first line if n is lesser than first visible line number', () => {
|
||||
thisViewModel.getCompletelyVisibleViewRange = () => new Range(2, 1, 5, 1);
|
||||
|
||||
moveTo(thisCursor, 4, 1);
|
||||
moveToBottom(thisCursor, 5);
|
||||
|
||||
cursorEqual(thisCursor, 2, 2);
|
||||
});
|
||||
});
|
||||
|
||||
// Move command
|
||||
|
||||
function move(cursor: Cursor, args: any) {
|
||||
CoreNavigationCommands.CursorMove.runCoreEditorCommand(cursor, args);
|
||||
}
|
||||
|
||||
function moveToLineStart(cursor: Cursor) {
|
||||
move(cursor, { to: CursorMove.RawDirection.WrappedLineStart });
|
||||
}
|
||||
|
||||
function moveToLineFirstNonWhiteSpaceCharacter(cursor: Cursor) {
|
||||
move(cursor, { to: CursorMove.RawDirection.WrappedLineFirstNonWhitespaceCharacter });
|
||||
}
|
||||
|
||||
function moveToLineCenter(cursor: Cursor) {
|
||||
move(cursor, { to: CursorMove.RawDirection.WrappedLineColumnCenter });
|
||||
}
|
||||
|
||||
function moveToLineEnd(cursor: Cursor) {
|
||||
move(cursor, { to: CursorMove.RawDirection.WrappedLineEnd });
|
||||
}
|
||||
|
||||
function moveToLineLastNonWhiteSpaceCharacter(cursor: Cursor) {
|
||||
move(cursor, { to: CursorMove.RawDirection.WrappedLineLastNonWhitespaceCharacter });
|
||||
}
|
||||
|
||||
function moveLeft(cursor: Cursor, value?: number, by?: string, select?: boolean) {
|
||||
move(cursor, { to: CursorMove.RawDirection.Left, by: by, value: value, select: select });
|
||||
}
|
||||
|
||||
function moveRight(cursor: Cursor, value?: number, by?: string, select?: boolean) {
|
||||
move(cursor, { to: CursorMove.RawDirection.Right, by: by, value: value, select: select });
|
||||
}
|
||||
|
||||
function moveUp(cursor: Cursor, noOfLines: number = 1, select?: boolean) {
|
||||
move(cursor, { to: CursorMove.RawDirection.Up, by: CursorMove.RawUnit.WrappedLine, value: noOfLines, select: select });
|
||||
}
|
||||
|
||||
function moveUpByModelLine(cursor: Cursor, noOfLines: number = 1, select?: boolean) {
|
||||
move(cursor, { to: CursorMove.RawDirection.Up, value: noOfLines, select: select });
|
||||
}
|
||||
|
||||
function moveDown(cursor: Cursor, noOfLines: number = 1, select?: boolean) {
|
||||
move(cursor, { to: CursorMove.RawDirection.Down, by: CursorMove.RawUnit.WrappedLine, value: noOfLines, select: select });
|
||||
}
|
||||
|
||||
function moveDownByModelLine(cursor: Cursor, noOfLines: number = 1, select?: boolean) {
|
||||
move(cursor, { to: CursorMove.RawDirection.Down, value: noOfLines, select: select });
|
||||
}
|
||||
|
||||
function moveToTop(cursor: Cursor, noOfLines: number = 1, select?: boolean) {
|
||||
move(cursor, { to: CursorMove.RawDirection.ViewPortTop, value: noOfLines, select: select });
|
||||
}
|
||||
|
||||
function moveToCenter(cursor: Cursor, select?: boolean) {
|
||||
move(cursor, { to: CursorMove.RawDirection.ViewPortCenter, select: select });
|
||||
}
|
||||
|
||||
function moveToBottom(cursor: Cursor, noOfLines: number = 1, select?: boolean) {
|
||||
move(cursor, { to: CursorMove.RawDirection.ViewPortBottom, value: noOfLines, select: select });
|
||||
}
|
||||
|
||||
function cursorEqual(cursor: Cursor, posLineNumber: number, posColumn: number, selLineNumber: number = posLineNumber, selColumn: number = posColumn) {
|
||||
positionEqual(cursor.getPosition(), posLineNumber, posColumn);
|
||||
selectionEqual(cursor.getSelection(), posLineNumber, posColumn, selLineNumber, selColumn);
|
||||
}
|
||||
|
||||
function positionEqual(position: Position, lineNumber: number, column: number) {
|
||||
assert.deepEqual(position, new Position(lineNumber, column), 'position equal');
|
||||
}
|
||||
|
||||
function selectionEqual(selection: Selection, posLineNumber: number, posColumn: number, selLineNumber: number, selColumn: number) {
|
||||
assert.deepEqual({
|
||||
selectionStartLineNumber: selection.selectionStartLineNumber,
|
||||
selectionStartColumn: selection.selectionStartColumn,
|
||||
positionLineNumber: selection.positionLineNumber,
|
||||
positionColumn: selection.positionColumn
|
||||
}, {
|
||||
selectionStartLineNumber: selLineNumber,
|
||||
selectionStartColumn: selColumn,
|
||||
positionLineNumber: posLineNumber,
|
||||
positionColumn: posColumn
|
||||
}, 'selection equal');
|
||||
}
|
||||
|
||||
function moveTo(cursor: Cursor, lineNumber: number, column: number, inSelectionMode: boolean = false) {
|
||||
if (inSelectionMode) {
|
||||
CoreNavigationCommands.MoveToSelect.runCoreEditorCommand(cursor, {
|
||||
position: new Position(lineNumber, column)
|
||||
});
|
||||
} else {
|
||||
CoreNavigationCommands.MoveTo.runCoreEditorCommand(cursor, {
|
||||
position: new Position(lineNumber, column)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function moveToEndOfLine(cursor: Cursor, inSelectionMode: boolean = false) {
|
||||
if (inSelectionMode) {
|
||||
CoreNavigationCommands.CursorEndSelect.runCoreEditorCommand(cursor, {});
|
||||
} else {
|
||||
CoreNavigationCommands.CursorEnd.runCoreEditorCommand(cursor, {});
|
||||
}
|
||||
}
|
||||
178
src/vs/editor/test/common/controller/cursorMoveHelper.test.ts
Normal file
178
src/vs/editor/test/common/controller/cursorMoveHelper.test.ts
Normal file
@@ -0,0 +1,178 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { CursorColumns } from 'vs/editor/common/controller/cursorCommon';
|
||||
|
||||
suite('CursorMove', () => {
|
||||
|
||||
test('nextTabStop', () => {
|
||||
assert.equal(CursorColumns.nextTabStop(0, 4), 4);
|
||||
assert.equal(CursorColumns.nextTabStop(1, 4), 4);
|
||||
assert.equal(CursorColumns.nextTabStop(2, 4), 4);
|
||||
assert.equal(CursorColumns.nextTabStop(3, 4), 4);
|
||||
assert.equal(CursorColumns.nextTabStop(4, 4), 8);
|
||||
assert.equal(CursorColumns.nextTabStop(5, 4), 8);
|
||||
assert.equal(CursorColumns.nextTabStop(6, 4), 8);
|
||||
assert.equal(CursorColumns.nextTabStop(7, 4), 8);
|
||||
assert.equal(CursorColumns.nextTabStop(8, 4), 12);
|
||||
|
||||
assert.equal(CursorColumns.nextTabStop(0, 2), 2);
|
||||
assert.equal(CursorColumns.nextTabStop(1, 2), 2);
|
||||
assert.equal(CursorColumns.nextTabStop(2, 2), 4);
|
||||
assert.equal(CursorColumns.nextTabStop(3, 2), 4);
|
||||
assert.equal(CursorColumns.nextTabStop(4, 2), 6);
|
||||
assert.equal(CursorColumns.nextTabStop(5, 2), 6);
|
||||
assert.equal(CursorColumns.nextTabStop(6, 2), 8);
|
||||
assert.equal(CursorColumns.nextTabStop(7, 2), 8);
|
||||
assert.equal(CursorColumns.nextTabStop(8, 2), 10);
|
||||
|
||||
assert.equal(CursorColumns.nextTabStop(0, 1), 1);
|
||||
assert.equal(CursorColumns.nextTabStop(1, 1), 2);
|
||||
assert.equal(CursorColumns.nextTabStop(2, 1), 3);
|
||||
assert.equal(CursorColumns.nextTabStop(3, 1), 4);
|
||||
assert.equal(CursorColumns.nextTabStop(4, 1), 5);
|
||||
assert.equal(CursorColumns.nextTabStop(5, 1), 6);
|
||||
assert.equal(CursorColumns.nextTabStop(6, 1), 7);
|
||||
assert.equal(CursorColumns.nextTabStop(7, 1), 8);
|
||||
assert.equal(CursorColumns.nextTabStop(8, 1), 9);
|
||||
});
|
||||
|
||||
test('visibleColumnFromColumn', () => {
|
||||
|
||||
function testVisibleColumnFromColumn(text: string, tabSize: number, column: number, expected: number): void {
|
||||
assert.equal(CursorColumns.visibleColumnFromColumn(text, column, tabSize), expected);
|
||||
}
|
||||
|
||||
testVisibleColumnFromColumn('\t\tvar x = 3;', 4, 1, 0);
|
||||
testVisibleColumnFromColumn('\t\tvar x = 3;', 4, 2, 4);
|
||||
testVisibleColumnFromColumn('\t\tvar x = 3;', 4, 3, 8);
|
||||
testVisibleColumnFromColumn('\t\tvar x = 3;', 4, 4, 9);
|
||||
testVisibleColumnFromColumn('\t\tvar x = 3;', 4, 5, 10);
|
||||
testVisibleColumnFromColumn('\t\tvar x = 3;', 4, 6, 11);
|
||||
testVisibleColumnFromColumn('\t\tvar x = 3;', 4, 7, 12);
|
||||
testVisibleColumnFromColumn('\t\tvar x = 3;', 4, 8, 13);
|
||||
testVisibleColumnFromColumn('\t\tvar x = 3;', 4, 9, 14);
|
||||
testVisibleColumnFromColumn('\t\tvar x = 3;', 4, 10, 15);
|
||||
testVisibleColumnFromColumn('\t\tvar x = 3;', 4, 11, 16);
|
||||
testVisibleColumnFromColumn('\t\tvar x = 3;', 4, 12, 17);
|
||||
testVisibleColumnFromColumn('\t\tvar x = 3;', 4, 13, 18);
|
||||
|
||||
testVisibleColumnFromColumn('\t \tvar x = 3;', 4, 1, 0);
|
||||
testVisibleColumnFromColumn('\t \tvar x = 3;', 4, 2, 4);
|
||||
testVisibleColumnFromColumn('\t \tvar x = 3;', 4, 3, 5);
|
||||
testVisibleColumnFromColumn('\t \tvar x = 3;', 4, 4, 8);
|
||||
testVisibleColumnFromColumn('\t \tvar x = 3;', 4, 5, 9);
|
||||
testVisibleColumnFromColumn('\t \tvar x = 3;', 4, 6, 10);
|
||||
testVisibleColumnFromColumn('\t \tvar x = 3;', 4, 7, 11);
|
||||
testVisibleColumnFromColumn('\t \tvar x = 3;', 4, 8, 12);
|
||||
testVisibleColumnFromColumn('\t \tvar x = 3;', 4, 9, 13);
|
||||
testVisibleColumnFromColumn('\t \tvar x = 3;', 4, 10, 14);
|
||||
testVisibleColumnFromColumn('\t \tvar x = 3;', 4, 11, 15);
|
||||
testVisibleColumnFromColumn('\t \tvar x = 3;', 4, 12, 16);
|
||||
testVisibleColumnFromColumn('\t \tvar x = 3;', 4, 13, 17);
|
||||
testVisibleColumnFromColumn('\t \tvar x = 3;', 4, 14, 18);
|
||||
|
||||
testVisibleColumnFromColumn('\t \tx\t', 4, -1, 0);
|
||||
testVisibleColumnFromColumn('\t \tx\t', 4, 0, 0);
|
||||
testVisibleColumnFromColumn('\t \tx\t', 4, 1, 0);
|
||||
testVisibleColumnFromColumn('\t \tx\t', 4, 2, 4);
|
||||
testVisibleColumnFromColumn('\t \tx\t', 4, 3, 5);
|
||||
testVisibleColumnFromColumn('\t \tx\t', 4, 4, 6);
|
||||
testVisibleColumnFromColumn('\t \tx\t', 4, 5, 8);
|
||||
testVisibleColumnFromColumn('\t \tx\t', 4, 6, 9);
|
||||
testVisibleColumnFromColumn('\t \tx\t', 4, 7, 12);
|
||||
testVisibleColumnFromColumn('\t \tx\t', 4, 8, 12);
|
||||
testVisibleColumnFromColumn('\t \tx\t', 4, 9, 12);
|
||||
|
||||
testVisibleColumnFromColumn('baz', 4, 1, 0);
|
||||
testVisibleColumnFromColumn('baz', 4, 2, 1);
|
||||
testVisibleColumnFromColumn('baz', 4, 3, 2);
|
||||
testVisibleColumnFromColumn('baz', 4, 4, 3);
|
||||
|
||||
testVisibleColumnFromColumn('📚az', 4, 1, 0);
|
||||
testVisibleColumnFromColumn('📚az', 4, 2, 1);
|
||||
testVisibleColumnFromColumn('📚az', 4, 3, 2);
|
||||
testVisibleColumnFromColumn('📚az', 4, 4, 3);
|
||||
testVisibleColumnFromColumn('📚az', 4, 5, 4);
|
||||
});
|
||||
|
||||
test('columnFromVisibleColumn', () => {
|
||||
|
||||
function testColumnFromVisibleColumn(text: string, tabSize: number, visibleColumn: number, expected: number): void {
|
||||
assert.equal(CursorColumns.columnFromVisibleColumn(text, visibleColumn, tabSize), expected);
|
||||
}
|
||||
|
||||
// testColumnFromVisibleColumn('\t\tvar x = 3;', 4, 0, 1);
|
||||
testColumnFromVisibleColumn('\t\tvar x = 3;', 4, 1, 1);
|
||||
testColumnFromVisibleColumn('\t\tvar x = 3;', 4, 2, 1);
|
||||
testColumnFromVisibleColumn('\t\tvar x = 3;', 4, 3, 2);
|
||||
testColumnFromVisibleColumn('\t\tvar x = 3;', 4, 4, 2);
|
||||
testColumnFromVisibleColumn('\t\tvar x = 3;', 4, 5, 2);
|
||||
testColumnFromVisibleColumn('\t\tvar x = 3;', 4, 6, 2);
|
||||
testColumnFromVisibleColumn('\t\tvar x = 3;', 4, 7, 3);
|
||||
testColumnFromVisibleColumn('\t\tvar x = 3;', 4, 8, 3);
|
||||
testColumnFromVisibleColumn('\t\tvar x = 3;', 4, 9, 4);
|
||||
testColumnFromVisibleColumn('\t\tvar x = 3;', 4, 10, 5);
|
||||
testColumnFromVisibleColumn('\t\tvar x = 3;', 4, 11, 6);
|
||||
testColumnFromVisibleColumn('\t\tvar x = 3;', 4, 12, 7);
|
||||
testColumnFromVisibleColumn('\t\tvar x = 3;', 4, 13, 8);
|
||||
testColumnFromVisibleColumn('\t\tvar x = 3;', 4, 14, 9);
|
||||
testColumnFromVisibleColumn('\t\tvar x = 3;', 4, 15, 10);
|
||||
testColumnFromVisibleColumn('\t\tvar x = 3;', 4, 16, 11);
|
||||
testColumnFromVisibleColumn('\t\tvar x = 3;', 4, 17, 12);
|
||||
testColumnFromVisibleColumn('\t\tvar x = 3;', 4, 18, 13);
|
||||
|
||||
testColumnFromVisibleColumn('\t \tvar x = 3;', 4, 0, 1);
|
||||
testColumnFromVisibleColumn('\t \tvar x = 3;', 4, 1, 1);
|
||||
testColumnFromVisibleColumn('\t \tvar x = 3;', 4, 2, 1);
|
||||
testColumnFromVisibleColumn('\t \tvar x = 3;', 4, 3, 2);
|
||||
testColumnFromVisibleColumn('\t \tvar x = 3;', 4, 4, 2);
|
||||
testColumnFromVisibleColumn('\t \tvar x = 3;', 4, 5, 3);
|
||||
testColumnFromVisibleColumn('\t \tvar x = 3;', 4, 6, 3);
|
||||
testColumnFromVisibleColumn('\t \tvar x = 3;', 4, 7, 4);
|
||||
testColumnFromVisibleColumn('\t \tvar x = 3;', 4, 8, 4);
|
||||
testColumnFromVisibleColumn('\t \tvar x = 3;', 4, 9, 5);
|
||||
testColumnFromVisibleColumn('\t \tvar x = 3;', 4, 10, 6);
|
||||
testColumnFromVisibleColumn('\t \tvar x = 3;', 4, 11, 7);
|
||||
testColumnFromVisibleColumn('\t \tvar x = 3;', 4, 12, 8);
|
||||
testColumnFromVisibleColumn('\t \tvar x = 3;', 4, 13, 9);
|
||||
testColumnFromVisibleColumn('\t \tvar x = 3;', 4, 14, 10);
|
||||
testColumnFromVisibleColumn('\t \tvar x = 3;', 4, 15, 11);
|
||||
testColumnFromVisibleColumn('\t \tvar x = 3;', 4, 16, 12);
|
||||
testColumnFromVisibleColumn('\t \tvar x = 3;', 4, 17, 13);
|
||||
testColumnFromVisibleColumn('\t \tvar x = 3;', 4, 18, 14);
|
||||
|
||||
testColumnFromVisibleColumn('\t \tx\t', 4, -2, 1);
|
||||
testColumnFromVisibleColumn('\t \tx\t', 4, -1, 1);
|
||||
testColumnFromVisibleColumn('\t \tx\t', 4, 0, 1);
|
||||
testColumnFromVisibleColumn('\t \tx\t', 4, 1, 1);
|
||||
testColumnFromVisibleColumn('\t \tx\t', 4, 2, 1);
|
||||
testColumnFromVisibleColumn('\t \tx\t', 4, 3, 2);
|
||||
testColumnFromVisibleColumn('\t \tx\t', 4, 4, 2);
|
||||
testColumnFromVisibleColumn('\t \tx\t', 4, 5, 3);
|
||||
testColumnFromVisibleColumn('\t \tx\t', 4, 6, 4);
|
||||
testColumnFromVisibleColumn('\t \tx\t', 4, 7, 4);
|
||||
testColumnFromVisibleColumn('\t \tx\t', 4, 8, 5);
|
||||
testColumnFromVisibleColumn('\t \tx\t', 4, 9, 6);
|
||||
testColumnFromVisibleColumn('\t \tx\t', 4, 10, 6);
|
||||
testColumnFromVisibleColumn('\t \tx\t', 4, 11, 7);
|
||||
testColumnFromVisibleColumn('\t \tx\t', 4, 12, 7);
|
||||
testColumnFromVisibleColumn('\t \tx\t', 4, 13, 7);
|
||||
testColumnFromVisibleColumn('\t \tx\t', 4, 14, 7);
|
||||
|
||||
testColumnFromVisibleColumn('baz', 4, 0, 1);
|
||||
testColumnFromVisibleColumn('baz', 4, 1, 2);
|
||||
testColumnFromVisibleColumn('baz', 4, 2, 3);
|
||||
testColumnFromVisibleColumn('baz', 4, 3, 4);
|
||||
|
||||
testColumnFromVisibleColumn('📚az', 4, 0, 1);
|
||||
testColumnFromVisibleColumn('📚az', 4, 1, 2);
|
||||
testColumnFromVisibleColumn('📚az', 4, 2, 3);
|
||||
testColumnFromVisibleColumn('📚az', 4, 3, 4);
|
||||
testColumnFromVisibleColumn('📚az', 4, 4, 5);
|
||||
});
|
||||
});
|
||||
39
src/vs/editor/test/common/core/characterClassifier.test.ts
Normal file
39
src/vs/editor/test/common/core/characterClassifier.test.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { CharacterClassifier } from 'vs/editor/common/core/characterClassifier';
|
||||
import { CharCode } from 'vs/base/common/charCode';
|
||||
|
||||
suite('CharacterClassifier', () => {
|
||||
|
||||
test('works', () => {
|
||||
let classifier = new CharacterClassifier<number>(0);
|
||||
|
||||
assert.equal(classifier.get(-1), 0);
|
||||
assert.equal(classifier.get(0), 0);
|
||||
assert.equal(classifier.get(CharCode.a), 0);
|
||||
assert.equal(classifier.get(CharCode.b), 0);
|
||||
assert.equal(classifier.get(CharCode.z), 0);
|
||||
assert.equal(classifier.get(255), 0);
|
||||
assert.equal(classifier.get(1000), 0);
|
||||
assert.equal(classifier.get(2000), 0);
|
||||
|
||||
classifier.set(CharCode.a, 1);
|
||||
classifier.set(CharCode.z, 2);
|
||||
classifier.set(1000, 3);
|
||||
|
||||
assert.equal(classifier.get(-1), 0);
|
||||
assert.equal(classifier.get(0), 0);
|
||||
assert.equal(classifier.get(CharCode.a), 1);
|
||||
assert.equal(classifier.get(CharCode.b), 0);
|
||||
assert.equal(classifier.get(CharCode.z), 2);
|
||||
assert.equal(classifier.get(255), 0);
|
||||
assert.equal(classifier.get(1000), 3);
|
||||
assert.equal(classifier.get(2000), 0);
|
||||
});
|
||||
|
||||
});
|
||||
104
src/vs/editor/test/common/core/editorState.test.ts
Normal file
104
src/vs/editor/test/common/core/editorState.test.ts
Normal file
@@ -0,0 +1,104 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 URI from 'vs/base/common/uri';
|
||||
import { ICommonCodeEditor, IModel } from 'vs/editor/common/editorCommon';
|
||||
import { EditorState, CodeEditorStateFlag } from 'vs/editor/common/core/editorState';
|
||||
import { Selection } from 'vs/editor/common/core/selection';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
|
||||
interface IStubEditorState {
|
||||
model?: { uri?: URI, version?: number };
|
||||
position?: Position;
|
||||
selection?: Selection;
|
||||
scroll?: { left?: number, top?: number };
|
||||
}
|
||||
|
||||
suite('Editor Core - Editor State', () => {
|
||||
|
||||
const allFlags = (
|
||||
CodeEditorStateFlag.Value
|
||||
| CodeEditorStateFlag.Selection
|
||||
| CodeEditorStateFlag.Position
|
||||
| CodeEditorStateFlag.Scroll
|
||||
);
|
||||
|
||||
test('empty editor state should be valid', () => {
|
||||
let result = validate({}, {});
|
||||
assert.equal(result, true);
|
||||
});
|
||||
|
||||
test('different model URIs should be invalid', () => {
|
||||
let result = validate(
|
||||
{ model: { uri: URI.parse('http://test1') } },
|
||||
{ model: { uri: URI.parse('http://test2') } }
|
||||
);
|
||||
|
||||
assert.equal(result, false);
|
||||
});
|
||||
|
||||
test('different model versions should be invalid', () => {
|
||||
let result = validate(
|
||||
{ model: { version: 1 } },
|
||||
{ model: { version: 2 } }
|
||||
);
|
||||
|
||||
assert.equal(result, false);
|
||||
});
|
||||
|
||||
test('different positions should be invalid', () => {
|
||||
let result = validate(
|
||||
{ position: new Position(1, 2) },
|
||||
{ position: new Position(2, 3) }
|
||||
);
|
||||
|
||||
assert.equal(result, false);
|
||||
});
|
||||
|
||||
test('different selections should be invalid', () => {
|
||||
let result = validate(
|
||||
{ selection: new Selection(1, 2, 3, 4) },
|
||||
{ selection: new Selection(5, 2, 3, 4) }
|
||||
);
|
||||
|
||||
assert.equal(result, false);
|
||||
});
|
||||
|
||||
test('different scroll positions should be invalid', () => {
|
||||
let result = validate(
|
||||
{ scroll: { left: 1, top: 2 } },
|
||||
{ scroll: { left: 3, top: 2 } }
|
||||
);
|
||||
|
||||
assert.equal(result, false);
|
||||
});
|
||||
|
||||
|
||||
function validate(source: IStubEditorState, target: IStubEditorState) {
|
||||
let sourceEditor = createEditor(source),
|
||||
targetEditor = createEditor(target);
|
||||
|
||||
let result = new EditorState(sourceEditor, allFlags).validate(targetEditor);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function createEditor({ model, position, selection, scroll }: IStubEditorState = {}): ICommonCodeEditor {
|
||||
let mappedModel = model ? { uri: model.uri ? model.uri : URI.parse('http://dummy.org'), getVersionId: () => model.version } : null;
|
||||
|
||||
return <any>{
|
||||
getModel: (): IModel => <any>mappedModel,
|
||||
getPosition: (): Position => position,
|
||||
getSelection: (): Selection => selection,
|
||||
getScrollLeft: (): number => scroll && scroll.left,
|
||||
getScrollTop: (): number => scroll && scroll.top
|
||||
};
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
292
src/vs/editor/test/common/core/lineTokens.test.ts
Normal file
292
src/vs/editor/test/common/core/lineTokens.test.ts
Normal file
@@ -0,0 +1,292 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { LineTokens } from 'vs/editor/common/core/lineTokens';
|
||||
import { MetadataConsts } from 'vs/editor/common/modes';
|
||||
import { ViewLineToken } from 'vs/editor/common/core/viewLineToken';
|
||||
|
||||
suite('LineTokens', () => {
|
||||
|
||||
interface ILineToken {
|
||||
startIndex: number;
|
||||
foreground: number;
|
||||
}
|
||||
|
||||
function createLineTokens(text: string, tokens: ILineToken[]): LineTokens {
|
||||
let binTokens = new Uint32Array(tokens.length << 1);
|
||||
|
||||
for (let i = 0, len = tokens.length; i < len; i++) {
|
||||
let token = tokens[i];
|
||||
binTokens[(i << 1)] = token.startIndex;
|
||||
binTokens[(i << 1) + 1] = (
|
||||
token.foreground << MetadataConsts.FOREGROUND_OFFSET
|
||||
) >>> 0;
|
||||
}
|
||||
|
||||
return new LineTokens(binTokens, text);
|
||||
}
|
||||
|
||||
function createTestLineTokens(): LineTokens {
|
||||
return createLineTokens(
|
||||
'Hello world, this is a lovely day',
|
||||
[
|
||||
{ startIndex: 0, foreground: 1 }, // Hello_
|
||||
{ startIndex: 6, foreground: 2 }, // world,_
|
||||
{ startIndex: 13, foreground: 3 }, // this_
|
||||
{ startIndex: 18, foreground: 4 }, // is_
|
||||
{ startIndex: 21, foreground: 5 }, // a_
|
||||
{ startIndex: 23, foreground: 6 }, // lovely_
|
||||
{ startIndex: 30, foreground: 7 }, // day
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
test('basics', () => {
|
||||
const lineTokens = createTestLineTokens();
|
||||
|
||||
assert.equal(lineTokens.getLineContent(), 'Hello world, this is a lovely day');
|
||||
assert.equal(lineTokens.getLineLength(), 33);
|
||||
assert.equal(lineTokens.getTokenCount(), 7);
|
||||
|
||||
assert.equal(lineTokens.getTokenStartOffset(0), 0);
|
||||
assert.equal(lineTokens.getTokenEndOffset(0), 6);
|
||||
assert.equal(lineTokens.getTokenStartOffset(1), 6);
|
||||
assert.equal(lineTokens.getTokenEndOffset(1), 13);
|
||||
assert.equal(lineTokens.getTokenStartOffset(2), 13);
|
||||
assert.equal(lineTokens.getTokenEndOffset(2), 18);
|
||||
assert.equal(lineTokens.getTokenStartOffset(3), 18);
|
||||
assert.equal(lineTokens.getTokenEndOffset(3), 21);
|
||||
assert.equal(lineTokens.getTokenStartOffset(4), 21);
|
||||
assert.equal(lineTokens.getTokenEndOffset(4), 23);
|
||||
assert.equal(lineTokens.getTokenStartOffset(5), 23);
|
||||
assert.equal(lineTokens.getTokenEndOffset(5), 30);
|
||||
assert.equal(lineTokens.getTokenStartOffset(6), 30);
|
||||
assert.equal(lineTokens.getTokenEndOffset(6), 33);
|
||||
});
|
||||
|
||||
test('findToken', () => {
|
||||
const lineTokens = createTestLineTokens();
|
||||
|
||||
assert.equal(lineTokens.findTokenIndexAtOffset(0), 0);
|
||||
assert.equal(lineTokens.findTokenIndexAtOffset(1), 0);
|
||||
assert.equal(lineTokens.findTokenIndexAtOffset(2), 0);
|
||||
assert.equal(lineTokens.findTokenIndexAtOffset(3), 0);
|
||||
assert.equal(lineTokens.findTokenIndexAtOffset(4), 0);
|
||||
assert.equal(lineTokens.findTokenIndexAtOffset(5), 0);
|
||||
assert.equal(lineTokens.findTokenIndexAtOffset(6), 1);
|
||||
assert.equal(lineTokens.findTokenIndexAtOffset(7), 1);
|
||||
assert.equal(lineTokens.findTokenIndexAtOffset(8), 1);
|
||||
assert.equal(lineTokens.findTokenIndexAtOffset(9), 1);
|
||||
assert.equal(lineTokens.findTokenIndexAtOffset(10), 1);
|
||||
assert.equal(lineTokens.findTokenIndexAtOffset(11), 1);
|
||||
assert.equal(lineTokens.findTokenIndexAtOffset(12), 1);
|
||||
assert.equal(lineTokens.findTokenIndexAtOffset(13), 2);
|
||||
assert.equal(lineTokens.findTokenIndexAtOffset(14), 2);
|
||||
assert.equal(lineTokens.findTokenIndexAtOffset(15), 2);
|
||||
assert.equal(lineTokens.findTokenIndexAtOffset(16), 2);
|
||||
assert.equal(lineTokens.findTokenIndexAtOffset(17), 2);
|
||||
assert.equal(lineTokens.findTokenIndexAtOffset(18), 3);
|
||||
assert.equal(lineTokens.findTokenIndexAtOffset(19), 3);
|
||||
assert.equal(lineTokens.findTokenIndexAtOffset(20), 3);
|
||||
assert.equal(lineTokens.findTokenIndexAtOffset(21), 4);
|
||||
assert.equal(lineTokens.findTokenIndexAtOffset(22), 4);
|
||||
assert.equal(lineTokens.findTokenIndexAtOffset(23), 5);
|
||||
assert.equal(lineTokens.findTokenIndexAtOffset(24), 5);
|
||||
assert.equal(lineTokens.findTokenIndexAtOffset(25), 5);
|
||||
assert.equal(lineTokens.findTokenIndexAtOffset(26), 5);
|
||||
assert.equal(lineTokens.findTokenIndexAtOffset(27), 5);
|
||||
assert.equal(lineTokens.findTokenIndexAtOffset(28), 5);
|
||||
assert.equal(lineTokens.findTokenIndexAtOffset(29), 5);
|
||||
assert.equal(lineTokens.findTokenIndexAtOffset(30), 6);
|
||||
assert.equal(lineTokens.findTokenIndexAtOffset(31), 6);
|
||||
assert.equal(lineTokens.findTokenIndexAtOffset(32), 6);
|
||||
assert.equal(lineTokens.findTokenIndexAtOffset(33), 6);
|
||||
assert.equal(lineTokens.findTokenIndexAtOffset(34), 6);
|
||||
|
||||
assert.equal(lineTokens.findTokenAtOffset(7).startOffset, 6);
|
||||
assert.equal(lineTokens.findTokenAtOffset(7).endOffset, 13);
|
||||
assert.equal(lineTokens.findTokenAtOffset(7).foregroundId, 2);
|
||||
|
||||
assert.equal(lineTokens.findTokenAtOffset(30).startOffset, 30);
|
||||
assert.equal(lineTokens.findTokenAtOffset(30).endOffset, 33);
|
||||
assert.equal(lineTokens.findTokenAtOffset(30).foregroundId, 7);
|
||||
});
|
||||
|
||||
test('iterate forward', () => {
|
||||
const lineTokens = createTestLineTokens();
|
||||
|
||||
let token = lineTokens.firstToken();
|
||||
assert.equal(token.startOffset, 0);
|
||||
assert.equal(token.endOffset, 6);
|
||||
assert.equal(token.foregroundId, 1);
|
||||
|
||||
token = token.next();
|
||||
assert.equal(token.startOffset, 6);
|
||||
assert.equal(token.endOffset, 13);
|
||||
assert.equal(token.foregroundId, 2);
|
||||
|
||||
token = token.next();
|
||||
assert.equal(token.startOffset, 13);
|
||||
assert.equal(token.endOffset, 18);
|
||||
assert.equal(token.foregroundId, 3);
|
||||
|
||||
token = token.next();
|
||||
assert.equal(token.startOffset, 18);
|
||||
assert.equal(token.endOffset, 21);
|
||||
assert.equal(token.foregroundId, 4);
|
||||
|
||||
token = token.next();
|
||||
assert.equal(token.startOffset, 21);
|
||||
assert.equal(token.endOffset, 23);
|
||||
assert.equal(token.foregroundId, 5);
|
||||
|
||||
token = token.next();
|
||||
assert.equal(token.startOffset, 23);
|
||||
assert.equal(token.endOffset, 30);
|
||||
assert.equal(token.foregroundId, 6);
|
||||
|
||||
token = token.next();
|
||||
assert.equal(token.startOffset, 30);
|
||||
assert.equal(token.endOffset, 33);
|
||||
assert.equal(token.foregroundId, 7);
|
||||
|
||||
token = token.next();
|
||||
assert.equal(token, null);
|
||||
});
|
||||
|
||||
test('iterate backward', () => {
|
||||
const lineTokens = createTestLineTokens();
|
||||
|
||||
let token = lineTokens.lastToken();
|
||||
assert.equal(token.startOffset, 30);
|
||||
assert.equal(token.endOffset, 33);
|
||||
assert.equal(token.foregroundId, 7);
|
||||
|
||||
token = token.prev();
|
||||
assert.equal(token.startOffset, 23);
|
||||
assert.equal(token.endOffset, 30);
|
||||
assert.equal(token.foregroundId, 6);
|
||||
|
||||
token = token.prev();
|
||||
assert.equal(token.startOffset, 21);
|
||||
assert.equal(token.endOffset, 23);
|
||||
assert.equal(token.foregroundId, 5);
|
||||
|
||||
token = token.prev();
|
||||
assert.equal(token.startOffset, 18);
|
||||
assert.equal(token.endOffset, 21);
|
||||
assert.equal(token.foregroundId, 4);
|
||||
|
||||
token = token.prev();
|
||||
assert.equal(token.startOffset, 13);
|
||||
assert.equal(token.endOffset, 18);
|
||||
assert.equal(token.foregroundId, 3);
|
||||
|
||||
token = token.prev();
|
||||
assert.equal(token.startOffset, 6);
|
||||
assert.equal(token.endOffset, 13);
|
||||
assert.equal(token.foregroundId, 2);
|
||||
|
||||
token = token.prev();
|
||||
assert.equal(token.startOffset, 0);
|
||||
assert.equal(token.endOffset, 6);
|
||||
assert.equal(token.foregroundId, 1);
|
||||
|
||||
token = token.prev();
|
||||
assert.equal(token, null);
|
||||
});
|
||||
|
||||
interface ITestViewLineToken {
|
||||
endIndex: number;
|
||||
foreground: number;
|
||||
}
|
||||
|
||||
function assertViewLineTokens(actual: ViewLineToken[], expected: ITestViewLineToken[]): void {
|
||||
assert.deepEqual(actual.map(token => {
|
||||
return {
|
||||
endIndex: token.endIndex,
|
||||
foreground: token.getForeground()
|
||||
};
|
||||
}), expected);
|
||||
}
|
||||
|
||||
test('inflate', () => {
|
||||
const lineTokens = createTestLineTokens();
|
||||
assertViewLineTokens(lineTokens.inflate(), [
|
||||
{ endIndex: 6, foreground: 1 },
|
||||
{ endIndex: 13, foreground: 2 },
|
||||
{ endIndex: 18, foreground: 3 },
|
||||
{ endIndex: 21, foreground: 4 },
|
||||
{ endIndex: 23, foreground: 5 },
|
||||
{ endIndex: 30, foreground: 6 },
|
||||
{ endIndex: 33, foreground: 7 },
|
||||
]);
|
||||
});
|
||||
|
||||
test('sliceAndInflate', () => {
|
||||
const lineTokens = createTestLineTokens();
|
||||
assertViewLineTokens(lineTokens.sliceAndInflate(0, 33, 0), [
|
||||
{ endIndex: 6, foreground: 1 },
|
||||
{ endIndex: 13, foreground: 2 },
|
||||
{ endIndex: 18, foreground: 3 },
|
||||
{ endIndex: 21, foreground: 4 },
|
||||
{ endIndex: 23, foreground: 5 },
|
||||
{ endIndex: 30, foreground: 6 },
|
||||
{ endIndex: 33, foreground: 7 },
|
||||
]);
|
||||
|
||||
assertViewLineTokens(lineTokens.sliceAndInflate(0, 32, 0), [
|
||||
{ endIndex: 6, foreground: 1 },
|
||||
{ endIndex: 13, foreground: 2 },
|
||||
{ endIndex: 18, foreground: 3 },
|
||||
{ endIndex: 21, foreground: 4 },
|
||||
{ endIndex: 23, foreground: 5 },
|
||||
{ endIndex: 30, foreground: 6 },
|
||||
{ endIndex: 32, foreground: 7 },
|
||||
]);
|
||||
|
||||
assertViewLineTokens(lineTokens.sliceAndInflate(0, 30, 0), [
|
||||
{ endIndex: 6, foreground: 1 },
|
||||
{ endIndex: 13, foreground: 2 },
|
||||
{ endIndex: 18, foreground: 3 },
|
||||
{ endIndex: 21, foreground: 4 },
|
||||
{ endIndex: 23, foreground: 5 },
|
||||
{ endIndex: 30, foreground: 6 }
|
||||
]);
|
||||
|
||||
assertViewLineTokens(lineTokens.sliceAndInflate(0, 30, 1), [
|
||||
{ endIndex: 7, foreground: 1 },
|
||||
{ endIndex: 14, foreground: 2 },
|
||||
{ endIndex: 19, foreground: 3 },
|
||||
{ endIndex: 22, foreground: 4 },
|
||||
{ endIndex: 24, foreground: 5 },
|
||||
{ endIndex: 31, foreground: 6 }
|
||||
]);
|
||||
|
||||
assertViewLineTokens(lineTokens.sliceAndInflate(6, 18, 0), [
|
||||
{ endIndex: 7, foreground: 2 },
|
||||
{ endIndex: 12, foreground: 3 }
|
||||
]);
|
||||
|
||||
assertViewLineTokens(lineTokens.sliceAndInflate(7, 18, 0), [
|
||||
{ endIndex: 6, foreground: 2 },
|
||||
{ endIndex: 11, foreground: 3 }
|
||||
]);
|
||||
|
||||
assertViewLineTokens(lineTokens.sliceAndInflate(6, 17, 0), [
|
||||
{ endIndex: 7, foreground: 2 },
|
||||
{ endIndex: 11, foreground: 3 }
|
||||
]);
|
||||
|
||||
assertViewLineTokens(lineTokens.sliceAndInflate(6, 19, 0), [
|
||||
{ endIndex: 7, foreground: 2 },
|
||||
{ endIndex: 12, foreground: 3 },
|
||||
{ endIndex: 13, foreground: 4 },
|
||||
]);
|
||||
});
|
||||
});
|
||||
120
src/vs/editor/test/common/core/range.test.ts
Normal file
120
src/vs/editor/test/common/core/range.test.ts
Normal file
@@ -0,0 +1,120 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { Position } from 'vs/editor/common/core/position';
|
||||
|
||||
suite('Editor Core - Range', () => {
|
||||
test('empty range', () => {
|
||||
var s = new Range(1, 1, 1, 1);
|
||||
assert.equal(s.startLineNumber, 1);
|
||||
assert.equal(s.startColumn, 1);
|
||||
assert.equal(s.endLineNumber, 1);
|
||||
assert.equal(s.endColumn, 1);
|
||||
assert.equal(s.isEmpty(), true);
|
||||
});
|
||||
|
||||
test('swap start and stop same line', () => {
|
||||
var s = new Range(1, 2, 1, 1);
|
||||
assert.equal(s.startLineNumber, 1);
|
||||
assert.equal(s.startColumn, 1);
|
||||
assert.equal(s.endLineNumber, 1);
|
||||
assert.equal(s.endColumn, 2);
|
||||
assert.equal(s.isEmpty(), false);
|
||||
});
|
||||
|
||||
test('swap start and stop', () => {
|
||||
var s = new Range(2, 1, 1, 2);
|
||||
assert.equal(s.startLineNumber, 1);
|
||||
assert.equal(s.startColumn, 2);
|
||||
assert.equal(s.endLineNumber, 2);
|
||||
assert.equal(s.endColumn, 1);
|
||||
assert.equal(s.isEmpty(), false);
|
||||
});
|
||||
|
||||
test('no swap same line', () => {
|
||||
var s = new Range(1, 1, 1, 2);
|
||||
assert.equal(s.startLineNumber, 1);
|
||||
assert.equal(s.startColumn, 1);
|
||||
assert.equal(s.endLineNumber, 1);
|
||||
assert.equal(s.endColumn, 2);
|
||||
assert.equal(s.isEmpty(), false);
|
||||
});
|
||||
|
||||
test('no swap', () => {
|
||||
var s = new Range(1, 1, 2, 1);
|
||||
assert.equal(s.startLineNumber, 1);
|
||||
assert.equal(s.startColumn, 1);
|
||||
assert.equal(s.endLineNumber, 2);
|
||||
assert.equal(s.endColumn, 1);
|
||||
assert.equal(s.isEmpty(), false);
|
||||
});
|
||||
|
||||
test('compareRangesUsingEnds', () => {
|
||||
var a, b;
|
||||
|
||||
a = new Range(1, 1, 1, 3);
|
||||
b = new Range(1, 2, 1, 4);
|
||||
assert.ok(Range.compareRangesUsingEnds(a, b) < 0, 'a.start < b.start, a.end < b.end');
|
||||
|
||||
a = new Range(1, 1, 1, 3);
|
||||
b = new Range(1, 1, 1, 4);
|
||||
assert.ok(Range.compareRangesUsingEnds(a, b) < 0, 'a.start = b.start, a.end < b.end');
|
||||
|
||||
a = new Range(1, 2, 1, 3);
|
||||
b = new Range(1, 1, 1, 4);
|
||||
assert.ok(Range.compareRangesUsingEnds(a, b) < 0, 'a.start > b.start, a.end < b.end');
|
||||
|
||||
a = new Range(1, 1, 1, 4);
|
||||
b = new Range(1, 2, 1, 4);
|
||||
assert.ok(Range.compareRangesUsingEnds(a, b) < 0, 'a.start < b.start, a.end = b.end');
|
||||
|
||||
a = new Range(1, 1, 1, 4);
|
||||
b = new Range(1, 1, 1, 4);
|
||||
assert.ok(Range.compareRangesUsingEnds(a, b) === 0, 'a.start = b.start, a.end = b.end');
|
||||
|
||||
a = new Range(1, 2, 1, 4);
|
||||
b = new Range(1, 1, 1, 4);
|
||||
assert.ok(Range.compareRangesUsingEnds(a, b) > 0, 'a.start > b.start, a.end = b.end');
|
||||
|
||||
a = new Range(1, 1, 1, 5);
|
||||
b = new Range(1, 2, 1, 4);
|
||||
assert.ok(Range.compareRangesUsingEnds(a, b) > 0, 'a.start < b.start, a.end > b.end');
|
||||
|
||||
a = new Range(1, 1, 2, 4);
|
||||
b = new Range(1, 1, 1, 4);
|
||||
assert.ok(Range.compareRangesUsingEnds(a, b) > 0, 'a.start = b.start, a.end > b.end');
|
||||
|
||||
a = new Range(1, 1, 5, 1);
|
||||
b = new Range(1, 1, 1, 4);
|
||||
assert.ok(Range.compareRangesUsingEnds(a, b) > 0, 'a.start = b.start, a.end > b.end');
|
||||
});
|
||||
|
||||
test('containsPosition', () => {
|
||||
assert.equal(new Range(2, 2, 5, 10).containsPosition(new Position(1, 3)), false);
|
||||
assert.equal(new Range(2, 2, 5, 10).containsPosition(new Position(2, 1)), false);
|
||||
assert.equal(new Range(2, 2, 5, 10).containsPosition(new Position(2, 2)), true);
|
||||
assert.equal(new Range(2, 2, 5, 10).containsPosition(new Position(2, 3)), true);
|
||||
assert.equal(new Range(2, 2, 5, 10).containsPosition(new Position(3, 1)), true);
|
||||
assert.equal(new Range(2, 2, 5, 10).containsPosition(new Position(5, 9)), true);
|
||||
assert.equal(new Range(2, 2, 5, 10).containsPosition(new Position(5, 10)), true);
|
||||
assert.equal(new Range(2, 2, 5, 10).containsPosition(new Position(5, 11)), false);
|
||||
assert.equal(new Range(2, 2, 5, 10).containsPosition(new Position(6, 1)), false);
|
||||
});
|
||||
|
||||
test('containsRange', () => {
|
||||
assert.equal(new Range(2, 2, 5, 10).containsRange(new Range(1, 3, 2, 2)), false);
|
||||
assert.equal(new Range(2, 2, 5, 10).containsRange(new Range(2, 1, 2, 2)), false);
|
||||
assert.equal(new Range(2, 2, 5, 10).containsRange(new Range(2, 2, 5, 11)), false);
|
||||
assert.equal(new Range(2, 2, 5, 10).containsRange(new Range(2, 2, 6, 1)), false);
|
||||
assert.equal(new Range(2, 2, 5, 10).containsRange(new Range(5, 9, 6, 1)), false);
|
||||
assert.equal(new Range(2, 2, 5, 10).containsRange(new Range(5, 10, 6, 1)), false);
|
||||
assert.equal(new Range(2, 2, 5, 10).containsRange(new Range(2, 2, 5, 10)), true);
|
||||
assert.equal(new Range(2, 2, 5, 10).containsRange(new Range(2, 3, 5, 9)), true);
|
||||
assert.equal(new Range(2, 2, 5, 10).containsRange(new Range(3, 100, 4, 100)), true);
|
||||
});
|
||||
});
|
||||
677
src/vs/editor/test/common/diff/diffComputer.test.ts
Normal file
677
src/vs/editor/test/common/diff/diffComputer.test.ts
Normal file
@@ -0,0 +1,677 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { DiffComputer } from 'vs/editor/common/diff/diffComputer';
|
||||
import { IChange, ICharChange, ILineChange } from 'vs/editor/common/editorCommon';
|
||||
|
||||
function extractCharChangeRepresentation(change: ICharChange, expectedChange: ICharChange): ICharChange {
|
||||
var hasOriginal = expectedChange && expectedChange.originalStartLineNumber > 0;
|
||||
var hasModified = expectedChange && expectedChange.modifiedStartLineNumber > 0;
|
||||
return {
|
||||
originalStartLineNumber: hasOriginal ? change.originalStartLineNumber : 0,
|
||||
originalStartColumn: hasOriginal ? change.originalStartColumn : 0,
|
||||
originalEndLineNumber: hasOriginal ? change.originalEndLineNumber : 0,
|
||||
originalEndColumn: hasOriginal ? change.originalEndColumn : 0,
|
||||
|
||||
modifiedStartLineNumber: hasModified ? change.modifiedStartLineNumber : 0,
|
||||
modifiedStartColumn: hasModified ? change.modifiedStartColumn : 0,
|
||||
modifiedEndLineNumber: hasModified ? change.modifiedEndLineNumber : 0,
|
||||
modifiedEndColumn: hasModified ? change.modifiedEndColumn : 0,
|
||||
};
|
||||
}
|
||||
|
||||
function extractLineChangeRepresentation(change: ILineChange, expectedChange: ILineChange): IChange | ILineChange {
|
||||
if (change.charChanges) {
|
||||
let charChanges: ICharChange[] = [];
|
||||
for (let i = 0; i < change.charChanges.length; i++) {
|
||||
charChanges.push(
|
||||
extractCharChangeRepresentation(
|
||||
change.charChanges[i],
|
||||
expectedChange && expectedChange.charChanges && i < expectedChange.charChanges.length ? expectedChange.charChanges[i] : null
|
||||
)
|
||||
);
|
||||
}
|
||||
return {
|
||||
originalStartLineNumber: change.originalStartLineNumber,
|
||||
originalEndLineNumber: change.originalEndLineNumber,
|
||||
modifiedStartLineNumber: change.modifiedStartLineNumber,
|
||||
modifiedEndLineNumber: change.modifiedEndLineNumber,
|
||||
charChanges: charChanges
|
||||
};
|
||||
}
|
||||
return {
|
||||
originalStartLineNumber: change.originalStartLineNumber,
|
||||
originalEndLineNumber: change.originalEndLineNumber,
|
||||
modifiedStartLineNumber: change.modifiedStartLineNumber,
|
||||
modifiedEndLineNumber: change.modifiedEndLineNumber
|
||||
};
|
||||
}
|
||||
|
||||
function assertDiff(originalLines: string[], modifiedLines: string[], expectedChanges: IChange[], shouldPostProcessCharChanges: boolean = false, shouldIgnoreTrimWhitespace: boolean = false) {
|
||||
var diffComputer = new DiffComputer(originalLines, modifiedLines, {
|
||||
shouldPostProcessCharChanges: shouldPostProcessCharChanges || false,
|
||||
shouldIgnoreTrimWhitespace: shouldIgnoreTrimWhitespace || false,
|
||||
shouldConsiderTrimWhitespaceInEmptyCase: true,
|
||||
shouldMakePrettyDiff: true
|
||||
});
|
||||
var changes = diffComputer.computeDiff();
|
||||
|
||||
var extracted = [];
|
||||
for (var i = 0; i < changes.length; i++) {
|
||||
extracted.push(extractLineChangeRepresentation(changes[i], <ILineChange>(i < expectedChanges.length ? expectedChanges[i] : null)));
|
||||
}
|
||||
assert.deepEqual(extracted, expectedChanges);
|
||||
}
|
||||
|
||||
function createLineDeletion(startLineNumber: number, endLineNumber: number, modifiedLineNumber: number): IChange {
|
||||
return {
|
||||
originalStartLineNumber: startLineNumber,
|
||||
originalEndLineNumber: endLineNumber,
|
||||
modifiedStartLineNumber: modifiedLineNumber,
|
||||
modifiedEndLineNumber: 0
|
||||
};
|
||||
}
|
||||
|
||||
function createLineInsertion(startLineNumber: number, endLineNumber: number, originalLineNumber: number): IChange {
|
||||
return {
|
||||
originalStartLineNumber: originalLineNumber,
|
||||
originalEndLineNumber: 0,
|
||||
modifiedStartLineNumber: startLineNumber,
|
||||
modifiedEndLineNumber: endLineNumber
|
||||
};
|
||||
}
|
||||
|
||||
function createLineChange(originalStartLineNumber: number, originalEndLineNumber: number, modifiedStartLineNumber: number, modifiedEndLineNumber: number, charChanges: ICharChange[]): ILineChange {
|
||||
return {
|
||||
originalStartLineNumber: originalStartLineNumber,
|
||||
originalEndLineNumber: originalEndLineNumber,
|
||||
modifiedStartLineNumber: modifiedStartLineNumber,
|
||||
modifiedEndLineNumber: modifiedEndLineNumber,
|
||||
charChanges: charChanges
|
||||
};
|
||||
}
|
||||
|
||||
function createCharInsertion(startLineNumber: number, startColumn: number, endLineNumber: number, endColumn: number) {
|
||||
return {
|
||||
originalStartLineNumber: 0,
|
||||
originalStartColumn: 0,
|
||||
originalEndLineNumber: 0,
|
||||
originalEndColumn: 0,
|
||||
modifiedStartLineNumber: startLineNumber,
|
||||
modifiedStartColumn: startColumn,
|
||||
modifiedEndLineNumber: endLineNumber,
|
||||
modifiedEndColumn: endColumn
|
||||
};
|
||||
}
|
||||
|
||||
function createCharDeletion(startLineNumber: number, startColumn: number, endLineNumber: number, endColumn: number) {
|
||||
return {
|
||||
originalStartLineNumber: startLineNumber,
|
||||
originalStartColumn: startColumn,
|
||||
originalEndLineNumber: endLineNumber,
|
||||
originalEndColumn: endColumn,
|
||||
modifiedStartLineNumber: 0,
|
||||
modifiedStartColumn: 0,
|
||||
modifiedEndLineNumber: 0,
|
||||
modifiedEndColumn: 0
|
||||
};
|
||||
}
|
||||
|
||||
function createCharChange(
|
||||
originalStartLineNumber: number, originalStartColumn: number, originalEndLineNumber: number, originalEndColumn: number,
|
||||
modifiedStartLineNumber: number, modifiedStartColumn: number, modifiedEndLineNumber: number, modifiedEndColumn: number
|
||||
) {
|
||||
return {
|
||||
originalStartLineNumber: originalStartLineNumber,
|
||||
originalStartColumn: originalStartColumn,
|
||||
originalEndLineNumber: originalEndLineNumber,
|
||||
originalEndColumn: originalEndColumn,
|
||||
modifiedStartLineNumber: modifiedStartLineNumber,
|
||||
modifiedStartColumn: modifiedStartColumn,
|
||||
modifiedEndLineNumber: modifiedEndLineNumber,
|
||||
modifiedEndColumn: modifiedEndColumn
|
||||
};
|
||||
}
|
||||
|
||||
suite('Editor Diff - DiffComputer', () => {
|
||||
|
||||
// ---- insertions
|
||||
|
||||
test('one inserted line below', () => {
|
||||
var original = ['line'];
|
||||
var modified = ['line', 'new line'];
|
||||
var expected = [createLineInsertion(2, 2, 1)];
|
||||
assertDiff(original, modified, expected);
|
||||
});
|
||||
|
||||
test('two inserted lines below', () => {
|
||||
var original = ['line'];
|
||||
var modified = ['line', 'new line', 'another new line'];
|
||||
var expected = [createLineInsertion(2, 3, 1)];
|
||||
assertDiff(original, modified, expected);
|
||||
});
|
||||
|
||||
test('one inserted line above', () => {
|
||||
var original = ['line'];
|
||||
var modified = ['new line', 'line'];
|
||||
var expected = [createLineInsertion(1, 1, 0)];
|
||||
assertDiff(original, modified, expected);
|
||||
});
|
||||
|
||||
test('two inserted lines above', () => {
|
||||
var original = ['line'];
|
||||
var modified = ['new line', 'another new line', 'line'];
|
||||
var expected = [createLineInsertion(1, 2, 0)];
|
||||
assertDiff(original, modified, expected);
|
||||
});
|
||||
|
||||
test('one inserted line in middle', () => {
|
||||
var original = ['line1', 'line2', 'line3', 'line4'];
|
||||
var modified = ['line1', 'line2', 'new line', 'line3', 'line4'];
|
||||
var expected = [createLineInsertion(3, 3, 2)];
|
||||
assertDiff(original, modified, expected);
|
||||
});
|
||||
|
||||
test('two inserted lines in middle', () => {
|
||||
var original = ['line1', 'line2', 'line3', 'line4'];
|
||||
var modified = ['line1', 'line2', 'new line', 'another new line', 'line3', 'line4'];
|
||||
var expected = [createLineInsertion(3, 4, 2)];
|
||||
assertDiff(original, modified, expected);
|
||||
});
|
||||
|
||||
test('two inserted lines in middle interrupted', () => {
|
||||
var original = ['line1', 'line2', 'line3', 'line4'];
|
||||
var modified = ['line1', 'line2', 'new line', 'line3', 'another new line', 'line4'];
|
||||
var expected = [createLineInsertion(3, 3, 2), createLineInsertion(5, 5, 3)];
|
||||
assertDiff(original, modified, expected);
|
||||
});
|
||||
|
||||
// ---- deletions
|
||||
|
||||
test('one deleted line below', () => {
|
||||
var original = ['line', 'new line'];
|
||||
var modified = ['line'];
|
||||
var expected = [createLineDeletion(2, 2, 1)];
|
||||
assertDiff(original, modified, expected);
|
||||
});
|
||||
|
||||
test('two deleted lines below', () => {
|
||||
var original = ['line', 'new line', 'another new line'];
|
||||
var modified = ['line'];
|
||||
var expected = [createLineDeletion(2, 3, 1)];
|
||||
assertDiff(original, modified, expected);
|
||||
});
|
||||
|
||||
test('one deleted lines above', () => {
|
||||
var original = ['new line', 'line'];
|
||||
var modified = ['line'];
|
||||
var expected = [createLineDeletion(1, 1, 0)];
|
||||
assertDiff(original, modified, expected);
|
||||
});
|
||||
|
||||
test('two deleted lines above', () => {
|
||||
var original = ['new line', 'another new line', 'line'];
|
||||
var modified = ['line'];
|
||||
var expected = [createLineDeletion(1, 2, 0)];
|
||||
assertDiff(original, modified, expected);
|
||||
});
|
||||
|
||||
test('one deleted line in middle', () => {
|
||||
var original = ['line1', 'line2', 'new line', 'line3', 'line4'];
|
||||
var modified = ['line1', 'line2', 'line3', 'line4'];
|
||||
var expected = [createLineDeletion(3, 3, 2)];
|
||||
assertDiff(original, modified, expected);
|
||||
});
|
||||
|
||||
test('two deleted lines in middle', () => {
|
||||
var original = ['line1', 'line2', 'new line', 'another new line', 'line3', 'line4'];
|
||||
var modified = ['line1', 'line2', 'line3', 'line4'];
|
||||
var expected = [createLineDeletion(3, 4, 2)];
|
||||
assertDiff(original, modified, expected);
|
||||
});
|
||||
|
||||
test('two deleted lines in middle interrupted', () => {
|
||||
var original = ['line1', 'line2', 'new line', 'line3', 'another new line', 'line4'];
|
||||
var modified = ['line1', 'line2', 'line3', 'line4'];
|
||||
var expected = [createLineDeletion(3, 3, 2), createLineDeletion(5, 5, 3)];
|
||||
assertDiff(original, modified, expected);
|
||||
});
|
||||
|
||||
// ---- changes
|
||||
|
||||
test('one line changed: chars inserted at the end', () => {
|
||||
var original = ['line'];
|
||||
var modified = ['line changed'];
|
||||
var expected = [
|
||||
createLineChange(1, 1, 1, 1, [
|
||||
createCharInsertion(1, 5, 1, 13)
|
||||
])
|
||||
];
|
||||
assertDiff(original, modified, expected);
|
||||
});
|
||||
|
||||
test('one line changed: chars inserted at the beginning', () => {
|
||||
var original = ['line'];
|
||||
var modified = ['my line'];
|
||||
var expected = [
|
||||
createLineChange(1, 1, 1, 1, [
|
||||
createCharInsertion(1, 1, 1, 4)
|
||||
])
|
||||
];
|
||||
assertDiff(original, modified, expected);
|
||||
});
|
||||
|
||||
test('one line changed: chars inserted in the middle', () => {
|
||||
var original = ['abba'];
|
||||
var modified = ['abzzba'];
|
||||
var expected = [
|
||||
createLineChange(1, 1, 1, 1, [
|
||||
createCharInsertion(1, 3, 1, 5)
|
||||
])
|
||||
];
|
||||
assertDiff(original, modified, expected);
|
||||
});
|
||||
|
||||
test('one line changed: chars inserted in the middle (two spots)', () => {
|
||||
var original = ['abba'];
|
||||
var modified = ['abzzbzza'];
|
||||
var expected = [
|
||||
createLineChange(1, 1, 1, 1, [
|
||||
createCharInsertion(1, 3, 1, 5),
|
||||
createCharInsertion(1, 6, 1, 8)
|
||||
])
|
||||
];
|
||||
assertDiff(original, modified, expected);
|
||||
});
|
||||
|
||||
test('one line changed: chars deleted 1', () => {
|
||||
var original = ['abcdefg'];
|
||||
var modified = ['abcfg'];
|
||||
var expected = [
|
||||
createLineChange(1, 1, 1, 1, [
|
||||
createCharDeletion(1, 4, 1, 6)
|
||||
])
|
||||
];
|
||||
assertDiff(original, modified, expected);
|
||||
});
|
||||
|
||||
test('one line changed: chars deleted 2', () => {
|
||||
var original = ['abcdefg'];
|
||||
var modified = ['acfg'];
|
||||
var expected = [
|
||||
createLineChange(1, 1, 1, 1, [
|
||||
createCharDeletion(1, 2, 1, 3),
|
||||
createCharDeletion(1, 4, 1, 6)
|
||||
])
|
||||
];
|
||||
assertDiff(original, modified, expected);
|
||||
});
|
||||
|
||||
test('two lines changed 1', () => {
|
||||
var original = ['abcd', 'efgh'];
|
||||
var modified = ['abcz'];
|
||||
var expected = [
|
||||
createLineChange(1, 2, 1, 1, [
|
||||
createCharChange(1, 4, 2, 5, 1, 4, 1, 5)
|
||||
])
|
||||
];
|
||||
assertDiff(original, modified, expected);
|
||||
});
|
||||
|
||||
test('two lines changed 2', () => {
|
||||
var original = ['foo', 'abcd', 'efgh', 'BAR'];
|
||||
var modified = ['foo', 'abcz', 'BAR'];
|
||||
var expected = [
|
||||
createLineChange(2, 3, 2, 2, [
|
||||
createCharChange(2, 4, 3, 5, 2, 4, 2, 5)
|
||||
])
|
||||
];
|
||||
assertDiff(original, modified, expected);
|
||||
});
|
||||
|
||||
test('two lines changed 3', () => {
|
||||
var original = ['foo', 'abcd', 'efgh', 'BAR'];
|
||||
var modified = ['foo', 'abcz', 'zzzzefgh', 'BAR'];
|
||||
var expected = [
|
||||
createLineChange(2, 3, 2, 3, [
|
||||
createCharChange(2, 4, 2, 5, 2, 4, 3, 5)
|
||||
])
|
||||
];
|
||||
assertDiff(original, modified, expected);
|
||||
});
|
||||
|
||||
test('three lines changed', () => {
|
||||
var original = ['foo', 'abcd', 'efgh', 'BAR'];
|
||||
var modified = ['foo', 'zzzefgh', 'xxx', 'BAR'];
|
||||
var expected = [
|
||||
createLineChange(2, 3, 2, 3, [
|
||||
createCharChange(2, 1, 2, 5, 2, 1, 2, 4),
|
||||
createCharInsertion(3, 1, 3, 4)
|
||||
])
|
||||
];
|
||||
assertDiff(original, modified, expected);
|
||||
});
|
||||
|
||||
test('big change part 1', () => {
|
||||
var original = ['foo', 'abcd', 'efgh', 'BAR'];
|
||||
var modified = ['hello', 'foo', 'zzzefgh', 'xxx', 'BAR'];
|
||||
var expected = [
|
||||
createLineInsertion(1, 1, 0),
|
||||
createLineChange(2, 3, 3, 4, [
|
||||
createCharChange(2, 1, 2, 5, 3, 1, 3, 4),
|
||||
createCharInsertion(4, 1, 4, 4)
|
||||
])
|
||||
];
|
||||
assertDiff(original, modified, expected);
|
||||
});
|
||||
|
||||
test('big change part 2', () => {
|
||||
var original = ['foo', 'abcd', 'efgh', 'BAR', 'RAB'];
|
||||
var modified = ['hello', 'foo', 'zzzefgh', 'xxx', 'BAR'];
|
||||
var expected = [
|
||||
createLineInsertion(1, 1, 0),
|
||||
createLineChange(2, 3, 3, 4, [
|
||||
createCharChange(2, 1, 2, 5, 3, 1, 3, 4),
|
||||
createCharInsertion(4, 1, 4, 4)
|
||||
]),
|
||||
createLineDeletion(5, 5, 5)
|
||||
];
|
||||
assertDiff(original, modified, expected);
|
||||
});
|
||||
|
||||
test('char change postprocessing merges', () => {
|
||||
var original = ['abba'];
|
||||
var modified = ['azzzbzzzbzzza'];
|
||||
var expected = [
|
||||
createLineChange(1, 1, 1, 1, [
|
||||
createCharChange(1, 2, 1, 4, 1, 2, 1, 13)
|
||||
])
|
||||
];
|
||||
assertDiff(original, modified, expected, true);
|
||||
});
|
||||
|
||||
test('ignore trim whitespace', () => {
|
||||
var original = ['\t\t foo ', 'abcd', 'efgh', '\t\t BAR\t\t'];
|
||||
var modified = [' hello\t', '\t foo \t', 'zzzefgh', 'xxx', ' BAR \t'];
|
||||
var expected = [
|
||||
createLineInsertion(1, 1, 0),
|
||||
createLineChange(2, 3, 3, 4, [
|
||||
createCharChange(2, 1, 2, 5, 3, 1, 3, 4),
|
||||
createCharInsertion(4, 1, 4, 4)
|
||||
])
|
||||
];
|
||||
assertDiff(original, modified, expected, false, true);
|
||||
});
|
||||
|
||||
test('issue #12122 r.hasOwnProperty is not a function', () => {
|
||||
var original = ['hasOwnProperty'];
|
||||
var modified = ['hasOwnProperty', 'and another line'];
|
||||
var expected = [
|
||||
createLineInsertion(2, 2, 1)
|
||||
];
|
||||
assertDiff(original, modified, expected);
|
||||
});
|
||||
|
||||
test('empty diff 1', () => {
|
||||
var original = [''];
|
||||
var modified = ['something'];
|
||||
var expected = [
|
||||
createLineChange(1, 1, 1, 1, [
|
||||
createCharChange(0, 0, 0, 0, 0, 0, 0, 0)
|
||||
])
|
||||
];
|
||||
assertDiff(original, modified, expected, false, true);
|
||||
});
|
||||
|
||||
test('empty diff 2', () => {
|
||||
var original = [''];
|
||||
var modified = ['something', 'something else'];
|
||||
var expected = [
|
||||
createLineChange(1, 1, 1, 2, [
|
||||
createCharChange(0, 0, 0, 0, 0, 0, 0, 0)
|
||||
])
|
||||
];
|
||||
assertDiff(original, modified, expected, false, true);
|
||||
});
|
||||
|
||||
test('empty diff 3', () => {
|
||||
var original = ['something', 'something else'];
|
||||
var modified = [''];
|
||||
var expected = [
|
||||
createLineChange(1, 2, 1, 1, [
|
||||
createCharChange(0, 0, 0, 0, 0, 0, 0, 0)
|
||||
])
|
||||
];
|
||||
assertDiff(original, modified, expected, false, true);
|
||||
});
|
||||
|
||||
test('empty diff 4', () => {
|
||||
var original = ['something'];
|
||||
var modified = [''];
|
||||
var expected = [
|
||||
createLineChange(1, 1, 1, 1, [
|
||||
createCharChange(0, 0, 0, 0, 0, 0, 0, 0)
|
||||
])
|
||||
];
|
||||
assertDiff(original, modified, expected, false, true);
|
||||
});
|
||||
|
||||
test('pretty diff 1', () => {
|
||||
var original = [
|
||||
'suite(function () {',
|
||||
' test1() {',
|
||||
' assert.ok(true);',
|
||||
' }',
|
||||
'',
|
||||
' test2() {',
|
||||
' assert.ok(true);',
|
||||
' }',
|
||||
'});',
|
||||
'',
|
||||
];
|
||||
var modified = [
|
||||
'// An insertion',
|
||||
'suite(function () {',
|
||||
' test1() {',
|
||||
' assert.ok(true);',
|
||||
' }',
|
||||
'',
|
||||
' test2() {',
|
||||
' assert.ok(true);',
|
||||
' }',
|
||||
'',
|
||||
' test3() {',
|
||||
' assert.ok(true);',
|
||||
' }',
|
||||
'});',
|
||||
'',
|
||||
];
|
||||
var expected = [
|
||||
createLineInsertion(1, 1, 0),
|
||||
createLineInsertion(10, 13, 8)
|
||||
];
|
||||
assertDiff(original, modified, expected, false, true);
|
||||
});
|
||||
|
||||
test('pretty diff 2', () => {
|
||||
var original = [
|
||||
'// Just a comment',
|
||||
'',
|
||||
'function compute(a, b, c, d) {',
|
||||
' if (a) {',
|
||||
' if (b) {',
|
||||
' if (c) {',
|
||||
' return 5;',
|
||||
' }',
|
||||
' }',
|
||||
' // These next lines will be deleted',
|
||||
' if (d) {',
|
||||
' return -1;',
|
||||
' }',
|
||||
' return 0;',
|
||||
' }',
|
||||
'}',
|
||||
];
|
||||
var modified = [
|
||||
'// Here is an inserted line',
|
||||
'// and another inserted line',
|
||||
'// and another one',
|
||||
'// Just a comment',
|
||||
'',
|
||||
'function compute(a, b, c, d) {',
|
||||
' if (a) {',
|
||||
' if (b) {',
|
||||
' if (c) {',
|
||||
' return 5;',
|
||||
' }',
|
||||
' }',
|
||||
' return 0;',
|
||||
' }',
|
||||
'}',
|
||||
];
|
||||
var expected = [
|
||||
createLineInsertion(1, 3, 0),
|
||||
createLineDeletion(10, 13, 12),
|
||||
];
|
||||
assertDiff(original, modified, expected, false, true);
|
||||
});
|
||||
|
||||
test('pretty diff 3', () => {
|
||||
var original = [
|
||||
'class A {',
|
||||
' /**',
|
||||
' * m1',
|
||||
' */',
|
||||
' method1() {}',
|
||||
'',
|
||||
' /**',
|
||||
' * m3',
|
||||
' */',
|
||||
' method3() {}',
|
||||
'}',
|
||||
];
|
||||
var modified = [
|
||||
'class A {',
|
||||
' /**',
|
||||
' * m1',
|
||||
' */',
|
||||
' method1() {}',
|
||||
'',
|
||||
' /**',
|
||||
' * m2',
|
||||
' */',
|
||||
' method2() {}',
|
||||
'',
|
||||
' /**',
|
||||
' * m3',
|
||||
' */',
|
||||
' method3() {}',
|
||||
'}',
|
||||
];
|
||||
var expected = [
|
||||
createLineInsertion(7, 11, 6)
|
||||
];
|
||||
assertDiff(original, modified, expected, false, true);
|
||||
});
|
||||
|
||||
test('issue #23636', () => {
|
||||
let original = [
|
||||
'if(!TextDrawLoad[playerid])',
|
||||
'{',
|
||||
'',
|
||||
' TextDrawHideForPlayer(playerid,TD_AppleJob[3]);',
|
||||
' TextDrawHideForPlayer(playerid,TD_AppleJob[4]);',
|
||||
' if(!AppleJobTreesType[AppleJobTreesPlayerNum[playerid]])',
|
||||
' {',
|
||||
' for(new i=0;i<10;i++) if(StatusTD_AppleJobApples[playerid][i]) TextDrawHideForPlayer(playerid,TD_AppleJob[5+i]);',
|
||||
' }',
|
||||
' else',
|
||||
' {',
|
||||
' for(new i=0;i<10;i++) if(StatusTD_AppleJobApples[playerid][i]) TextDrawHideForPlayer(playerid,TD_AppleJob[15+i]);',
|
||||
' }',
|
||||
'}',
|
||||
'else',
|
||||
'{',
|
||||
' TextDrawHideForPlayer(playerid,TD_AppleJob[3]);',
|
||||
' TextDrawHideForPlayer(playerid,TD_AppleJob[27]);',
|
||||
' if(!AppleJobTreesType[AppleJobTreesPlayerNum[playerid]])',
|
||||
' {',
|
||||
' for(new i=0;i<10;i++) if(StatusTD_AppleJobApples[playerid][i]) TextDrawHideForPlayer(playerid,TD_AppleJob[28+i]);',
|
||||
' }',
|
||||
' else',
|
||||
' {',
|
||||
' for(new i=0;i<10;i++) if(StatusTD_AppleJobApples[playerid][i]) TextDrawHideForPlayer(playerid,TD_AppleJob[38+i]);',
|
||||
' }',
|
||||
'}',
|
||||
];
|
||||
let modified = [
|
||||
' if(!TextDrawLoad[playerid])',
|
||||
' {',
|
||||
' ',
|
||||
' TextDrawHideForPlayer(playerid,TD_AppleJob[3]);',
|
||||
' TextDrawHideForPlayer(playerid,TD_AppleJob[4]);',
|
||||
' if(!AppleJobTreesType[AppleJobTreesPlayerNum[playerid]])',
|
||||
' {',
|
||||
' for(new i=0;i<10;i++) if(StatusTD_AppleJobApples[playerid][i]) TextDrawHideForPlayer(playerid,TD_AppleJob[5+i]);',
|
||||
' }',
|
||||
' else',
|
||||
' {',
|
||||
' for(new i=0;i<10;i++) if(StatusTD_AppleJobApples[playerid][i]) TextDrawHideForPlayer(playerid,TD_AppleJob[15+i]);',
|
||||
' }',
|
||||
' }',
|
||||
' else',
|
||||
' {',
|
||||
' TextDrawHideForPlayer(playerid,TD_AppleJob[3]);',
|
||||
' TextDrawHideForPlayer(playerid,TD_AppleJob[27]);',
|
||||
' if(!AppleJobTreesType[AppleJobTreesPlayerNum[playerid]])',
|
||||
' {',
|
||||
' for(new i=0;i<10;i++) if(StatusTD_AppleJobApples[playerid][i]) TextDrawHideForPlayer(playerid,TD_AppleJob[28+i]);',
|
||||
' }',
|
||||
' else',
|
||||
' {',
|
||||
' for(new i=0;i<10;i++) if(StatusTD_AppleJobApples[playerid][i]) TextDrawHideForPlayer(playerid,TD_AppleJob[38+i]);',
|
||||
' }',
|
||||
' }',
|
||||
];
|
||||
var expected = [
|
||||
createLineChange(
|
||||
1, 27, 1, 27,
|
||||
[
|
||||
createCharChange(1, 1, 1, 1, 1, 1, 1, 2),
|
||||
createCharChange(2, 1, 2, 1, 2, 1, 2, 2),
|
||||
createCharChange(3, 1, 3, 1, 3, 1, 3, 2),
|
||||
createCharChange(4, 1, 4, 1, 4, 1, 4, 2),
|
||||
createCharChange(5, 1, 5, 1, 5, 1, 5, 2),
|
||||
createCharChange(6, 1, 6, 1, 6, 1, 6, 2),
|
||||
createCharChange(7, 1, 7, 1, 7, 1, 7, 2),
|
||||
createCharChange(8, 1, 8, 1, 8, 1, 8, 2),
|
||||
createCharChange(9, 1, 9, 1, 9, 1, 9, 2),
|
||||
createCharChange(10, 1, 10, 1, 10, 1, 10, 2),
|
||||
createCharChange(11, 1, 11, 1, 11, 1, 11, 2),
|
||||
createCharChange(12, 1, 12, 1, 12, 1, 12, 2),
|
||||
createCharChange(13, 1, 13, 1, 13, 1, 13, 2),
|
||||
createCharChange(14, 1, 14, 1, 14, 1, 14, 2),
|
||||
createCharChange(15, 1, 15, 1, 15, 1, 15, 2),
|
||||
createCharChange(16, 1, 16, 1, 16, 1, 16, 2),
|
||||
createCharChange(17, 1, 17, 1, 17, 1, 17, 2),
|
||||
createCharChange(18, 1, 18, 1, 18, 1, 18, 2),
|
||||
createCharChange(19, 1, 19, 1, 19, 1, 19, 2),
|
||||
createCharChange(20, 1, 20, 1, 20, 1, 20, 2),
|
||||
createCharChange(21, 1, 21, 1, 21, 1, 21, 2),
|
||||
createCharChange(22, 1, 22, 1, 22, 1, 22, 2),
|
||||
createCharChange(23, 1, 23, 1, 23, 1, 23, 2),
|
||||
createCharChange(24, 1, 24, 1, 24, 1, 24, 2),
|
||||
createCharChange(25, 1, 25, 1, 25, 1, 25, 2),
|
||||
createCharChange(26, 1, 26, 1, 26, 1, 26, 2),
|
||||
createCharChange(27, 1, 27, 1, 27, 1, 27, 2),
|
||||
]
|
||||
)
|
||||
// createLineInsertion(7, 11, 6)
|
||||
];
|
||||
assertDiff(original, modified, expected, true, false);
|
||||
});
|
||||
});
|
||||
13
src/vs/editor/test/common/editorTestUtils.ts
Normal file
13
src/vs/editor/test/common/editorTestUtils.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { Model } from 'vs/editor/common/model/model';
|
||||
|
||||
export function withEditorModel(text: string[], callback: (model: Model) => void): void {
|
||||
var model = Model.createFromString(text.join('\n'));
|
||||
callback(model);
|
||||
model.dispose();
|
||||
}
|
||||
111
src/vs/editor/test/common/mocks/mockCodeEditor.ts
Normal file
111
src/vs/editor/test/common/mocks/mockCodeEditor.ts
Normal file
@@ -0,0 +1,111 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
|
||||
import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
|
||||
import { IContextKeyService, IContextKeyServiceTarget } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { MockContextKeyService } from 'vs/platform/keybinding/test/common/mockKeybindingService';
|
||||
import { CommonCodeEditor } from 'vs/editor/common/commonCodeEditor';
|
||||
import { CommonEditorConfiguration } from 'vs/editor/common/config/commonEditorConfig';
|
||||
import { Cursor } from 'vs/editor/common/controller/cursor';
|
||||
import * as editorCommon from 'vs/editor/common/editorCommon';
|
||||
import { Model } from 'vs/editor/common/model/model';
|
||||
import { TestConfiguration } from 'vs/editor/test/common/mocks/testConfiguration';
|
||||
import * as editorOptions from 'vs/editor/common/config/editorOptions';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
|
||||
export class MockCodeEditor extends CommonCodeEditor {
|
||||
protected _createConfiguration(options: editorOptions.IEditorOptions): CommonEditorConfiguration {
|
||||
return new TestConfiguration(options);
|
||||
}
|
||||
|
||||
public layout(dimension?: editorCommon.IDimension): void { }
|
||||
|
||||
public focus(): void { }
|
||||
public isFocused(): boolean { return true; }
|
||||
public hasWidgetFocus(): boolean { return true; };
|
||||
|
||||
protected _enableEmptySelectionClipboard(): boolean { return false; }
|
||||
protected _scheduleAtNextAnimationFrame(callback: () => void): IDisposable { throw new Error('Notimplemented'); }
|
||||
protected _createView(): void { }
|
||||
|
||||
protected _registerDecorationType(key: string, options: editorCommon.IDecorationRenderOptions, parentTypeKey?: string): void { throw new Error('NotImplemented'); }
|
||||
protected _removeDecorationType(key: string): void { throw new Error('NotImplemented'); }
|
||||
protected _resolveDecorationOptions(typeKey: string, writable: boolean): editorCommon.IModelDecorationOptions { throw new Error('NotImplemented'); }
|
||||
|
||||
// --- test utils
|
||||
getCursor(): Cursor {
|
||||
return this.cursor;
|
||||
}
|
||||
|
||||
public registerAndInstantiateContribution<T extends editorCommon.IEditorContribution>(ctor: any): T {
|
||||
let r = <T>this._instantiationService.createInstance(ctor, this);
|
||||
this._contributions[r.getId()] = r;
|
||||
return r;
|
||||
}
|
||||
|
||||
public dispose() {
|
||||
super.dispose();
|
||||
if (this.model) {
|
||||
this.model.dispose();
|
||||
}
|
||||
this._contextKeyService.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
export class MockScopeLocation implements IContextKeyServiceTarget {
|
||||
parentElement: IContextKeyServiceTarget = null;
|
||||
setAttribute(attr: string, value: string): void { }
|
||||
removeAttribute(attr: string): void { }
|
||||
hasAttribute(attr: string): boolean { return false; }
|
||||
getAttribute(attr: string): string { return undefined; }
|
||||
}
|
||||
|
||||
export interface MockCodeEditorCreationOptions extends editorOptions.IEditorOptions {
|
||||
/**
|
||||
* The initial model associated with this code editor.
|
||||
*/
|
||||
model?: editorCommon.IModel;
|
||||
serviceCollection?: ServiceCollection;
|
||||
}
|
||||
|
||||
export function withMockCodeEditor(text: string[], options: MockCodeEditorCreationOptions, callback: (editor: MockCodeEditor, cursor: Cursor) => void): void {
|
||||
// create a model if necessary and remember it in order to dispose it.
|
||||
let modelToDispose: Model = null;
|
||||
if (!options.model) {
|
||||
modelToDispose = Model.createFromString(text.join('\n'));
|
||||
options.model = modelToDispose;
|
||||
}
|
||||
|
||||
let editor = <MockCodeEditor>_mockCodeEditor(options);
|
||||
callback(editor, editor.getCursor());
|
||||
|
||||
if (modelToDispose) {
|
||||
modelToDispose.dispose();
|
||||
}
|
||||
editor.dispose();
|
||||
}
|
||||
|
||||
export function mockCodeEditor(text: string[], options: MockCodeEditorCreationOptions): CommonCodeEditor {
|
||||
// TODO: who owns this model now?
|
||||
if (!options.model) {
|
||||
options.model = Model.createFromString(text.join('\n'));
|
||||
}
|
||||
return _mockCodeEditor(options);
|
||||
}
|
||||
|
||||
function _mockCodeEditor(options: MockCodeEditorCreationOptions): CommonCodeEditor {
|
||||
|
||||
let contextKeyService = new MockContextKeyService();
|
||||
|
||||
let services = options.serviceCollection || new ServiceCollection();
|
||||
services.set(IContextKeyService, contextKeyService);
|
||||
let instantiationService = new InstantiationService(services);
|
||||
|
||||
let editor = new MockCodeEditor(new MockScopeLocation(), options, instantiationService, contextKeyService);
|
||||
editor.setModel(options.model);
|
||||
return editor;
|
||||
}
|
||||
14
src/vs/editor/test/common/mocks/mockCodeEditorService.ts
Normal file
14
src/vs/editor/test/common/mocks/mockCodeEditorService.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { IDecorationRenderOptions, IModelDecorationOptions } from 'vs/editor/common/editorCommon';
|
||||
import { AbstractCodeEditorService } from 'vs/editor/common/services/abstractCodeEditorService';
|
||||
|
||||
export class MockCodeEditorService extends AbstractCodeEditorService {
|
||||
public registerDecorationType(key: string, options: IDecorationRenderOptions, parentTypeKey?: string): void { }
|
||||
public removeDecorationType(key: string): void { }
|
||||
public resolveDecorationOptions(decorationTypeKey: string, writable: boolean): IModelDecorationOptions { return null; }
|
||||
}
|
||||
25
src/vs/editor/test/common/mocks/mockMode.ts
Normal file
25
src/vs/editor/test/common/mocks/mockMode.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { IMode, LanguageIdentifier } from 'vs/editor/common/modes';
|
||||
|
||||
export class MockMode extends Disposable implements IMode {
|
||||
private _languageIdentifier: LanguageIdentifier;
|
||||
|
||||
constructor(languageIdentifier: LanguageIdentifier) {
|
||||
super();
|
||||
this._languageIdentifier = languageIdentifier;
|
||||
}
|
||||
|
||||
public getId(): string {
|
||||
return this._languageIdentifier.language;
|
||||
}
|
||||
|
||||
public getLanguageIdentifier(): LanguageIdentifier {
|
||||
return this._languageIdentifier;
|
||||
}
|
||||
}
|
||||
46
src/vs/editor/test/common/mocks/testConfiguration.ts
Normal file
46
src/vs/editor/test/common/mocks/testConfiguration.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { CommonEditorConfiguration, IEnvConfiguration } from 'vs/editor/common/config/commonEditorConfig';
|
||||
import { IEditorOptions } from 'vs/editor/common/config/editorOptions';
|
||||
import { FontInfo, BareFontInfo } from 'vs/editor/common/config/fontInfo';
|
||||
import { AccessibilitySupport } from 'vs/base/common/platform';
|
||||
|
||||
export class TestConfiguration extends CommonEditorConfiguration {
|
||||
|
||||
constructor(opts: IEditorOptions) {
|
||||
super(opts);
|
||||
this._recomputeOptions();
|
||||
}
|
||||
|
||||
protected _getEnvConfiguration(): IEnvConfiguration {
|
||||
return {
|
||||
extraEditorClassName: '',
|
||||
outerWidth: 100,
|
||||
outerHeight: 100,
|
||||
emptySelectionClipboard: true,
|
||||
pixelRatio: 1,
|
||||
zoomLevel: 0,
|
||||
accessibilitySupport: AccessibilitySupport.Unknown
|
||||
};
|
||||
}
|
||||
|
||||
protected readConfiguration(styling: BareFontInfo): FontInfo {
|
||||
return new FontInfo({
|
||||
zoomLevel: 0,
|
||||
fontFamily: 'mockFont',
|
||||
fontWeight: 'normal',
|
||||
fontSize: 14,
|
||||
lineHeight: 19,
|
||||
letterSpacing: 1.5,
|
||||
isMonospace: true,
|
||||
typicalHalfwidthCharacterWidth: 10,
|
||||
typicalFullwidthCharacterWidth: 20,
|
||||
spaceWidth: 10,
|
||||
maxDigitWidth: 10,
|
||||
}, true);
|
||||
}
|
||||
}
|
||||
1835
src/vs/editor/test/common/model/editableTextModel.test.ts
Normal file
1835
src/vs/editor/test/common/model/editableTextModel.test.ts
Normal file
File diff suppressed because it is too large
Load Diff
300
src/vs/editor/test/common/model/editableTextModelAuto.test.ts
Normal file
300
src/vs/editor/test/common/model/editableTextModelAuto.test.ts
Normal file
@@ -0,0 +1,300 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { Position } from 'vs/editor/common/core/position';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { IIdentifiedSingleEditOperation } from 'vs/editor/common/editorCommon';
|
||||
import { testApplyEditsWithSyncedModels } from 'vs/editor/test/common/model/editableTextModelTestUtils';
|
||||
import { CharCode } from 'vs/base/common/charCode';
|
||||
|
||||
const GENERATE_TESTS = false;
|
||||
|
||||
suite('EditorModel Auto Tests', () => {
|
||||
function editOp(startLineNumber: number, startColumn: number, endLineNumber: number, endColumn: number, text: string[]): IIdentifiedSingleEditOperation {
|
||||
return {
|
||||
identifier: null,
|
||||
range: new Range(startLineNumber, startColumn, endLineNumber, endColumn),
|
||||
text: text.join('\n'),
|
||||
forceMoveMarkers: false
|
||||
};
|
||||
}
|
||||
|
||||
test('auto1', () => {
|
||||
testApplyEditsWithSyncedModels(
|
||||
[
|
||||
'ioe',
|
||||
'',
|
||||
'yjct',
|
||||
'',
|
||||
'',
|
||||
],
|
||||
[
|
||||
editOp(1, 2, 1, 2, ['b', 'r', 'fq']),
|
||||
editOp(1, 4, 2, 1, ['', '']),
|
||||
],
|
||||
[
|
||||
'ib',
|
||||
'r',
|
||||
'fqoe',
|
||||
'',
|
||||
'yjct',
|
||||
'',
|
||||
'',
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
test('auto2', () => {
|
||||
testApplyEditsWithSyncedModels(
|
||||
[
|
||||
'f',
|
||||
'littnhskrq',
|
||||
'utxvsizqnk',
|
||||
'lslqz',
|
||||
'jxn',
|
||||
'gmm',
|
||||
],
|
||||
[
|
||||
editOp(1, 2, 1, 2, ['', 'o']),
|
||||
editOp(2, 4, 2, 4, ['zaq', 'avb']),
|
||||
editOp(2, 5, 6, 2, ['jlr', 'zl', 'j']),
|
||||
],
|
||||
[
|
||||
'f',
|
||||
'o',
|
||||
'litzaq',
|
||||
'avbtjlr',
|
||||
'zl',
|
||||
'jmm',
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
test('auto3', () => {
|
||||
testApplyEditsWithSyncedModels(
|
||||
[
|
||||
'ofw',
|
||||
'qsxmziuvzw',
|
||||
'rp',
|
||||
'qsnymek',
|
||||
'elth',
|
||||
'wmgzbwudxz',
|
||||
'iwsdkndh',
|
||||
'bujlbwb',
|
||||
'asuouxfv',
|
||||
'xuccnb',
|
||||
],
|
||||
[
|
||||
editOp(4, 3, 4, 3, ['']),
|
||||
],
|
||||
[
|
||||
'ofw',
|
||||
'qsxmziuvzw',
|
||||
'rp',
|
||||
'qsnymek',
|
||||
'elth',
|
||||
'wmgzbwudxz',
|
||||
'iwsdkndh',
|
||||
'bujlbwb',
|
||||
'asuouxfv',
|
||||
'xuccnb',
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
test('auto4', () => {
|
||||
testApplyEditsWithSyncedModels(
|
||||
[
|
||||
'fefymj',
|
||||
'qum',
|
||||
'vmiwxxaiqq',
|
||||
'dz',
|
||||
'lnqdgorosf',
|
||||
],
|
||||
[
|
||||
editOp(1, 3, 1, 5, ['hp']),
|
||||
editOp(1, 7, 2, 1, ['kcg', '', 'mpx']),
|
||||
editOp(2, 2, 2, 2, ['', 'aw', '']),
|
||||
editOp(2, 2, 2, 2, ['vqr', 'mo']),
|
||||
editOp(4, 2, 5, 3, ['xyc']),
|
||||
],
|
||||
[
|
||||
'fehpmjkcg',
|
||||
'',
|
||||
'mpxq',
|
||||
'aw',
|
||||
'vqr',
|
||||
'moum',
|
||||
'vmiwxxaiqq',
|
||||
'dxycqdgorosf',
|
||||
]
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
function getRandomInt(min: number, max: number): number {
|
||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
function generateFile(small: boolean): string {
|
||||
let lineCount = getRandomInt(1, small ? 3 : 10);
|
||||
let lines: string[] = [];
|
||||
for (let i = 0; i < lineCount; i++) {
|
||||
lines.push(getRandomString(0, small ? 3 : 10));
|
||||
}
|
||||
return lines.join('\n');
|
||||
}
|
||||
|
||||
function generateEdits(content: string): ITestModelEdit[] {
|
||||
|
||||
let result: ITestModelEdit[] = [];
|
||||
let cnt = getRandomInt(1, 5);
|
||||
|
||||
let maxOffset = content.length;
|
||||
|
||||
while (cnt > 0 && maxOffset > 0) {
|
||||
|
||||
let offset = getRandomInt(0, maxOffset);
|
||||
let length = getRandomInt(0, maxOffset - offset);
|
||||
let text = generateFile(true);
|
||||
|
||||
result.push({
|
||||
offset: offset,
|
||||
length: length,
|
||||
text: text
|
||||
});
|
||||
|
||||
maxOffset = offset;
|
||||
cnt--;
|
||||
}
|
||||
|
||||
result.reverse();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
interface ITestModelEdit {
|
||||
offset: number;
|
||||
length: number;
|
||||
text: string;
|
||||
}
|
||||
|
||||
class TestModel {
|
||||
|
||||
public initialContent: string;
|
||||
public resultingContent: string;
|
||||
public edits: IIdentifiedSingleEditOperation[];
|
||||
|
||||
private static _generateOffsetToPosition(content: string): Position[] {
|
||||
let result: Position[] = [];
|
||||
let lineNumber = 1;
|
||||
let column = 1;
|
||||
|
||||
for (let offset = 0, len = content.length; offset <= len; offset++) {
|
||||
let ch = content.charAt(offset);
|
||||
|
||||
result[offset] = new Position(lineNumber, column);
|
||||
|
||||
if (ch === '\n') {
|
||||
lineNumber++;
|
||||
column = 1;
|
||||
} else {
|
||||
column++;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
this.initialContent = generateFile(false);
|
||||
|
||||
let edits = generateEdits(this.initialContent);
|
||||
|
||||
let offsetToPosition = TestModel._generateOffsetToPosition(this.initialContent);
|
||||
this.edits = [];
|
||||
for (let i = 0; i < edits.length; i++) {
|
||||
let startPosition = offsetToPosition[edits[i].offset];
|
||||
let endPosition = offsetToPosition[edits[i].offset + edits[i].length];
|
||||
this.edits.push({
|
||||
identifier: null,
|
||||
range: new Range(startPosition.lineNumber, startPosition.column, endPosition.lineNumber, endPosition.column),
|
||||
text: edits[i].text,
|
||||
forceMoveMarkers: false
|
||||
});
|
||||
}
|
||||
|
||||
this.resultingContent = this.initialContent;
|
||||
for (let i = edits.length - 1; i >= 0; i--) {
|
||||
this.resultingContent = (
|
||||
this.resultingContent.substring(0, edits[i].offset) +
|
||||
edits[i].text +
|
||||
this.resultingContent.substring(edits[i].offset + edits[i].length)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public print(): string {
|
||||
let r: string[] = [];
|
||||
r.push('testApplyEditsWithSyncedModels(');
|
||||
r.push('\t[');
|
||||
let initialLines = this.initialContent.split('\n');
|
||||
r = r.concat(initialLines.map((i) => `\t\t'${i}',`));
|
||||
r.push('\t],');
|
||||
r.push('\t[');
|
||||
r = r.concat(this.edits.map((i) => {
|
||||
let text = `['` + i.text.split('\n').join(`', '`) + `']`;
|
||||
return `\t\teditOp(${i.range.startLineNumber}, ${i.range.startColumn}, ${i.range.endLineNumber}, ${i.range.endColumn}, ${text}),`;
|
||||
}));
|
||||
r.push('\t],');
|
||||
r.push('\t[');
|
||||
let resultLines = this.resultingContent.split('\n');
|
||||
r = r.concat(resultLines.map((i) => `\t\t'${i}',`));
|
||||
r.push('\t]');
|
||||
r.push(');');
|
||||
|
||||
return r.join('\n');
|
||||
}
|
||||
}
|
||||
|
||||
if (GENERATE_TESTS) {
|
||||
let number = 1;
|
||||
while (true) {
|
||||
|
||||
console.log('------BEGIN NEW TEST: ' + number);
|
||||
|
||||
let testModel = new TestModel();
|
||||
|
||||
// console.log(testModel.print());
|
||||
|
||||
console.log('------END NEW TEST: ' + (number++));
|
||||
|
||||
try {
|
||||
testApplyEditsWithSyncedModels(
|
||||
testModel.initialContent.split('\n'),
|
||||
testModel.edits,
|
||||
testModel.resultingContent.split('\n')
|
||||
);
|
||||
// throw new Error('a');
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
console.log(testModel.print());
|
||||
break;
|
||||
}
|
||||
|
||||
// break;
|
||||
}
|
||||
|
||||
}
|
||||
117
src/vs/editor/test/common/model/editableTextModelTestUtils.ts
Normal file
117
src/vs/editor/test/common/model/editableTextModelTestUtils.ts
Normal file
@@ -0,0 +1,117 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 * as editorCommon from 'vs/editor/common/editorCommon';
|
||||
import { EditableTextModel } from 'vs/editor/common/model/editableTextModel';
|
||||
import { MirrorModel } from 'vs/editor/common/model/mirrorModel';
|
||||
import { TextModel } from 'vs/editor/common/model/textModel';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { RawTextSource } from 'vs/editor/common/model/textSource';
|
||||
import { IModelContentChangedEvent } from 'vs/editor/common/model/textModelEvents';
|
||||
|
||||
export function testApplyEditsWithSyncedModels(original: string[], edits: editorCommon.IIdentifiedSingleEditOperation[], expected: string[], inputEditsAreInvalid: boolean = false): void {
|
||||
var originalStr = original.join('\n');
|
||||
var expectedStr = expected.join('\n');
|
||||
|
||||
assertSyncedModels(originalStr, (model, assertMirrorModels) => {
|
||||
// Apply edits & collect inverse edits
|
||||
var inverseEdits = model.applyEdits(edits);
|
||||
|
||||
// Assert edits produced expected result
|
||||
assert.deepEqual(model.getValue(editorCommon.EndOfLinePreference.LF), expectedStr);
|
||||
|
||||
assertMirrorModels();
|
||||
|
||||
// Apply the inverse edits
|
||||
var inverseInverseEdits = model.applyEdits(inverseEdits);
|
||||
|
||||
// Assert the inverse edits brought back model to original state
|
||||
assert.deepEqual(model.getValue(editorCommon.EndOfLinePreference.LF), originalStr);
|
||||
|
||||
if (!inputEditsAreInvalid) {
|
||||
// Assert the inverse of the inverse edits are the original edits
|
||||
assert.deepEqual(inverseInverseEdits, edits);
|
||||
}
|
||||
|
||||
assertMirrorModels();
|
||||
});
|
||||
}
|
||||
|
||||
const enum AssertDocumentLineMappingDirection {
|
||||
OffsetToPosition,
|
||||
PositionToOffset
|
||||
}
|
||||
|
||||
function assertOneDirectionLineMapping(model: TextModel, direction: AssertDocumentLineMappingDirection, msg: string): void {
|
||||
let allText = model.getValue();
|
||||
|
||||
let line = 1, column = 1, previousIsCarriageReturn = false;
|
||||
for (let offset = 0; offset <= allText.length; offset++) {
|
||||
// The position coordinate system cannot express the position between \r and \n
|
||||
let position = new Position(line, column + (previousIsCarriageReturn ? -1 : 0));
|
||||
|
||||
if (direction === AssertDocumentLineMappingDirection.OffsetToPosition) {
|
||||
let actualPosition = model.getPositionAt(offset);
|
||||
assert.equal(actualPosition.toString(), position.toString(), msg + ' - getPositionAt mismatch for offset ' + offset);
|
||||
} else {
|
||||
// The position coordinate system cannot express the position between \r and \n
|
||||
let expectedOffset = offset + (previousIsCarriageReturn ? -1 : 0);
|
||||
let actualOffset = model.getOffsetAt(position);
|
||||
assert.equal(actualOffset, expectedOffset, msg + ' - getOffsetAt mismatch for position ' + position.toString());
|
||||
}
|
||||
|
||||
if (allText.charAt(offset) === '\n') {
|
||||
line++;
|
||||
column = 1;
|
||||
} else {
|
||||
column++;
|
||||
}
|
||||
|
||||
previousIsCarriageReturn = (allText.charAt(offset) === '\r');
|
||||
}
|
||||
}
|
||||
|
||||
function assertLineMapping(model: TextModel, msg: string): void {
|
||||
assertOneDirectionLineMapping(model, AssertDocumentLineMappingDirection.PositionToOffset, msg);
|
||||
assertOneDirectionLineMapping(model, AssertDocumentLineMappingDirection.OffsetToPosition, msg);
|
||||
}
|
||||
|
||||
|
||||
export function assertSyncedModels(text: string, callback: (model: EditableTextModel, assertMirrorModels: () => void) => void, setup: (model: EditableTextModel) => void = null): void {
|
||||
var model = new EditableTextModel(RawTextSource.fromString(text), TextModel.DEFAULT_CREATION_OPTIONS, null);
|
||||
model.setEOL(editorCommon.EndOfLineSequence.LF);
|
||||
assertLineMapping(model, 'model');
|
||||
|
||||
if (setup) {
|
||||
setup(model);
|
||||
assertLineMapping(model, 'model');
|
||||
}
|
||||
|
||||
var mirrorModel2 = new MirrorModel(null, model.getLinesContent(), model.getEOL(), model.getVersionId());
|
||||
var mirrorModel2PrevVersionId = model.getVersionId();
|
||||
|
||||
model.onDidChangeContent((e: IModelContentChangedEvent) => {
|
||||
let versionId = e.versionId;
|
||||
if (versionId < mirrorModel2PrevVersionId) {
|
||||
console.warn('Model version id did not advance between edits (2)');
|
||||
}
|
||||
mirrorModel2PrevVersionId = versionId;
|
||||
mirrorModel2.onEvents(e);
|
||||
});
|
||||
|
||||
var assertMirrorModels = () => {
|
||||
assertLineMapping(model, 'model');
|
||||
model._assertLineNumbersOK();
|
||||
assert.equal(mirrorModel2.getText(), model.getValue(), 'mirror model 2 text OK');
|
||||
assert.equal(mirrorModel2.version, model.getVersionId(), 'mirror model 2 version OK');
|
||||
};
|
||||
|
||||
callback(model, assertMirrorModels);
|
||||
|
||||
model.dispose();
|
||||
mirrorModel2.dispose();
|
||||
}
|
||||
122
src/vs/editor/test/common/model/indentRanges.test.ts
Normal file
122
src/vs/editor/test/common/model/indentRanges.test.ts
Normal file
@@ -0,0 +1,122 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { Model } from 'vs/editor/common/model/model';
|
||||
import { computeRanges } from 'vs/editor/common/model/indentRanges';
|
||||
|
||||
export interface IndentRange {
|
||||
startLineNumber: number;
|
||||
endLineNumber: number;
|
||||
indent: number;
|
||||
}
|
||||
|
||||
suite('Indentation Folding', () => {
|
||||
function assertRanges(lines: string[], expected: IndentRange[]): void {
|
||||
let model = Model.createFromString(lines.join('\n'));
|
||||
let actual = computeRanges(model);
|
||||
actual.sort((r1, r2) => r1.startLineNumber - r2.startLineNumber);
|
||||
assert.deepEqual(actual, expected);
|
||||
model.dispose();
|
||||
}
|
||||
|
||||
function r(startLineNumber: number, endLineNumber: number, indent: number): IndentRange {
|
||||
return { startLineNumber, endLineNumber, indent };
|
||||
}
|
||||
|
||||
test('Fold one level', () => {
|
||||
assertRanges([
|
||||
'A',
|
||||
' A',
|
||||
' A',
|
||||
' A'
|
||||
], [r(1, 4, 0)]);
|
||||
});
|
||||
|
||||
test('Fold two levels', () => {
|
||||
assertRanges([
|
||||
'A',
|
||||
' A',
|
||||
' A',
|
||||
' A',
|
||||
' A'
|
||||
], [r(1, 5, 0), r(3, 5, 2)]);
|
||||
});
|
||||
|
||||
test('Fold three levels', () => {
|
||||
assertRanges([
|
||||
'A',
|
||||
' A',
|
||||
' A',
|
||||
' A',
|
||||
'A'
|
||||
], [r(1, 4, 0), r(2, 4, 2), r(3, 4, 4)]);
|
||||
});
|
||||
|
||||
test('Fold decreasing indent', () => {
|
||||
assertRanges([
|
||||
' A',
|
||||
' A',
|
||||
'A'
|
||||
], []);
|
||||
});
|
||||
|
||||
test('Fold Java', () => {
|
||||
assertRanges([
|
||||
/* 1*/ 'class A {',
|
||||
/* 2*/ ' void foo() {',
|
||||
/* 3*/ ' console.log();',
|
||||
/* 4*/ ' console.log();',
|
||||
/* 5*/ ' }',
|
||||
/* 6*/ '',
|
||||
/* 7*/ ' void bar() {',
|
||||
/* 8*/ ' console.log();',
|
||||
/* 9*/ ' }',
|
||||
/*10*/ '}',
|
||||
/*11*/ 'interface B {',
|
||||
/*12*/ ' void bar();',
|
||||
/*13*/ '}',
|
||||
], [r(1, 9, 0), r(2, 4, 2), r(7, 8, 2), r(11, 12, 0)]);
|
||||
});
|
||||
|
||||
test('Fold Javadoc', () => {
|
||||
assertRanges([
|
||||
/* 1*/ '/**',
|
||||
/* 2*/ ' * Comment',
|
||||
/* 3*/ ' */',
|
||||
/* 4*/ 'class A {',
|
||||
/* 5*/ ' void foo() {',
|
||||
/* 6*/ ' }',
|
||||
/* 7*/ '}',
|
||||
], [r(1, 3, 0), r(4, 6, 0)]);
|
||||
});
|
||||
test('Fold Whitespace', () => {
|
||||
assertRanges([
|
||||
/* 1*/ 'class A {',
|
||||
/* 2*/ '',
|
||||
/* 3*/ ' void foo() {',
|
||||
/* 4*/ ' ',
|
||||
/* 5*/ ' return 0;',
|
||||
/* 6*/ ' }',
|
||||
/* 7*/ ' ',
|
||||
/* 8*/ '}',
|
||||
], [r(1, 7, 0), r(3, 5, 2)]);
|
||||
});
|
||||
|
||||
test('Fold Tabs', () => {
|
||||
assertRanges([
|
||||
/* 1*/ 'class A {',
|
||||
/* 2*/ '\t\t',
|
||||
/* 3*/ '\tvoid foo() {',
|
||||
/* 4*/ '\t \t//hello',
|
||||
/* 5*/ '\t return 0;',
|
||||
/* 6*/ ' \t}',
|
||||
/* 7*/ ' ',
|
||||
/* 8*/ '}',
|
||||
], [r(1, 7, 0), r(3, 5, 4)]);
|
||||
});
|
||||
});
|
||||
2331
src/vs/editor/test/common/model/model.line.test.ts
Normal file
2331
src/vs/editor/test/common/model/model.line.test.ts
Normal file
File diff suppressed because it is too large
Load Diff
290
src/vs/editor/test/common/model/model.modes.test.ts
Normal file
290
src/vs/editor/test/common/model/model.modes.test.ts
Normal file
@@ -0,0 +1,290 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { EditOperation } from 'vs/editor/common/core/editOperation';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { Model } from 'vs/editor/common/model/model';
|
||||
import * as modes from 'vs/editor/common/modes';
|
||||
import { NULL_STATE } from 'vs/editor/common/modes/nullMode';
|
||||
import { TokenizationResult2 } from 'vs/editor/common/core/token';
|
||||
|
||||
// --------- utils
|
||||
|
||||
suite('Editor Model - Model Modes 1', () => {
|
||||
|
||||
let calledFor: string[] = [];
|
||||
|
||||
function checkAndClear(arr: string[]) {
|
||||
assert.deepEqual(calledFor, arr);
|
||||
calledFor = [];
|
||||
}
|
||||
|
||||
const tokenizationSupport: modes.ITokenizationSupport = {
|
||||
getInitialState: () => NULL_STATE,
|
||||
tokenize: undefined,
|
||||
tokenize2: (line: string, state: modes.IState): TokenizationResult2 => {
|
||||
calledFor.push(line.charAt(0));
|
||||
return new TokenizationResult2(null, state);
|
||||
}
|
||||
};
|
||||
|
||||
let thisModel: Model = null;
|
||||
let languageRegistration: IDisposable = null;
|
||||
|
||||
setup(() => {
|
||||
const TEXT =
|
||||
'1\r\n' +
|
||||
'2\n' +
|
||||
'3\n' +
|
||||
'4\r\n' +
|
||||
'5';
|
||||
const LANGUAGE_ID = 'modelModeTest1';
|
||||
calledFor = [];
|
||||
languageRegistration = modes.TokenizationRegistry.register(LANGUAGE_ID, tokenizationSupport);
|
||||
thisModel = Model.createFromString(TEXT, undefined, new modes.LanguageIdentifier(LANGUAGE_ID, 0));
|
||||
});
|
||||
|
||||
teardown(() => {
|
||||
thisModel.dispose();
|
||||
thisModel = null;
|
||||
languageRegistration.dispose();
|
||||
languageRegistration = null;
|
||||
calledFor = [];
|
||||
});
|
||||
|
||||
test('model calls syntax highlighter 1', () => {
|
||||
thisModel.forceTokenization(1);
|
||||
checkAndClear(['1']);
|
||||
});
|
||||
|
||||
test('model calls syntax highlighter 2', () => {
|
||||
thisModel.forceTokenization(2);
|
||||
checkAndClear(['1', '2']);
|
||||
|
||||
thisModel.forceTokenization(2);
|
||||
checkAndClear([]);
|
||||
});
|
||||
|
||||
test('model caches states', () => {
|
||||
thisModel.forceTokenization(1);
|
||||
checkAndClear(['1']);
|
||||
|
||||
thisModel.forceTokenization(2);
|
||||
checkAndClear(['2']);
|
||||
|
||||
thisModel.forceTokenization(3);
|
||||
checkAndClear(['3']);
|
||||
|
||||
thisModel.forceTokenization(4);
|
||||
checkAndClear(['4']);
|
||||
|
||||
thisModel.forceTokenization(5);
|
||||
checkAndClear(['5']);
|
||||
|
||||
thisModel.forceTokenization(5);
|
||||
checkAndClear([]);
|
||||
});
|
||||
|
||||
test('model invalidates states for one line insert', () => {
|
||||
thisModel.forceTokenization(5);
|
||||
checkAndClear(['1', '2', '3', '4', '5']);
|
||||
|
||||
thisModel.applyEdits([EditOperation.insert(new Position(1, 1), '-')]);
|
||||
thisModel.forceTokenization(5);
|
||||
checkAndClear(['-']);
|
||||
|
||||
thisModel.forceTokenization(5);
|
||||
checkAndClear([]);
|
||||
});
|
||||
|
||||
test('model invalidates states for many lines insert', () => {
|
||||
thisModel.forceTokenization(5);
|
||||
checkAndClear(['1', '2', '3', '4', '5']);
|
||||
|
||||
thisModel.applyEdits([EditOperation.insert(new Position(1, 1), '0\n-\n+')]);
|
||||
assert.equal(thisModel.getLineCount(), 7);
|
||||
thisModel.forceTokenization(7);
|
||||
checkAndClear(['0', '-', '+']);
|
||||
|
||||
thisModel.forceTokenization(7);
|
||||
checkAndClear([]);
|
||||
});
|
||||
|
||||
test('model invalidates states for one new line', () => {
|
||||
thisModel.forceTokenization(5);
|
||||
checkAndClear(['1', '2', '3', '4', '5']);
|
||||
|
||||
thisModel.applyEdits([EditOperation.insert(new Position(1, 2), '\n')]);
|
||||
thisModel.applyEdits([EditOperation.insert(new Position(2, 1), 'a')]);
|
||||
thisModel.forceTokenization(6);
|
||||
checkAndClear(['1', 'a']);
|
||||
});
|
||||
|
||||
test('model invalidates states for one line delete', () => {
|
||||
thisModel.forceTokenization(5);
|
||||
checkAndClear(['1', '2', '3', '4', '5']);
|
||||
|
||||
thisModel.applyEdits([EditOperation.insert(new Position(1, 2), '-')]);
|
||||
thisModel.forceTokenization(5);
|
||||
checkAndClear(['1']);
|
||||
|
||||
thisModel.applyEdits([EditOperation.delete(new Range(1, 1, 1, 2))]);
|
||||
thisModel.forceTokenization(5);
|
||||
checkAndClear(['-']);
|
||||
|
||||
thisModel.forceTokenization(5);
|
||||
checkAndClear([]);
|
||||
});
|
||||
|
||||
test('model invalidates states for many lines delete', () => {
|
||||
thisModel.forceTokenization(5);
|
||||
checkAndClear(['1', '2', '3', '4', '5']);
|
||||
|
||||
thisModel.applyEdits([EditOperation.delete(new Range(1, 1, 3, 1))]);
|
||||
thisModel.forceTokenization(3);
|
||||
checkAndClear(['3']);
|
||||
|
||||
thisModel.forceTokenization(3);
|
||||
checkAndClear([]);
|
||||
});
|
||||
});
|
||||
|
||||
suite('Editor Model - Model Modes 2', () => {
|
||||
|
||||
class ModelState2 implements modes.IState {
|
||||
prevLineContent: string;
|
||||
|
||||
constructor(prevLineContent: string) {
|
||||
this.prevLineContent = prevLineContent;
|
||||
}
|
||||
|
||||
clone(): modes.IState {
|
||||
return new ModelState2(this.prevLineContent);
|
||||
}
|
||||
|
||||
equals(other: modes.IState): boolean {
|
||||
return (other instanceof ModelState2) && other.prevLineContent === this.prevLineContent;
|
||||
}
|
||||
}
|
||||
|
||||
const tokenizationSupport: modes.ITokenizationSupport = {
|
||||
getInitialState: () => new ModelState2(''),
|
||||
tokenize: undefined,
|
||||
tokenize2: (line: string, state: modes.IState): TokenizationResult2 => {
|
||||
(<ModelState2>state).prevLineContent = line;
|
||||
return new TokenizationResult2(null, state);
|
||||
}
|
||||
};
|
||||
|
||||
function invalidEqual(model: Model, expected: number[]): void {
|
||||
let actual: number[] = [];
|
||||
for (let i = 0, len = model.getLineCount(); i < len; i++) {
|
||||
if (model._lines[i].isInvalid()) {
|
||||
actual.push(i);
|
||||
}
|
||||
}
|
||||
assert.deepEqual(actual, expected);
|
||||
}
|
||||
|
||||
function stateEqual(state: modes.IState, content: string): void {
|
||||
assert.equal((<ModelState2>state).prevLineContent, content);
|
||||
}
|
||||
|
||||
function statesEqual(model: Model, states: string[]): void {
|
||||
var i, len = states.length - 1;
|
||||
for (i = 0; i < len; i++) {
|
||||
stateEqual(model._lines[i].getState(), states[i]);
|
||||
}
|
||||
stateEqual((<any>model)._lastState, states[len]);
|
||||
}
|
||||
|
||||
let thisModel: Model = null;
|
||||
let languageRegistration: IDisposable = null;
|
||||
|
||||
setup(() => {
|
||||
const TEXT =
|
||||
'Line1' + '\r\n' +
|
||||
'Line2' + '\n' +
|
||||
'Line3' + '\n' +
|
||||
'Line4' + '\r\n' +
|
||||
'Line5';
|
||||
const LANGUAGE_ID = 'modelModeTest2';
|
||||
languageRegistration = modes.TokenizationRegistry.register(LANGUAGE_ID, tokenizationSupport);
|
||||
thisModel = Model.createFromString(TEXT, undefined, new modes.LanguageIdentifier(LANGUAGE_ID, 0));
|
||||
});
|
||||
|
||||
teardown(() => {
|
||||
thisModel.dispose();
|
||||
thisModel = null;
|
||||
languageRegistration.dispose();
|
||||
languageRegistration = null;
|
||||
});
|
||||
|
||||
test('getTokensForInvalidLines one text insert', () => {
|
||||
thisModel.forceTokenization(5);
|
||||
statesEqual(thisModel, ['', 'Line1', 'Line2', 'Line3', 'Line4', 'Line5']);
|
||||
thisModel.applyEdits([EditOperation.insert(new Position(1, 6), '-')]);
|
||||
invalidEqual(thisModel, [0]);
|
||||
statesEqual(thisModel, ['', 'Line1', 'Line2', 'Line3', 'Line4', 'Line5']);
|
||||
thisModel.forceTokenization(5);
|
||||
statesEqual(thisModel, ['', 'Line1-', 'Line2', 'Line3', 'Line4', 'Line5']);
|
||||
});
|
||||
|
||||
test('getTokensForInvalidLines two text insert', () => {
|
||||
thisModel.forceTokenization(5);
|
||||
statesEqual(thisModel, ['', 'Line1', 'Line2', 'Line3', 'Line4', 'Line5']);
|
||||
thisModel.applyEdits([
|
||||
EditOperation.insert(new Position(1, 6), '-'),
|
||||
EditOperation.insert(new Position(3, 6), '-')
|
||||
]);
|
||||
|
||||
invalidEqual(thisModel, [0, 2]);
|
||||
thisModel.forceTokenization(5);
|
||||
statesEqual(thisModel, ['', 'Line1-', 'Line2', 'Line3-', 'Line4', 'Line5']);
|
||||
});
|
||||
|
||||
test('getTokensForInvalidLines one multi-line text insert, one small text insert', () => {
|
||||
thisModel.forceTokenization(5);
|
||||
statesEqual(thisModel, ['', 'Line1', 'Line2', 'Line3', 'Line4', 'Line5']);
|
||||
thisModel.applyEdits([EditOperation.insert(new Position(1, 6), '\nNew line\nAnother new line')]);
|
||||
thisModel.applyEdits([EditOperation.insert(new Position(5, 6), '-')]);
|
||||
invalidEqual(thisModel, [0, 4]);
|
||||
thisModel.forceTokenization(7);
|
||||
statesEqual(thisModel, ['', 'Line1', 'New line', 'Another new line', 'Line2', 'Line3-', 'Line4', 'Line5']);
|
||||
});
|
||||
|
||||
test('getTokensForInvalidLines one delete text', () => {
|
||||
thisModel.forceTokenization(5);
|
||||
statesEqual(thisModel, ['', 'Line1', 'Line2', 'Line3', 'Line4', 'Line5']);
|
||||
thisModel.applyEdits([EditOperation.delete(new Range(1, 1, 1, 5))]);
|
||||
invalidEqual(thisModel, [0]);
|
||||
thisModel.forceTokenization(5);
|
||||
statesEqual(thisModel, ['', '1', 'Line2', 'Line3', 'Line4', 'Line5']);
|
||||
});
|
||||
|
||||
test('getTokensForInvalidLines one line delete text', () => {
|
||||
thisModel.forceTokenization(5);
|
||||
statesEqual(thisModel, ['', 'Line1', 'Line2', 'Line3', 'Line4', 'Line5']);
|
||||
thisModel.applyEdits([EditOperation.delete(new Range(1, 1, 2, 1))]);
|
||||
invalidEqual(thisModel, [0]);
|
||||
statesEqual(thisModel, ['', 'Line2', 'Line3', 'Line4', 'Line5']);
|
||||
thisModel.forceTokenization(4);
|
||||
statesEqual(thisModel, ['', 'Line2', 'Line3', 'Line4', 'Line5']);
|
||||
});
|
||||
|
||||
test('getTokensForInvalidLines multiple lines delete text', () => {
|
||||
thisModel.forceTokenization(5);
|
||||
statesEqual(thisModel, ['', 'Line1', 'Line2', 'Line3', 'Line4', 'Line5']);
|
||||
thisModel.applyEdits([EditOperation.delete(new Range(1, 1, 3, 3))]);
|
||||
invalidEqual(thisModel, [0]);
|
||||
statesEqual(thisModel, ['', 'Line3', 'Line4', 'Line5']);
|
||||
thisModel.forceTokenization(3);
|
||||
statesEqual(thisModel, ['', 'ne3', 'Line4', 'Line5']);
|
||||
});
|
||||
});
|
||||
395
src/vs/editor/test/common/model/model.test.ts
Normal file
395
src/vs/editor/test/common/model/model.test.ts
Normal file
@@ -0,0 +1,395 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { EditOperation } from 'vs/editor/common/core/editOperation';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import {
|
||||
ModelRawContentChangedEvent, ModelRawFlush, ModelRawLineChanged,
|
||||
ModelRawLinesDeleted, ModelRawLinesInserted
|
||||
} from 'vs/editor/common/model/textModelEvents';
|
||||
import { Model } from 'vs/editor/common/model/model';
|
||||
|
||||
// --------- utils
|
||||
|
||||
var LINE1 = 'My First Line';
|
||||
var LINE2 = '\t\tMy Second Line';
|
||||
var LINE3 = ' Third Line';
|
||||
var LINE4 = '';
|
||||
var LINE5 = '1';
|
||||
|
||||
suite('Editor Model - Model', () => {
|
||||
|
||||
var thisModel: Model;
|
||||
|
||||
setup(() => {
|
||||
var text =
|
||||
LINE1 + '\r\n' +
|
||||
LINE2 + '\n' +
|
||||
LINE3 + '\n' +
|
||||
LINE4 + '\r\n' +
|
||||
LINE5;
|
||||
thisModel = Model.createFromString(text);
|
||||
});
|
||||
|
||||
teardown(() => {
|
||||
thisModel.dispose();
|
||||
});
|
||||
|
||||
// --------- insert text
|
||||
|
||||
test('model getValue', () => {
|
||||
assert.equal(thisModel.getValue(), 'My First Line\n\t\tMy Second Line\n Third Line\n\n1');
|
||||
});
|
||||
|
||||
test('model insert empty text', () => {
|
||||
thisModel.applyEdits([EditOperation.insert(new Position(1, 1), '')]);
|
||||
assert.equal(thisModel.getLineCount(), 5);
|
||||
assert.equal(thisModel.getLineContent(1), 'My First Line');
|
||||
});
|
||||
|
||||
test('model insert text without newline 1', () => {
|
||||
thisModel.applyEdits([EditOperation.insert(new Position(1, 1), 'foo ')]);
|
||||
assert.equal(thisModel.getLineCount(), 5);
|
||||
assert.equal(thisModel.getLineContent(1), 'foo My First Line');
|
||||
});
|
||||
|
||||
test('model insert text without newline 2', () => {
|
||||
thisModel.applyEdits([EditOperation.insert(new Position(1, 3), ' foo')]);
|
||||
assert.equal(thisModel.getLineCount(), 5);
|
||||
assert.equal(thisModel.getLineContent(1), 'My foo First Line');
|
||||
});
|
||||
|
||||
test('model insert text with one newline', () => {
|
||||
thisModel.applyEdits([EditOperation.insert(new Position(1, 3), ' new line\nNo longer')]);
|
||||
assert.equal(thisModel.getLineCount(), 6);
|
||||
assert.equal(thisModel.getLineContent(1), 'My new line');
|
||||
assert.equal(thisModel.getLineContent(2), 'No longer First Line');
|
||||
});
|
||||
|
||||
test('model insert text with two newlines', () => {
|
||||
thisModel.applyEdits([EditOperation.insert(new Position(1, 3), ' new line\nOne more line in the middle\nNo longer')]);
|
||||
assert.equal(thisModel.getLineCount(), 7);
|
||||
assert.equal(thisModel.getLineContent(1), 'My new line');
|
||||
assert.equal(thisModel.getLineContent(2), 'One more line in the middle');
|
||||
assert.equal(thisModel.getLineContent(3), 'No longer First Line');
|
||||
});
|
||||
|
||||
test('model insert text with many newlines', () => {
|
||||
thisModel.applyEdits([EditOperation.insert(new Position(1, 3), '\n\n\n\n')]);
|
||||
assert.equal(thisModel.getLineCount(), 9);
|
||||
assert.equal(thisModel.getLineContent(1), 'My');
|
||||
assert.equal(thisModel.getLineContent(2), '');
|
||||
assert.equal(thisModel.getLineContent(3), '');
|
||||
assert.equal(thisModel.getLineContent(4), '');
|
||||
assert.equal(thisModel.getLineContent(5), ' First Line');
|
||||
});
|
||||
|
||||
|
||||
// --------- insert text eventing
|
||||
|
||||
test('model insert empty text does not trigger eventing', () => {
|
||||
thisModel.onDidChangeRawContent((e) => {
|
||||
assert.ok(false, 'was not expecting event');
|
||||
});
|
||||
thisModel.applyEdits([EditOperation.insert(new Position(1, 1), '')]);
|
||||
});
|
||||
|
||||
test('model insert text without newline eventing', () => {
|
||||
let e: ModelRawContentChangedEvent = null;
|
||||
thisModel.onDidChangeRawContent((_e) => {
|
||||
if (e !== null) {
|
||||
assert.fail();
|
||||
}
|
||||
e = _e;
|
||||
});
|
||||
thisModel.applyEdits([EditOperation.insert(new Position(1, 1), 'foo ')]);
|
||||
assert.deepEqual(e, new ModelRawContentChangedEvent(
|
||||
[
|
||||
new ModelRawLineChanged(1, 'foo My First Line')
|
||||
],
|
||||
2,
|
||||
false,
|
||||
false
|
||||
));
|
||||
});
|
||||
|
||||
test('model insert text with one newline eventing', () => {
|
||||
let e: ModelRawContentChangedEvent = null;
|
||||
thisModel.onDidChangeRawContent((_e) => {
|
||||
if (e !== null) {
|
||||
assert.fail();
|
||||
}
|
||||
e = _e;
|
||||
});
|
||||
thisModel.applyEdits([EditOperation.insert(new Position(1, 3), ' new line\nNo longer')]);
|
||||
assert.deepEqual(e, new ModelRawContentChangedEvent(
|
||||
[
|
||||
new ModelRawLineChanged(1, 'My new line First Line'),
|
||||
new ModelRawLineChanged(1, 'My new line'),
|
||||
new ModelRawLinesInserted(2, 2, 'No longer First Line'),
|
||||
],
|
||||
2,
|
||||
false,
|
||||
false
|
||||
));
|
||||
});
|
||||
|
||||
|
||||
// --------- delete text
|
||||
|
||||
test('model delete empty text', () => {
|
||||
thisModel.applyEdits([EditOperation.delete(new Range(1, 1, 1, 1))]);
|
||||
assert.equal(thisModel.getLineCount(), 5);
|
||||
assert.equal(thisModel.getLineContent(1), 'My First Line');
|
||||
});
|
||||
|
||||
test('model delete text from one line', () => {
|
||||
thisModel.applyEdits([EditOperation.delete(new Range(1, 1, 1, 2))]);
|
||||
assert.equal(thisModel.getLineCount(), 5);
|
||||
assert.equal(thisModel.getLineContent(1), 'y First Line');
|
||||
});
|
||||
|
||||
test('model delete text from one line 2', () => {
|
||||
thisModel.applyEdits([EditOperation.insert(new Position(1, 1), 'a')]);
|
||||
assert.equal(thisModel.getLineContent(1), 'aMy First Line');
|
||||
|
||||
thisModel.applyEdits([EditOperation.delete(new Range(1, 2, 1, 4))]);
|
||||
assert.equal(thisModel.getLineCount(), 5);
|
||||
assert.equal(thisModel.getLineContent(1), 'a First Line');
|
||||
});
|
||||
|
||||
test('model delete all text from a line', () => {
|
||||
thisModel.applyEdits([EditOperation.delete(new Range(1, 1, 1, 14))]);
|
||||
assert.equal(thisModel.getLineCount(), 5);
|
||||
assert.equal(thisModel.getLineContent(1), '');
|
||||
});
|
||||
|
||||
test('model delete text from two lines', () => {
|
||||
thisModel.applyEdits([EditOperation.delete(new Range(1, 4, 2, 6))]);
|
||||
assert.equal(thisModel.getLineCount(), 4);
|
||||
assert.equal(thisModel.getLineContent(1), 'My Second Line');
|
||||
});
|
||||
|
||||
test('model delete text from many lines', () => {
|
||||
thisModel.applyEdits([EditOperation.delete(new Range(1, 4, 3, 5))]);
|
||||
assert.equal(thisModel.getLineCount(), 3);
|
||||
assert.equal(thisModel.getLineContent(1), 'My Third Line');
|
||||
});
|
||||
|
||||
test('model delete everything', () => {
|
||||
thisModel.applyEdits([EditOperation.delete(new Range(1, 1, 5, 2))]);
|
||||
assert.equal(thisModel.getLineCount(), 1);
|
||||
assert.equal(thisModel.getLineContent(1), '');
|
||||
});
|
||||
|
||||
// --------- delete text eventing
|
||||
|
||||
test('model delete empty text does not trigger eventing', () => {
|
||||
thisModel.onDidChangeRawContent((e) => {
|
||||
assert.ok(false, 'was not expecting event');
|
||||
});
|
||||
thisModel.applyEdits([EditOperation.delete(new Range(1, 1, 1, 1))]);
|
||||
});
|
||||
|
||||
test('model delete text from one line eventing', () => {
|
||||
let e: ModelRawContentChangedEvent = null;
|
||||
thisModel.onDidChangeRawContent((_e) => {
|
||||
if (e !== null) {
|
||||
assert.fail();
|
||||
}
|
||||
e = _e;
|
||||
});
|
||||
thisModel.applyEdits([EditOperation.delete(new Range(1, 1, 1, 2))]);
|
||||
assert.deepEqual(e, new ModelRawContentChangedEvent(
|
||||
[
|
||||
new ModelRawLineChanged(1, 'y First Line'),
|
||||
],
|
||||
2,
|
||||
false,
|
||||
false
|
||||
));
|
||||
});
|
||||
|
||||
test('model delete all text from a line eventing', () => {
|
||||
let e: ModelRawContentChangedEvent = null;
|
||||
thisModel.onDidChangeRawContent((_e) => {
|
||||
if (e !== null) {
|
||||
assert.fail();
|
||||
}
|
||||
e = _e;
|
||||
});
|
||||
thisModel.applyEdits([EditOperation.delete(new Range(1, 1, 1, 14))]);
|
||||
assert.deepEqual(e, new ModelRawContentChangedEvent(
|
||||
[
|
||||
new ModelRawLineChanged(1, ''),
|
||||
],
|
||||
2,
|
||||
false,
|
||||
false
|
||||
));
|
||||
});
|
||||
|
||||
test('model delete text from two lines eventing', () => {
|
||||
let e: ModelRawContentChangedEvent = null;
|
||||
thisModel.onDidChangeRawContent((_e) => {
|
||||
if (e !== null) {
|
||||
assert.fail();
|
||||
}
|
||||
e = _e;
|
||||
});
|
||||
thisModel.applyEdits([EditOperation.delete(new Range(1, 4, 2, 6))]);
|
||||
assert.deepEqual(e, new ModelRawContentChangedEvent(
|
||||
[
|
||||
new ModelRawLineChanged(1, 'My '),
|
||||
new ModelRawLineChanged(1, 'My Second Line'),
|
||||
new ModelRawLinesDeleted(2, 2),
|
||||
],
|
||||
2,
|
||||
false,
|
||||
false
|
||||
));
|
||||
});
|
||||
|
||||
test('model delete text from many lines eventing', () => {
|
||||
let e: ModelRawContentChangedEvent = null;
|
||||
thisModel.onDidChangeRawContent((_e) => {
|
||||
if (e !== null) {
|
||||
assert.fail();
|
||||
}
|
||||
e = _e;
|
||||
});
|
||||
thisModel.applyEdits([EditOperation.delete(new Range(1, 4, 3, 5))]);
|
||||
assert.deepEqual(e, new ModelRawContentChangedEvent(
|
||||
[
|
||||
new ModelRawLineChanged(1, 'My '),
|
||||
new ModelRawLineChanged(1, 'My Third Line'),
|
||||
new ModelRawLinesDeleted(2, 3),
|
||||
],
|
||||
2,
|
||||
false,
|
||||
false
|
||||
));
|
||||
});
|
||||
|
||||
// --------- getValueInRange
|
||||
|
||||
test('getValueInRange', () => {
|
||||
assert.equal(thisModel.getValueInRange(new Range(1, 1, 1, 1)), '');
|
||||
assert.equal(thisModel.getValueInRange(new Range(1, 1, 1, 2)), 'M');
|
||||
assert.equal(thisModel.getValueInRange(new Range(1, 2, 1, 3)), 'y');
|
||||
assert.equal(thisModel.getValueInRange(new Range(1, 1, 1, 14)), 'My First Line');
|
||||
assert.equal(thisModel.getValueInRange(new Range(1, 1, 2, 1)), 'My First Line\n');
|
||||
assert.equal(thisModel.getValueInRange(new Range(1, 1, 2, 2)), 'My First Line\n\t');
|
||||
assert.equal(thisModel.getValueInRange(new Range(1, 1, 2, 3)), 'My First Line\n\t\t');
|
||||
assert.equal(thisModel.getValueInRange(new Range(1, 1, 2, 17)), 'My First Line\n\t\tMy Second Line');
|
||||
assert.equal(thisModel.getValueInRange(new Range(1, 1, 3, 1)), 'My First Line\n\t\tMy Second Line\n');
|
||||
assert.equal(thisModel.getValueInRange(new Range(1, 1, 4, 1)), 'My First Line\n\t\tMy Second Line\n Third Line\n');
|
||||
});
|
||||
|
||||
// --------- getValueLengthInRange
|
||||
|
||||
test('getValueLengthInRange', () => {
|
||||
assert.equal(thisModel.getValueLengthInRange(new Range(1, 1, 1, 1)), ''.length);
|
||||
assert.equal(thisModel.getValueLengthInRange(new Range(1, 1, 1, 2)), 'M'.length);
|
||||
assert.equal(thisModel.getValueLengthInRange(new Range(1, 2, 1, 3)), 'y'.length);
|
||||
assert.equal(thisModel.getValueLengthInRange(new Range(1, 1, 1, 14)), 'My First Line'.length);
|
||||
assert.equal(thisModel.getValueLengthInRange(new Range(1, 1, 2, 1)), 'My First Line\n'.length);
|
||||
assert.equal(thisModel.getValueLengthInRange(new Range(1, 1, 2, 2)), 'My First Line\n\t'.length);
|
||||
assert.equal(thisModel.getValueLengthInRange(new Range(1, 1, 2, 3)), 'My First Line\n\t\t'.length);
|
||||
assert.equal(thisModel.getValueLengthInRange(new Range(1, 1, 2, 17)), 'My First Line\n\t\tMy Second Line'.length);
|
||||
assert.equal(thisModel.getValueLengthInRange(new Range(1, 1, 3, 1)), 'My First Line\n\t\tMy Second Line\n'.length);
|
||||
assert.equal(thisModel.getValueLengthInRange(new Range(1, 1, 4, 1)), 'My First Line\n\t\tMy Second Line\n Third Line\n'.length);
|
||||
});
|
||||
|
||||
// --------- setValue
|
||||
test('setValue eventing', () => {
|
||||
let e: ModelRawContentChangedEvent = null;
|
||||
thisModel.onDidChangeRawContent((_e) => {
|
||||
if (e !== null) {
|
||||
assert.fail();
|
||||
}
|
||||
e = _e;
|
||||
});
|
||||
thisModel.setValue('new value');
|
||||
assert.deepEqual(e, new ModelRawContentChangedEvent(
|
||||
[
|
||||
new ModelRawFlush()
|
||||
],
|
||||
2,
|
||||
false,
|
||||
false
|
||||
));
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// --------- Special Unicode LINE SEPARATOR character
|
||||
suite('Editor Model - Model Line Separators', () => {
|
||||
|
||||
var thisModel: Model;
|
||||
|
||||
setup(() => {
|
||||
var text =
|
||||
LINE1 + '\u2028' +
|
||||
LINE2 + '\n' +
|
||||
LINE3 + '\u2028' +
|
||||
LINE4 + '\r\n' +
|
||||
LINE5;
|
||||
thisModel = Model.createFromString(text);
|
||||
});
|
||||
|
||||
teardown(() => {
|
||||
thisModel.dispose();
|
||||
});
|
||||
|
||||
test('model getValue', () => {
|
||||
assert.equal(thisModel.getValue(), 'My First Line\u2028\t\tMy Second Line\n Third Line\u2028\n1');
|
||||
});
|
||||
|
||||
test('model lines', () => {
|
||||
assert.equal(thisModel.getLineCount(), 3);
|
||||
});
|
||||
|
||||
test('Bug 13333:Model should line break on lonely CR too', () => {
|
||||
var model = Model.createFromString('Hello\rWorld!\r\nAnother line');
|
||||
assert.equal(model.getLineCount(), 3);
|
||||
assert.equal(model.getValue(), 'Hello\r\nWorld!\r\nAnother line');
|
||||
model.dispose();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// --------- Words
|
||||
|
||||
suite('Editor Model - Words', () => {
|
||||
|
||||
var thisModel: Model;
|
||||
|
||||
setup(() => {
|
||||
var text = ['This text has some words. '];
|
||||
thisModel = Model.createFromString(text.join('\n'));
|
||||
});
|
||||
|
||||
teardown(() => {
|
||||
thisModel.dispose();
|
||||
});
|
||||
|
||||
test('Get word at position', () => {
|
||||
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 });
|
||||
assert.deepEqual(thisModel.getWordAtPosition(new Position(1, 5)), { word: 'This', startColumn: 1, endColumn: 5 });
|
||||
assert.deepEqual(thisModel.getWordAtPosition(new Position(1, 6)), { word: 'text', startColumn: 6, endColumn: 10 });
|
||||
assert.deepEqual(thisModel.getWordAtPosition(new Position(1, 19)), { word: 'some', startColumn: 15, endColumn: 19 });
|
||||
assert.deepEqual(thisModel.getWordAtPosition(new Position(1, 20)), null);
|
||||
assert.deepEqual(thisModel.getWordAtPosition(new Position(1, 21)), { word: 'words', startColumn: 21, endColumn: 26 });
|
||||
assert.deepEqual(thisModel.getWordAtPosition(new Position(1, 26)), { word: 'words', startColumn: 21, endColumn: 26 });
|
||||
assert.deepEqual(thisModel.getWordAtPosition(new Position(1, 27)), null);
|
||||
assert.deepEqual(thisModel.getWordAtPosition(new Position(1, 28)), null);
|
||||
});
|
||||
});
|
||||
638
src/vs/editor/test/common/model/modelDecorations.test.ts
Normal file
638
src/vs/editor/test/common/model/modelDecorations.test.ts
Normal file
@@ -0,0 +1,638 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { EditOperation } from 'vs/editor/common/core/editOperation';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { IModelDeltaDecoration, TrackedRangeStickiness } from 'vs/editor/common/editorCommon';
|
||||
import { Model } from 'vs/editor/common/model/model';
|
||||
|
||||
// --------- utils
|
||||
|
||||
interface ILightWeightDecoration2 {
|
||||
range: Range;
|
||||
className: string;
|
||||
}
|
||||
|
||||
function modelHasDecorations(model: Model, decorations: ILightWeightDecoration2[]) {
|
||||
let modelDecorations: ILightWeightDecoration2[] = [];
|
||||
let actualDecorations = model.getAllDecorations();
|
||||
for (let i = 0, len = actualDecorations.length; i < len; i++) {
|
||||
modelDecorations.push({
|
||||
range: actualDecorations[i].range,
|
||||
className: actualDecorations[i].options.className
|
||||
});
|
||||
}
|
||||
assert.deepEqual(modelDecorations, decorations, 'Model decorations');
|
||||
}
|
||||
|
||||
function modelHasDecoration(model: Model, startLineNumber: number, startColumn: number, endLineNumber: number, endColumn: number, className: string) {
|
||||
modelHasDecorations(model, [{
|
||||
range: new Range(startLineNumber, startColumn, endLineNumber, endColumn),
|
||||
className: className
|
||||
}]);
|
||||
}
|
||||
|
||||
function modelHasNoDecorations(model: Model) {
|
||||
assert.equal(model.getAllDecorations().length, 0, 'Model has no decoration');
|
||||
}
|
||||
|
||||
function addDecoration(model: Model, startLineNumber: number, startColumn: number, endLineNumber: number, endColumn: number, className: string): string {
|
||||
return model.changeDecorations((changeAccessor) => {
|
||||
return changeAccessor.addDecoration(new Range(startLineNumber, startColumn, endLineNumber, endColumn), {
|
||||
className: className
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function lineHasDecorations(model: Model, lineNumber: number, decorations: { start: number; end: number; className: string; }[]) {
|
||||
var lineDecorations = [];
|
||||
var decs = model.getLineDecorations(lineNumber);
|
||||
for (var i = 0, len = decs.length; i < len; i++) {
|
||||
lineDecorations.push({
|
||||
start: decs[i].range.startColumn,
|
||||
end: decs[i].range.endColumn,
|
||||
className: decs[i].options.className
|
||||
});
|
||||
}
|
||||
assert.deepEqual(lineDecorations, decorations, 'Line decorations');
|
||||
}
|
||||
|
||||
function lineHasNoDecorations(model: Model, lineNumber: number) {
|
||||
lineHasDecorations(model, lineNumber, []);
|
||||
}
|
||||
|
||||
function lineHasDecoration(model: Model, lineNumber: number, start: number, end: number, className: string) {
|
||||
lineHasDecorations(model, lineNumber, [{
|
||||
start: start,
|
||||
end: end,
|
||||
className: className
|
||||
}]);
|
||||
}
|
||||
|
||||
suite('Editor Model - Model Decorations', () => {
|
||||
var LINE1 = 'My First Line';
|
||||
var LINE2 = '\t\tMy Second Line';
|
||||
var LINE3 = ' Third Line';
|
||||
var LINE4 = '';
|
||||
var LINE5 = '1';
|
||||
|
||||
// --------- Model Decorations
|
||||
|
||||
var thisModel: Model;
|
||||
|
||||
setup(() => {
|
||||
var text =
|
||||
LINE1 + '\r\n' +
|
||||
LINE2 + '\n' +
|
||||
LINE3 + '\n' +
|
||||
LINE4 + '\r\n' +
|
||||
LINE5;
|
||||
thisModel = Model.createFromString(text);
|
||||
});
|
||||
|
||||
teardown(() => {
|
||||
thisModel.dispose();
|
||||
thisModel = null;
|
||||
});
|
||||
|
||||
test('single character decoration', () => {
|
||||
addDecoration(thisModel, 1, 1, 1, 2, 'myType');
|
||||
lineHasDecoration(thisModel, 1, 1, 2, 'myType');
|
||||
lineHasNoDecorations(thisModel, 2);
|
||||
lineHasNoDecorations(thisModel, 3);
|
||||
lineHasNoDecorations(thisModel, 4);
|
||||
lineHasNoDecorations(thisModel, 5);
|
||||
});
|
||||
|
||||
test('line decoration', () => {
|
||||
addDecoration(thisModel, 1, 1, 1, 14, 'myType');
|
||||
lineHasDecoration(thisModel, 1, 1, 14, 'myType');
|
||||
lineHasNoDecorations(thisModel, 2);
|
||||
lineHasNoDecorations(thisModel, 3);
|
||||
lineHasNoDecorations(thisModel, 4);
|
||||
lineHasNoDecorations(thisModel, 5);
|
||||
});
|
||||
|
||||
test('full line decoration', () => {
|
||||
addDecoration(thisModel, 1, 1, 2, 1, 'myType');
|
||||
|
||||
var line1Decorations = thisModel.getLineDecorations(1);
|
||||
assert.equal(line1Decorations.length, 1);
|
||||
assert.equal(line1Decorations[0].options.className, 'myType');
|
||||
|
||||
var line2Decorations = thisModel.getLineDecorations(1);
|
||||
assert.equal(line2Decorations.length, 1);
|
||||
assert.equal(line2Decorations[0].options.className, 'myType');
|
||||
|
||||
lineHasNoDecorations(thisModel, 3);
|
||||
lineHasNoDecorations(thisModel, 4);
|
||||
lineHasNoDecorations(thisModel, 5);
|
||||
});
|
||||
|
||||
test('multiple line decoration', () => {
|
||||
addDecoration(thisModel, 1, 2, 3, 2, 'myType');
|
||||
|
||||
var line1Decorations = thisModel.getLineDecorations(1);
|
||||
assert.equal(line1Decorations.length, 1);
|
||||
assert.equal(line1Decorations[0].options.className, 'myType');
|
||||
|
||||
var line2Decorations = thisModel.getLineDecorations(1);
|
||||
assert.equal(line2Decorations.length, 1);
|
||||
assert.equal(line2Decorations[0].options.className, 'myType');
|
||||
|
||||
var line3Decorations = thisModel.getLineDecorations(1);
|
||||
assert.equal(line3Decorations.length, 1);
|
||||
assert.equal(line3Decorations[0].options.className, 'myType');
|
||||
|
||||
lineHasNoDecorations(thisModel, 4);
|
||||
lineHasNoDecorations(thisModel, 5);
|
||||
});
|
||||
|
||||
// --------- removing, changing decorations
|
||||
|
||||
test('decoration gets removed', () => {
|
||||
var decId = addDecoration(thisModel, 1, 2, 3, 2, 'myType');
|
||||
modelHasDecoration(thisModel, 1, 2, 3, 2, 'myType');
|
||||
thisModel.changeDecorations((changeAccessor) => {
|
||||
changeAccessor.removeDecoration(decId);
|
||||
});
|
||||
modelHasNoDecorations(thisModel);
|
||||
});
|
||||
|
||||
test('decorations get removed', () => {
|
||||
var decId1 = addDecoration(thisModel, 1, 2, 3, 2, 'myType1');
|
||||
var decId2 = addDecoration(thisModel, 1, 2, 3, 1, 'myType2');
|
||||
modelHasDecorations(thisModel, [
|
||||
{
|
||||
range: new Range(1, 2, 3, 2),
|
||||
className: 'myType1'
|
||||
},
|
||||
{
|
||||
range: new Range(1, 2, 3, 1),
|
||||
className: 'myType2'
|
||||
}
|
||||
]);
|
||||
thisModel.changeDecorations((changeAccessor) => {
|
||||
changeAccessor.removeDecoration(decId1);
|
||||
});
|
||||
modelHasDecorations(thisModel, [
|
||||
{
|
||||
range: new Range(1, 2, 3, 1),
|
||||
className: 'myType2'
|
||||
}
|
||||
]);
|
||||
thisModel.changeDecorations((changeAccessor) => {
|
||||
changeAccessor.removeDecoration(decId2);
|
||||
});
|
||||
modelHasNoDecorations(thisModel);
|
||||
});
|
||||
|
||||
test('decoration range can be changed', () => {
|
||||
var decId = addDecoration(thisModel, 1, 2, 3, 2, 'myType');
|
||||
modelHasDecoration(thisModel, 1, 2, 3, 2, 'myType');
|
||||
thisModel.changeDecorations((changeAccessor) => {
|
||||
changeAccessor.changeDecoration(decId, new Range(1, 1, 1, 2));
|
||||
});
|
||||
modelHasDecoration(thisModel, 1, 1, 1, 2, 'myType');
|
||||
});
|
||||
|
||||
// --------- eventing
|
||||
|
||||
test('decorations emit event on add', () => {
|
||||
let listenerCalled = 0;
|
||||
thisModel.onDidChangeDecorations((e) => {
|
||||
listenerCalled++;
|
||||
assert.equal(e.addedDecorations.length, 1);
|
||||
assert.equal(e.changedDecorations.length, 0);
|
||||
assert.equal(e.removedDecorations.length, 0);
|
||||
});
|
||||
addDecoration(thisModel, 1, 2, 3, 2, 'myType');
|
||||
assert.equal(listenerCalled, 1, 'listener called');
|
||||
});
|
||||
|
||||
test('decorations emit event on change', () => {
|
||||
let listenerCalled = 0;
|
||||
let decId = addDecoration(thisModel, 1, 2, 3, 2, 'myType');
|
||||
thisModel.onDidChangeDecorations((e) => {
|
||||
listenerCalled++;
|
||||
assert.equal(e.addedDecorations.length, 0);
|
||||
assert.equal(e.changedDecorations.length, 1);
|
||||
assert.equal(e.changedDecorations[0], decId);
|
||||
assert.equal(e.removedDecorations.length, 0);
|
||||
});
|
||||
thisModel.changeDecorations((changeAccessor) => {
|
||||
changeAccessor.changeDecoration(decId, new Range(1, 1, 1, 2));
|
||||
});
|
||||
assert.equal(listenerCalled, 1, 'listener called');
|
||||
});
|
||||
|
||||
test('decorations emit event on remove', () => {
|
||||
let listenerCalled = 0;
|
||||
let decId = addDecoration(thisModel, 1, 2, 3, 2, 'myType');
|
||||
thisModel.onDidChangeDecorations((e) => {
|
||||
listenerCalled++;
|
||||
assert.equal(e.addedDecorations.length, 0);
|
||||
assert.equal(e.changedDecorations.length, 0);
|
||||
assert.equal(e.removedDecorations.length, 1);
|
||||
assert.equal(e.removedDecorations[0], decId);
|
||||
});
|
||||
thisModel.changeDecorations((changeAccessor) => {
|
||||
changeAccessor.removeDecoration(decId);
|
||||
});
|
||||
assert.equal(listenerCalled, 1, 'listener called');
|
||||
});
|
||||
|
||||
test('decorations emit event when inserting one line text before it', () => {
|
||||
let listenerCalled = 0;
|
||||
let decId = addDecoration(thisModel, 1, 2, 3, 2, 'myType');
|
||||
|
||||
thisModel.onDidChangeDecorations((e) => {
|
||||
listenerCalled++;
|
||||
assert.equal(e.addedDecorations.length, 0);
|
||||
assert.equal(e.changedDecorations.length, 1);
|
||||
assert.equal(e.changedDecorations[0], decId);
|
||||
assert.equal(e.removedDecorations.length, 0);
|
||||
});
|
||||
|
||||
thisModel.applyEdits([EditOperation.insert(new Position(1, 1), 'Hallo ')]);
|
||||
assert.equal(listenerCalled, 1, 'listener called');
|
||||
});
|
||||
|
||||
// --------- editing text & effects on decorations
|
||||
|
||||
test('decorations are updated when inserting one line text before it', () => {
|
||||
addDecoration(thisModel, 1, 2, 3, 2, 'myType');
|
||||
modelHasDecoration(thisModel, 1, 2, 3, 2, 'myType');
|
||||
thisModel.applyEdits([EditOperation.insert(new Position(1, 1), 'Hallo ')]);
|
||||
modelHasDecoration(thisModel, 1, 8, 3, 2, 'myType');
|
||||
});
|
||||
|
||||
test('decorations are updated when inserting one line text before it 2', () => {
|
||||
addDecoration(thisModel, 1, 1, 3, 2, 'myType');
|
||||
modelHasDecoration(thisModel, 1, 1, 3, 2, 'myType');
|
||||
thisModel.applyEdits([EditOperation.replace(new Range(1, 1, 1, 1), 'Hallo ')]);
|
||||
modelHasDecoration(thisModel, 1, 1, 3, 2, 'myType');
|
||||
});
|
||||
|
||||
test('decorations are updated when inserting multiple lines text before it', () => {
|
||||
addDecoration(thisModel, 1, 2, 3, 2, 'myType');
|
||||
modelHasDecoration(thisModel, 1, 2, 3, 2, 'myType');
|
||||
thisModel.applyEdits([EditOperation.insert(new Position(1, 1), 'Hallo\nI\'m inserting multiple\nlines')]);
|
||||
modelHasDecoration(thisModel, 3, 7, 5, 2, 'myType');
|
||||
});
|
||||
|
||||
test('decorations change when inserting text after them', () => {
|
||||
addDecoration(thisModel, 1, 2, 3, 2, 'myType');
|
||||
modelHasDecoration(thisModel, 1, 2, 3, 2, 'myType');
|
||||
thisModel.applyEdits([EditOperation.insert(new Position(3, 2), 'Hallo')]);
|
||||
modelHasDecoration(thisModel, 1, 2, 3, 7, 'myType');
|
||||
});
|
||||
|
||||
test('decorations are updated when inserting text inside', () => {
|
||||
addDecoration(thisModel, 1, 2, 3, 2, 'myType');
|
||||
modelHasDecoration(thisModel, 1, 2, 3, 2, 'myType');
|
||||
thisModel.applyEdits([EditOperation.insert(new Position(1, 3), 'Hallo ')]);
|
||||
modelHasDecoration(thisModel, 1, 2, 3, 2, 'myType');
|
||||
});
|
||||
|
||||
test('decorations are updated when inserting text inside 2', () => {
|
||||
addDecoration(thisModel, 1, 2, 3, 2, 'myType');
|
||||
modelHasDecoration(thisModel, 1, 2, 3, 2, 'myType');
|
||||
thisModel.applyEdits([EditOperation.insert(new Position(3, 1), 'Hallo ')]);
|
||||
modelHasDecoration(thisModel, 1, 2, 3, 8, 'myType');
|
||||
});
|
||||
|
||||
test('decorations are updated when inserting text inside 3', () => {
|
||||
addDecoration(thisModel, 1, 1, 2, 16, 'myType');
|
||||
modelHasDecoration(thisModel, 1, 1, 2, 16, 'myType');
|
||||
thisModel.applyEdits([EditOperation.insert(new Position(2, 2), '\n')]);
|
||||
modelHasDecoration(thisModel, 1, 1, 3, 15, 'myType');
|
||||
});
|
||||
|
||||
test('decorations are updated when inserting multiple lines text inside', () => {
|
||||
addDecoration(thisModel, 1, 2, 3, 2, 'myType');
|
||||
modelHasDecoration(thisModel, 1, 2, 3, 2, 'myType');
|
||||
thisModel.applyEdits([EditOperation.insert(new Position(1, 3), 'Hallo\nI\'m inserting multiple\nlines')]);
|
||||
modelHasDecoration(thisModel, 1, 2, 5, 2, 'myType');
|
||||
});
|
||||
|
||||
test('decorations are updated when deleting one line text before it', () => {
|
||||
addDecoration(thisModel, 1, 2, 3, 2, 'myType');
|
||||
modelHasDecoration(thisModel, 1, 2, 3, 2, 'myType');
|
||||
thisModel.applyEdits([EditOperation.delete(new Range(1, 1, 1, 2))]);
|
||||
modelHasDecoration(thisModel, 1, 1, 3, 2, 'myType');
|
||||
});
|
||||
|
||||
test('decorations are updated when deleting multiple lines text before it', () => {
|
||||
addDecoration(thisModel, 2, 2, 3, 2, 'myType');
|
||||
modelHasDecoration(thisModel, 2, 2, 3, 2, 'myType');
|
||||
thisModel.applyEdits([EditOperation.delete(new Range(1, 1, 2, 1))]);
|
||||
modelHasDecoration(thisModel, 1, 2, 2, 2, 'myType');
|
||||
});
|
||||
|
||||
test('decorations are updated when deleting multiple lines text before it 2', () => {
|
||||
addDecoration(thisModel, 2, 3, 3, 2, 'myType');
|
||||
modelHasDecoration(thisModel, 2, 3, 3, 2, 'myType');
|
||||
thisModel.applyEdits([EditOperation.delete(new Range(1, 1, 2, 2))]);
|
||||
modelHasDecoration(thisModel, 1, 2, 2, 2, 'myType');
|
||||
});
|
||||
|
||||
test('decorations are updated when deleting text inside', () => {
|
||||
addDecoration(thisModel, 1, 2, 4, 1, 'myType');
|
||||
modelHasDecoration(thisModel, 1, 2, 4, 1, 'myType');
|
||||
thisModel.applyEdits([EditOperation.delete(new Range(1, 3, 2, 1))]);
|
||||
modelHasDecoration(thisModel, 1, 2, 3, 1, 'myType');
|
||||
});
|
||||
|
||||
test('decorations are updated when deleting text inside 2', () => {
|
||||
addDecoration(thisModel, 1, 2, 4, 1, 'myType');
|
||||
modelHasDecoration(thisModel, 1, 2, 4, 1, 'myType');
|
||||
thisModel.applyEdits([
|
||||
EditOperation.delete(new Range(1, 1, 1, 2)),
|
||||
EditOperation.delete(new Range(4, 1, 4, 1))
|
||||
]);
|
||||
modelHasDecoration(thisModel, 1, 1, 4, 1, 'myType');
|
||||
});
|
||||
|
||||
test('decorations are updated when deleting multiple lines text', () => {
|
||||
addDecoration(thisModel, 1, 2, 4, 1, 'myType');
|
||||
modelHasDecoration(thisModel, 1, 2, 4, 1, 'myType');
|
||||
thisModel.applyEdits([EditOperation.delete(new Range(1, 1, 3, 1))]);
|
||||
modelHasDecoration(thisModel, 1, 1, 2, 1, 'myType');
|
||||
});
|
||||
});
|
||||
|
||||
interface ILightWeightDecoration {
|
||||
id: string;
|
||||
range: Range;
|
||||
}
|
||||
|
||||
suite('deltaDecorations', () => {
|
||||
|
||||
function decoration(id: string, startLineNumber: number, startColumn: number, endLineNumber: number, endColum: number): ILightWeightDecoration {
|
||||
return {
|
||||
id: id,
|
||||
range: new Range(startLineNumber, startColumn, endLineNumber, endColum)
|
||||
};
|
||||
}
|
||||
|
||||
function toModelDeltaDecoration(dec: ILightWeightDecoration): IModelDeltaDecoration {
|
||||
return {
|
||||
range: dec.range,
|
||||
options: {
|
||||
className: dec.id
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function strcmp(a: string, b: string): number {
|
||||
if (a === b) {
|
||||
return 0;
|
||||
}
|
||||
if (a < b) {
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
function readModelDecorations(model: Model, ids: string[]): ILightWeightDecoration[] {
|
||||
return ids.map((id) => {
|
||||
return {
|
||||
range: model.getDecorationRange(id),
|
||||
id: model.getDecorationOptions(id).className
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function testDeltaDecorations(text: string[], decorations: ILightWeightDecoration[], newDecorations: ILightWeightDecoration[]): void {
|
||||
|
||||
var model = Model.createFromString(text.join('\n'));
|
||||
|
||||
// Add initial decorations & assert they are added
|
||||
var initialIds = model.deltaDecorations([], decorations.map(toModelDeltaDecoration));
|
||||
var actualDecorations = readModelDecorations(model, initialIds);
|
||||
|
||||
assert.equal(initialIds.length, decorations.length, 'returns expected cnt of ids');
|
||||
assert.equal(initialIds.length, model.getAllDecorations().length, 'does not leak decorations');
|
||||
assert.equal(initialIds.length, model._getTrackedRangesCount(), 'does not leak tracked ranges');
|
||||
assert.equal(2 * initialIds.length, model._getMarkersCount(), 'does not leak markers');
|
||||
actualDecorations.sort((a, b) => strcmp(a.id, b.id));
|
||||
decorations.sort((a, b) => strcmp(a.id, b.id));
|
||||
assert.deepEqual(actualDecorations, decorations);
|
||||
|
||||
var newIds = model.deltaDecorations(initialIds, newDecorations.map(toModelDeltaDecoration));
|
||||
var actualNewDecorations = readModelDecorations(model, newIds);
|
||||
|
||||
assert.equal(newIds.length, newDecorations.length, 'returns expected cnt of ids');
|
||||
assert.equal(newIds.length, model.getAllDecorations().length, 'does not leak decorations');
|
||||
assert.equal(newIds.length, model._getTrackedRangesCount(), 'does not leak tracked ranges');
|
||||
assert.equal(2 * newIds.length, model._getMarkersCount(), 'does not leak markers');
|
||||
actualNewDecorations.sort((a, b) => strcmp(a.id, b.id));
|
||||
newDecorations.sort((a, b) => strcmp(a.id, b.id));
|
||||
assert.deepEqual(actualDecorations, decorations);
|
||||
|
||||
model.dispose();
|
||||
}
|
||||
|
||||
function range(startLineNumber: number, startColumn: number, endLineNumber: number, endColumn: number): Range {
|
||||
return new Range(startLineNumber, startColumn, endLineNumber, endColumn);
|
||||
}
|
||||
|
||||
test('result respects input', () => {
|
||||
var model = Model.createFromString([
|
||||
'Hello world,',
|
||||
'How are you?'
|
||||
].join('\n'));
|
||||
|
||||
var ids = model.deltaDecorations([], [
|
||||
toModelDeltaDecoration(decoration('a', 1, 1, 1, 12)),
|
||||
toModelDeltaDecoration(decoration('b', 2, 1, 2, 13))
|
||||
]);
|
||||
|
||||
assert.deepEqual(model.getDecorationRange(ids[0]), range(1, 1, 1, 12));
|
||||
assert.deepEqual(model.getDecorationRange(ids[1]), range(2, 1, 2, 13));
|
||||
|
||||
model.dispose();
|
||||
});
|
||||
|
||||
test('deltaDecorations 1', () => {
|
||||
testDeltaDecorations(
|
||||
[
|
||||
'This is a text',
|
||||
'That has multiple lines',
|
||||
'And is very friendly',
|
||||
'Towards testing'
|
||||
],
|
||||
[
|
||||
decoration('a', 1, 1, 1, 2),
|
||||
decoration('b', 1, 1, 1, 15),
|
||||
decoration('c', 1, 1, 2, 1),
|
||||
decoration('d', 1, 1, 2, 24),
|
||||
decoration('e', 2, 1, 2, 24),
|
||||
decoration('f', 2, 1, 4, 16)
|
||||
],
|
||||
[
|
||||
decoration('x', 1, 1, 1, 2),
|
||||
decoration('b', 1, 1, 1, 15),
|
||||
decoration('c', 1, 1, 2, 1),
|
||||
decoration('d', 1, 1, 2, 24),
|
||||
decoration('e', 2, 1, 2, 21),
|
||||
decoration('f', 2, 17, 4, 16)
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
test('deltaDecorations 2', () => {
|
||||
testDeltaDecorations(
|
||||
[
|
||||
'This is a text',
|
||||
'That has multiple lines',
|
||||
'And is very friendly',
|
||||
'Towards testing'
|
||||
],
|
||||
[
|
||||
decoration('a', 1, 1, 1, 2),
|
||||
decoration('b', 1, 2, 1, 3),
|
||||
decoration('c', 1, 3, 1, 4),
|
||||
decoration('d', 1, 4, 1, 5),
|
||||
decoration('e', 1, 5, 1, 6)
|
||||
],
|
||||
[
|
||||
decoration('a', 1, 2, 1, 3),
|
||||
decoration('b', 1, 3, 1, 4),
|
||||
decoration('c', 1, 4, 1, 5),
|
||||
decoration('d', 1, 5, 1, 6)
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
test('deltaDecorations 3', () => {
|
||||
testDeltaDecorations(
|
||||
[
|
||||
'This is a text',
|
||||
'That has multiple lines',
|
||||
'And is very friendly',
|
||||
'Towards testing'
|
||||
],
|
||||
[
|
||||
decoration('a', 1, 1, 1, 2),
|
||||
decoration('b', 1, 2, 1, 3),
|
||||
decoration('c', 1, 3, 1, 4),
|
||||
decoration('d', 1, 4, 1, 5),
|
||||
decoration('e', 1, 5, 1, 6)
|
||||
],
|
||||
[]
|
||||
);
|
||||
});
|
||||
|
||||
test('issue #4317: editor.setDecorations doesn\'t update the hover message', () => {
|
||||
|
||||
let model = Model.createFromString('Hello world!');
|
||||
|
||||
let ids = model.deltaDecorations([], [{
|
||||
range: {
|
||||
startLineNumber: 1,
|
||||
startColumn: 1,
|
||||
endLineNumber: 100,
|
||||
endColumn: 1
|
||||
},
|
||||
options: {
|
||||
hoverMessage: { value: 'hello1' }
|
||||
}
|
||||
}]);
|
||||
|
||||
ids = model.deltaDecorations(ids, [{
|
||||
range: {
|
||||
startLineNumber: 1,
|
||||
startColumn: 1,
|
||||
endLineNumber: 100,
|
||||
endColumn: 1
|
||||
},
|
||||
options: {
|
||||
hoverMessage: { value: 'hello2' }
|
||||
}
|
||||
}]);
|
||||
|
||||
let actualDecoration = model.getDecorationOptions(ids[0]);
|
||||
|
||||
assert.deepEqual(actualDecoration.hoverMessage, { value: 'hello2' });
|
||||
|
||||
model.dispose();
|
||||
});
|
||||
|
||||
test('model doesn\'t get confused with individual tracked ranges', () => {
|
||||
var model = Model.createFromString([
|
||||
'Hello world,',
|
||||
'How are you?'
|
||||
].join('\n'));
|
||||
|
||||
var trackedRangeId = model.changeDecorations((changeAcessor) => {
|
||||
return changeAcessor.addDecoration(
|
||||
{
|
||||
startLineNumber: 1,
|
||||
startColumn: 1,
|
||||
endLineNumber: 1,
|
||||
endColumn: 1
|
||||
}, {
|
||||
stickiness: TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges
|
||||
}
|
||||
);
|
||||
});
|
||||
model.changeDecorations((changeAccessor) => {
|
||||
changeAccessor.removeDecoration(trackedRangeId);
|
||||
});
|
||||
|
||||
var ids = model.deltaDecorations([], [
|
||||
toModelDeltaDecoration(decoration('a', 1, 1, 1, 12)),
|
||||
toModelDeltaDecoration(decoration('b', 2, 1, 2, 13))
|
||||
]);
|
||||
|
||||
assert.deepEqual(model.getDecorationRange(ids[0]), range(1, 1, 1, 12));
|
||||
assert.deepEqual(model.getDecorationRange(ids[1]), range(2, 1, 2, 13));
|
||||
|
||||
ids = model.deltaDecorations(ids, [
|
||||
toModelDeltaDecoration(decoration('a', 1, 1, 1, 12)),
|
||||
toModelDeltaDecoration(decoration('b', 2, 1, 2, 13))
|
||||
]);
|
||||
|
||||
assert.deepEqual(model.getDecorationRange(ids[0]), range(1, 1, 1, 12));
|
||||
assert.deepEqual(model.getDecorationRange(ids[1]), range(2, 1, 2, 13));
|
||||
|
||||
model.dispose();
|
||||
});
|
||||
|
||||
test('issue #16922: Clicking on link doesn\'t seem to do anything', () => {
|
||||
var model = Model.createFromString([
|
||||
'Hello world,',
|
||||
'How are you?',
|
||||
'Fine.',
|
||||
'Good.',
|
||||
].join('\n'));
|
||||
|
||||
model.deltaDecorations([], [
|
||||
{ range: new Range(1, 1, 1, 1), options: { className: '1' } },
|
||||
{ range: new Range(1, 13, 1, 13), options: { className: '2' } },
|
||||
{ range: new Range(2, 1, 2, 1), options: { className: '3' } },
|
||||
{ range: new Range(2, 1, 2, 4), options: { className: '4' } },
|
||||
{ range: new Range(2, 8, 2, 13), options: { className: '5' } },
|
||||
{ range: new Range(3, 1, 4, 6), options: { className: '6' } },
|
||||
{ range: new Range(1, 1, 3, 6), options: { className: 'x1' } },
|
||||
{ range: new Range(2, 5, 2, 8), options: { className: 'x2' } },
|
||||
{ range: new Range(1, 1, 2, 8), options: { className: 'x3' } },
|
||||
{ range: new Range(2, 5, 3, 1), options: { className: 'x4' } },
|
||||
]);
|
||||
|
||||
let inRange = model.getDecorationsInRange(new Range(2, 6, 2, 6));
|
||||
|
||||
let inRangeClassNames = inRange.map(d => d.options.className);
|
||||
inRangeClassNames.sort();
|
||||
assert.deepEqual(inRangeClassNames, ['x1', 'x2', 'x3', 'x4']);
|
||||
|
||||
model.dispose();
|
||||
});
|
||||
});
|
||||
178
src/vs/editor/test/common/model/modelEditOperation.test.ts
Normal file
178
src/vs/editor/test/common/model/modelEditOperation.test.ts
Normal file
@@ -0,0 +1,178 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { IIdentifiedSingleEditOperation } from 'vs/editor/common/editorCommon';
|
||||
import { Model } from 'vs/editor/common/model/model';
|
||||
|
||||
suite('Editor Model - Model Edit Operation', () => {
|
||||
var LINE1 = 'My First Line';
|
||||
var LINE2 = '\t\tMy Second Line';
|
||||
var LINE3 = ' Third Line';
|
||||
var LINE4 = '';
|
||||
var LINE5 = '1';
|
||||
|
||||
var model: Model;
|
||||
|
||||
setup(() => {
|
||||
var text =
|
||||
LINE1 + '\r\n' +
|
||||
LINE2 + '\n' +
|
||||
LINE3 + '\n' +
|
||||
LINE4 + '\r\n' +
|
||||
LINE5;
|
||||
model = Model.createFromString(text);
|
||||
});
|
||||
|
||||
teardown(() => {
|
||||
model.dispose();
|
||||
model = null;
|
||||
});
|
||||
|
||||
function createSingleEditOp(text: string, positionLineNumber: number, positionColumn: number, selectionLineNumber: number = positionLineNumber, selectionColumn: number = positionColumn): IIdentifiedSingleEditOperation {
|
||||
var range = new Range(
|
||||
selectionLineNumber,
|
||||
selectionColumn,
|
||||
positionLineNumber,
|
||||
positionColumn
|
||||
);
|
||||
|
||||
return {
|
||||
identifier: {
|
||||
major: 0,
|
||||
minor: 0
|
||||
},
|
||||
range: range,
|
||||
text: text,
|
||||
forceMoveMarkers: false
|
||||
};
|
||||
}
|
||||
|
||||
function assertSingleEditOp(singleEditOp: IIdentifiedSingleEditOperation, editedLines: string[]) {
|
||||
var editOp = [singleEditOp];
|
||||
|
||||
var inverseEditOp = model.applyEdits(editOp);
|
||||
|
||||
assert.equal(model.getLineCount(), editedLines.length);
|
||||
for (var i = 0; i < editedLines.length; i++) {
|
||||
assert.equal(model.getLineContent(i + 1), editedLines[i]);
|
||||
}
|
||||
|
||||
var originalOp = model.applyEdits(inverseEditOp);
|
||||
|
||||
assert.equal(model.getLineCount(), 5);
|
||||
assert.equal(model.getLineContent(1), LINE1);
|
||||
assert.equal(model.getLineContent(2), LINE2);
|
||||
assert.equal(model.getLineContent(3), LINE3);
|
||||
assert.equal(model.getLineContent(4), LINE4);
|
||||
assert.equal(model.getLineContent(5), LINE5);
|
||||
|
||||
assert.deepEqual(originalOp, editOp);
|
||||
}
|
||||
|
||||
test('Insert inline', () => {
|
||||
assertSingleEditOp(
|
||||
createSingleEditOp('a', 1, 1),
|
||||
[
|
||||
'aMy First Line',
|
||||
LINE2,
|
||||
LINE3,
|
||||
LINE4,
|
||||
LINE5
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
test('Replace inline/inline 1', () => {
|
||||
assertSingleEditOp(
|
||||
createSingleEditOp(' incredibly awesome', 1, 3),
|
||||
[
|
||||
'My incredibly awesome First Line',
|
||||
LINE2,
|
||||
LINE3,
|
||||
LINE4,
|
||||
LINE5
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
test('Replace inline/inline 2', () => {
|
||||
assertSingleEditOp(
|
||||
createSingleEditOp(' with text at the end.', 1, 14),
|
||||
[
|
||||
'My First Line with text at the end.',
|
||||
LINE2,
|
||||
LINE3,
|
||||
LINE4,
|
||||
LINE5
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
test('Replace inline/inline 3', () => {
|
||||
assertSingleEditOp(
|
||||
createSingleEditOp('My new First Line.', 1, 1, 1, 14),
|
||||
[
|
||||
'My new First Line.',
|
||||
LINE2,
|
||||
LINE3,
|
||||
LINE4,
|
||||
LINE5
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
test('Replace inline/multi line 1', () => {
|
||||
assertSingleEditOp(
|
||||
createSingleEditOp('My new First Line.', 1, 1, 3, 15),
|
||||
[
|
||||
'My new First Line.',
|
||||
LINE4,
|
||||
LINE5
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
test('Replace inline/multi line 2', () => {
|
||||
assertSingleEditOp(
|
||||
createSingleEditOp('My new First Line.', 1, 2, 3, 15),
|
||||
[
|
||||
'MMy new First Line.',
|
||||
LINE4,
|
||||
LINE5
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
test('Replace inline/multi line 3', () => {
|
||||
assertSingleEditOp(
|
||||
createSingleEditOp('My new First Line.', 1, 2, 3, 2),
|
||||
[
|
||||
'MMy new First Line. Third Line',
|
||||
LINE4,
|
||||
LINE5
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
test('Replace muli line/multi line', () => {
|
||||
assertSingleEditOp(
|
||||
createSingleEditOp('1\n2\n3\n4\n', 1, 1),
|
||||
[
|
||||
'1',
|
||||
'2',
|
||||
'3',
|
||||
'4',
|
||||
LINE1,
|
||||
LINE2,
|
||||
LINE3,
|
||||
LINE4,
|
||||
LINE5
|
||||
]
|
||||
);
|
||||
});
|
||||
});
|
||||
997
src/vs/editor/test/common/model/textModel.test.ts
Normal file
997
src/vs/editor/test/common/model/textModel.test.ts
Normal file
@@ -0,0 +1,997 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { Position } from 'vs/editor/common/core/position';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { TextModel, ITextModelCreationData } from 'vs/editor/common/model/textModel';
|
||||
import { DefaultEndOfLine, TextModelResolvedOptions } from 'vs/editor/common/editorCommon';
|
||||
import { RawTextSource } from 'vs/editor/common/model/textSource';
|
||||
|
||||
function testGuessIndentation(defaultInsertSpaces: boolean, defaultTabSize: number, expectedInsertSpaces: boolean, expectedTabSize: number, text: string[], msg?: string): void {
|
||||
var m = TextModel.createFromString(
|
||||
text.join('\n'),
|
||||
{
|
||||
tabSize: defaultTabSize,
|
||||
insertSpaces: defaultInsertSpaces,
|
||||
detectIndentation: true,
|
||||
defaultEOL: DefaultEndOfLine.LF,
|
||||
trimAutoWhitespace: true
|
||||
}
|
||||
);
|
||||
var r = m.getOptions();
|
||||
m.dispose();
|
||||
|
||||
assert.equal(r.insertSpaces, expectedInsertSpaces, msg);
|
||||
assert.equal(r.tabSize, expectedTabSize, msg);
|
||||
}
|
||||
|
||||
function assertGuess(expectedInsertSpaces: boolean, expectedTabSize: number, text: string[], msg?: string): void {
|
||||
if (typeof expectedInsertSpaces === 'undefined') {
|
||||
// cannot guess insertSpaces
|
||||
if (typeof expectedTabSize === 'undefined') {
|
||||
// cannot guess tabSize
|
||||
testGuessIndentation(true, 13370, true, 13370, text, msg);
|
||||
testGuessIndentation(false, 13371, false, 13371, text, msg);
|
||||
} else {
|
||||
// can guess tabSize
|
||||
testGuessIndentation(true, 13370, true, expectedTabSize, text, msg);
|
||||
testGuessIndentation(false, 13371, false, expectedTabSize, text, msg);
|
||||
}
|
||||
} else {
|
||||
// can guess insertSpaces
|
||||
if (typeof expectedTabSize === 'undefined') {
|
||||
// cannot guess tabSize
|
||||
testGuessIndentation(true, 13370, expectedInsertSpaces, 13370, text, msg);
|
||||
testGuessIndentation(false, 13371, expectedInsertSpaces, 13371, text, msg);
|
||||
} else {
|
||||
// can guess tabSize
|
||||
testGuessIndentation(true, 13370, expectedInsertSpaces, expectedTabSize, text, msg);
|
||||
testGuessIndentation(false, 13371, expectedInsertSpaces, expectedTabSize, text, msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suite('TextModelData.fromString', () => {
|
||||
|
||||
function testTextModelDataFromString(text: string, expected: ITextModelCreationData): void {
|
||||
const rawTextSource = RawTextSource.fromString(text);
|
||||
const actual = TextModel.resolveCreationData(rawTextSource, TextModel.DEFAULT_CREATION_OPTIONS);
|
||||
assert.deepEqual(actual, expected);
|
||||
}
|
||||
|
||||
test('one line text', () => {
|
||||
testTextModelDataFromString('Hello world!', {
|
||||
text: {
|
||||
BOM: '',
|
||||
EOL: '\n',
|
||||
length: 12,
|
||||
'lines': [
|
||||
'Hello world!'
|
||||
],
|
||||
containsRTL: false,
|
||||
isBasicASCII: true
|
||||
},
|
||||
options: new TextModelResolvedOptions({
|
||||
defaultEOL: DefaultEndOfLine.LF,
|
||||
insertSpaces: true,
|
||||
tabSize: 4,
|
||||
trimAutoWhitespace: true,
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
test('multiline text', () => {
|
||||
testTextModelDataFromString('Hello,\r\ndear friend\nHow\rare\r\nyou?', {
|
||||
text: {
|
||||
BOM: '',
|
||||
EOL: '\r\n',
|
||||
length: 33,
|
||||
'lines': [
|
||||
'Hello,',
|
||||
'dear friend',
|
||||
'How',
|
||||
'are',
|
||||
'you?'
|
||||
],
|
||||
containsRTL: false,
|
||||
isBasicASCII: true
|
||||
},
|
||||
options: new TextModelResolvedOptions({
|
||||
defaultEOL: DefaultEndOfLine.LF,
|
||||
insertSpaces: true,
|
||||
tabSize: 4,
|
||||
trimAutoWhitespace: true,
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
test('Non Basic ASCII 1', () => {
|
||||
testTextModelDataFromString('Hello,\nZürich', {
|
||||
text: {
|
||||
BOM: '',
|
||||
EOL: '\n',
|
||||
length: 13,
|
||||
'lines': [
|
||||
'Hello,',
|
||||
'Zürich'
|
||||
],
|
||||
containsRTL: false,
|
||||
isBasicASCII: false
|
||||
},
|
||||
options: new TextModelResolvedOptions({
|
||||
defaultEOL: DefaultEndOfLine.LF,
|
||||
insertSpaces: true,
|
||||
tabSize: 4,
|
||||
trimAutoWhitespace: true,
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
test('containsRTL 1', () => {
|
||||
testTextModelDataFromString('Hello,\nזוהי עובדה מבוססת שדעתו', {
|
||||
text: {
|
||||
BOM: '',
|
||||
EOL: '\n',
|
||||
length: 30,
|
||||
'lines': [
|
||||
'Hello,',
|
||||
'זוהי עובדה מבוססת שדעתו'
|
||||
],
|
||||
containsRTL: true,
|
||||
isBasicASCII: false
|
||||
},
|
||||
options: new TextModelResolvedOptions({
|
||||
defaultEOL: DefaultEndOfLine.LF,
|
||||
insertSpaces: true,
|
||||
tabSize: 4,
|
||||
trimAutoWhitespace: true,
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
test('containsRTL 2', () => {
|
||||
testTextModelDataFromString('Hello,\nهناك حقيقة مثبتة منذ زمن طويل', {
|
||||
text: {
|
||||
BOM: '',
|
||||
EOL: '\n',
|
||||
length: 36,
|
||||
'lines': [
|
||||
'Hello,',
|
||||
'هناك حقيقة مثبتة منذ زمن طويل'
|
||||
],
|
||||
containsRTL: true,
|
||||
isBasicASCII: false
|
||||
},
|
||||
options: new TextModelResolvedOptions({
|
||||
defaultEOL: DefaultEndOfLine.LF,
|
||||
insertSpaces: true,
|
||||
tabSize: 4,
|
||||
trimAutoWhitespace: true,
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
suite('Editor Model - TextModel', () => {
|
||||
|
||||
test('getValueLengthInRange', () => {
|
||||
|
||||
var m = TextModel.createFromString('My First Line\r\nMy Second Line\r\nMy Third Line');
|
||||
assert.equal(m.getValueLengthInRange(new Range(1, 1, 1, 1)), ''.length);
|
||||
assert.equal(m.getValueLengthInRange(new Range(1, 1, 1, 2)), 'M'.length);
|
||||
assert.equal(m.getValueLengthInRange(new Range(1, 2, 1, 3)), 'y'.length);
|
||||
assert.equal(m.getValueLengthInRange(new Range(1, 1, 1, 14)), 'My First Line'.length);
|
||||
assert.equal(m.getValueLengthInRange(new Range(1, 1, 2, 1)), 'My First Line\r\n'.length);
|
||||
assert.equal(m.getValueLengthInRange(new Range(1, 2, 2, 1)), 'y First Line\r\n'.length);
|
||||
assert.equal(m.getValueLengthInRange(new Range(1, 2, 2, 2)), 'y First Line\r\nM'.length);
|
||||
assert.equal(m.getValueLengthInRange(new Range(1, 2, 2, 1000)), 'y First Line\r\nMy Second Line'.length);
|
||||
assert.equal(m.getValueLengthInRange(new Range(1, 2, 3, 1)), 'y First Line\r\nMy Second Line\r\n'.length);
|
||||
assert.equal(m.getValueLengthInRange(new Range(1, 2, 3, 1000)), 'y First Line\r\nMy Second Line\r\nMy Third Line'.length);
|
||||
assert.equal(m.getValueLengthInRange(new Range(1, 1, 1000, 1000)), 'My First Line\r\nMy Second Line\r\nMy Third Line'.length);
|
||||
|
||||
m = TextModel.createFromString('My First Line\nMy Second Line\nMy Third Line');
|
||||
assert.equal(m.getValueLengthInRange(new Range(1, 1, 1, 1)), ''.length);
|
||||
assert.equal(m.getValueLengthInRange(new Range(1, 1, 1, 2)), 'M'.length);
|
||||
assert.equal(m.getValueLengthInRange(new Range(1, 2, 1, 3)), 'y'.length);
|
||||
assert.equal(m.getValueLengthInRange(new Range(1, 1, 1, 14)), 'My First Line'.length);
|
||||
assert.equal(m.getValueLengthInRange(new Range(1, 1, 2, 1)), 'My First Line\n'.length);
|
||||
assert.equal(m.getValueLengthInRange(new Range(1, 2, 2, 1)), 'y First Line\n'.length);
|
||||
assert.equal(m.getValueLengthInRange(new Range(1, 2, 2, 2)), 'y First Line\nM'.length);
|
||||
assert.equal(m.getValueLengthInRange(new Range(1, 2, 2, 1000)), 'y First Line\nMy Second Line'.length);
|
||||
assert.equal(m.getValueLengthInRange(new Range(1, 2, 3, 1)), 'y First Line\nMy Second Line\n'.length);
|
||||
assert.equal(m.getValueLengthInRange(new Range(1, 2, 3, 1000)), 'y First Line\nMy Second Line\nMy Third Line'.length);
|
||||
assert.equal(m.getValueLengthInRange(new Range(1, 1, 1000, 1000)), 'My First Line\nMy Second Line\nMy Third Line'.length);
|
||||
});
|
||||
|
||||
test('guess indentation 1', () => {
|
||||
|
||||
assertGuess(undefined, undefined, [
|
||||
'x',
|
||||
'x',
|
||||
'x',
|
||||
'x',
|
||||
'x',
|
||||
'x',
|
||||
'x'
|
||||
], 'no clues');
|
||||
|
||||
assertGuess(false, undefined, [
|
||||
'\tx',
|
||||
'x',
|
||||
'x',
|
||||
'x',
|
||||
'x',
|
||||
'x',
|
||||
'x'
|
||||
], 'no spaces, 1xTAB');
|
||||
|
||||
assertGuess(true, 2, [
|
||||
' x',
|
||||
'x',
|
||||
'x',
|
||||
'x',
|
||||
'x',
|
||||
'x',
|
||||
'x'
|
||||
], '1x2');
|
||||
|
||||
assertGuess(false, undefined, [
|
||||
'\tx',
|
||||
'\tx',
|
||||
'\tx',
|
||||
'\tx',
|
||||
'\tx',
|
||||
'\tx',
|
||||
'\tx'
|
||||
], '7xTAB');
|
||||
|
||||
assertGuess(undefined, 2, [
|
||||
'\tx',
|
||||
' x',
|
||||
'\tx',
|
||||
' x',
|
||||
'\tx',
|
||||
' x',
|
||||
'\tx',
|
||||
' x',
|
||||
], '4x2, 4xTAB');
|
||||
assertGuess(false, undefined, [
|
||||
'\tx',
|
||||
' x',
|
||||
'\tx',
|
||||
' x',
|
||||
'\tx',
|
||||
' x',
|
||||
'\tx',
|
||||
' x'
|
||||
], '4x1, 4xTAB');
|
||||
assertGuess(false, 2, [
|
||||
'\tx',
|
||||
'\tx',
|
||||
' x',
|
||||
'\tx',
|
||||
' x',
|
||||
'\tx',
|
||||
' x',
|
||||
'\tx',
|
||||
' x',
|
||||
], '4x2, 5xTAB');
|
||||
assertGuess(false, 2, [
|
||||
'\tx',
|
||||
'\tx',
|
||||
'x',
|
||||
'\tx',
|
||||
'x',
|
||||
'\tx',
|
||||
'x',
|
||||
'\tx',
|
||||
' x',
|
||||
], '1x2, 5xTAB');
|
||||
assertGuess(false, 4, [
|
||||
'\tx',
|
||||
'\tx',
|
||||
'x',
|
||||
'\tx',
|
||||
'x',
|
||||
'\tx',
|
||||
'x',
|
||||
'\tx',
|
||||
' x',
|
||||
], '1x4, 5xTAB');
|
||||
assertGuess(false, 2, [
|
||||
'\tx',
|
||||
'\tx',
|
||||
'x',
|
||||
'\tx',
|
||||
'x',
|
||||
'\tx',
|
||||
' x',
|
||||
'\tx',
|
||||
' x',
|
||||
], '1x2, 1x4, 5xTAB');
|
||||
|
||||
assertGuess(undefined, undefined, [
|
||||
'x',
|
||||
' x',
|
||||
' x',
|
||||
' x',
|
||||
' x',
|
||||
' x',
|
||||
' x',
|
||||
' x'
|
||||
], '7x1 - 1 space is never guessed as an indentation');
|
||||
assertGuess(true, undefined, [
|
||||
'x',
|
||||
' x',
|
||||
' x',
|
||||
' x',
|
||||
' x',
|
||||
' x',
|
||||
' x',
|
||||
' x'
|
||||
], '1x10, 6x1');
|
||||
assertGuess(undefined, undefined, [
|
||||
'',
|
||||
' ',
|
||||
' ',
|
||||
' ',
|
||||
' ',
|
||||
' ',
|
||||
' ',
|
||||
' ',
|
||||
], 'whitespace lines don\'t count');
|
||||
assertGuess(true, 4, [
|
||||
'x',
|
||||
' x',
|
||||
' x',
|
||||
' x',
|
||||
'x',
|
||||
' x',
|
||||
' x',
|
||||
' x',
|
||||
'x',
|
||||
' x',
|
||||
' x',
|
||||
' x',
|
||||
], 'odd number is not allowed: 6x3, 3x4');
|
||||
assertGuess(true, 4, [
|
||||
'x',
|
||||
' x',
|
||||
' x',
|
||||
' x',
|
||||
'x',
|
||||
' x',
|
||||
' x',
|
||||
' x',
|
||||
'x',
|
||||
' x',
|
||||
' x',
|
||||
' x',
|
||||
], 'odd number is not allowed: 6x5, 3x4');
|
||||
assertGuess(true, 4, [
|
||||
'x',
|
||||
' x',
|
||||
' x',
|
||||
' x',
|
||||
'x',
|
||||
' x',
|
||||
' x',
|
||||
' x',
|
||||
'x',
|
||||
' x',
|
||||
' x',
|
||||
' x',
|
||||
], 'odd number is not allowed: 6x7, 3x4');
|
||||
assertGuess(true, 2, [
|
||||
'x',
|
||||
' x',
|
||||
' x',
|
||||
' x',
|
||||
' x',
|
||||
'x',
|
||||
' x',
|
||||
' x',
|
||||
' x',
|
||||
' x',
|
||||
], '8x2');
|
||||
|
||||
assertGuess(true, 2, [
|
||||
'x',
|
||||
' x',
|
||||
' x',
|
||||
'x',
|
||||
' x',
|
||||
' x',
|
||||
'x',
|
||||
' x',
|
||||
' x',
|
||||
'x',
|
||||
' x',
|
||||
' x',
|
||||
], '8x2');
|
||||
assertGuess(true, 2, [
|
||||
'x',
|
||||
' x',
|
||||
' x',
|
||||
'x',
|
||||
' x',
|
||||
' x',
|
||||
'x',
|
||||
' x',
|
||||
' x',
|
||||
'x',
|
||||
' x',
|
||||
' x',
|
||||
], '4x2, 4x4');
|
||||
assertGuess(true, 2, [
|
||||
'x',
|
||||
' x',
|
||||
' x',
|
||||
' x',
|
||||
'x',
|
||||
' x',
|
||||
' x',
|
||||
' x',
|
||||
'x',
|
||||
' x',
|
||||
' x',
|
||||
' x',
|
||||
], '6x2, 3x4');
|
||||
assertGuess(true, 2, [
|
||||
'x',
|
||||
' x',
|
||||
' x',
|
||||
' x',
|
||||
' x',
|
||||
'x',
|
||||
' x',
|
||||
' x',
|
||||
' x',
|
||||
' x',
|
||||
], '4x2, 4x4');
|
||||
assertGuess(true, 2, [
|
||||
'x',
|
||||
' x',
|
||||
' x',
|
||||
' x',
|
||||
'x',
|
||||
' x',
|
||||
' x',
|
||||
' x',
|
||||
], '2x2, 4x4');
|
||||
assertGuess(true, 4, [
|
||||
'x',
|
||||
' x',
|
||||
' x',
|
||||
'x',
|
||||
' x',
|
||||
' x',
|
||||
'x',
|
||||
' x',
|
||||
' x',
|
||||
'x',
|
||||
' x',
|
||||
' x',
|
||||
], '8x4');
|
||||
assertGuess(true, 2, [
|
||||
'x',
|
||||
' x',
|
||||
' x',
|
||||
' x',
|
||||
' x',
|
||||
'x',
|
||||
' x',
|
||||
' x',
|
||||
' x',
|
||||
' x',
|
||||
], '2x2, 4x4, 2x6');
|
||||
assertGuess(true, 2, [
|
||||
'x',
|
||||
' x',
|
||||
' x',
|
||||
' x',
|
||||
' x',
|
||||
' x',
|
||||
' x',
|
||||
], '1x2, 2x4, 2x6, 1x8');
|
||||
assertGuess(true, 4, [
|
||||
'x',
|
||||
' x',
|
||||
' x',
|
||||
' x',
|
||||
' x',
|
||||
' x',
|
||||
'x',
|
||||
' x',
|
||||
' x',
|
||||
' x',
|
||||
' x',
|
||||
' x',
|
||||
], '6x4, 2x5, 2x8');
|
||||
assertGuess(true, 4, [
|
||||
'x',
|
||||
' x',
|
||||
' x',
|
||||
' x',
|
||||
' x',
|
||||
' x',
|
||||
' x',
|
||||
], '3x4, 1x5, 2x8');
|
||||
assertGuess(true, 4, [
|
||||
'x',
|
||||
'x',
|
||||
' x',
|
||||
' x',
|
||||
' x',
|
||||
' x',
|
||||
' x',
|
||||
'x',
|
||||
'x',
|
||||
' x',
|
||||
' x',
|
||||
' x',
|
||||
' x',
|
||||
' x',
|
||||
], '6x4, 2x5, 4x8');
|
||||
assertGuess(true, 4, [
|
||||
'x',
|
||||
' x',
|
||||
' x',
|
||||
' x',
|
||||
' x',
|
||||
' x',
|
||||
'x',
|
||||
' x',
|
||||
' x',
|
||||
' x',
|
||||
], '5x1, 2x0, 1x3, 2x4');
|
||||
assertGuess(false, undefined, [
|
||||
'\t x',
|
||||
' \t x',
|
||||
'\tx'
|
||||
], 'mixed whitespace 1');
|
||||
assertGuess(false, 4, [
|
||||
'\tx',
|
||||
'\t x'
|
||||
], 'mixed whitespace 2');
|
||||
});
|
||||
|
||||
test('validatePosition', () => {
|
||||
|
||||
let m = TextModel.createFromString('line one\nline two');
|
||||
|
||||
assert.deepEqual(m.validatePosition(new Position(0, 0)), new Position(1, 1));
|
||||
assert.deepEqual(m.validatePosition(new Position(0, 1)), new Position(1, 1));
|
||||
|
||||
assert.deepEqual(m.validatePosition(new Position(1, 1)), new Position(1, 1));
|
||||
assert.deepEqual(m.validatePosition(new Position(1, 2)), new Position(1, 2));
|
||||
assert.deepEqual(m.validatePosition(new Position(1, 30)), new Position(1, 9));
|
||||
|
||||
assert.deepEqual(m.validatePosition(new Position(2, 0)), new Position(2, 1));
|
||||
assert.deepEqual(m.validatePosition(new Position(2, 1)), new Position(2, 1));
|
||||
assert.deepEqual(m.validatePosition(new Position(2, 2)), new Position(2, 2));
|
||||
assert.deepEqual(m.validatePosition(new Position(2, 30)), new Position(2, 9));
|
||||
|
||||
assert.deepEqual(m.validatePosition(new Position(3, 0)), new Position(2, 9));
|
||||
assert.deepEqual(m.validatePosition(new Position(3, 1)), new Position(2, 9));
|
||||
assert.deepEqual(m.validatePosition(new Position(3, 30)), new Position(2, 9));
|
||||
|
||||
assert.deepEqual(m.validatePosition(new Position(30, 30)), new Position(2, 9));
|
||||
|
||||
assert.deepEqual(m.validatePosition(new Position(-123.123, -0.5)), new Position(1, 1));
|
||||
assert.deepEqual(m.validatePosition(new Position(Number.MIN_VALUE, Number.MIN_VALUE)), new Position(1, 1));
|
||||
|
||||
assert.deepEqual(m.validatePosition(new Position(Number.MAX_VALUE, Number.MAX_VALUE)), new Position(2, 9));
|
||||
assert.deepEqual(m.validatePosition(new Position(123.23, 47.5)), new Position(2, 9));
|
||||
});
|
||||
|
||||
test('validatePosition around high-low surrogate pairs 1', () => {
|
||||
|
||||
let m = TextModel.createFromString('a📚b');
|
||||
|
||||
assert.deepEqual(m.validatePosition(new Position(0, 0)), new Position(1, 1));
|
||||
assert.deepEqual(m.validatePosition(new Position(0, 1)), new Position(1, 1));
|
||||
assert.deepEqual(m.validatePosition(new Position(0, 7)), new Position(1, 1));
|
||||
|
||||
assert.deepEqual(m.validatePosition(new Position(1, 1)), new Position(1, 1));
|
||||
assert.deepEqual(m.validatePosition(new Position(1, 2)), new Position(1, 2));
|
||||
assert.deepEqual(m.validatePosition(new Position(1, 3)), new Position(1, 2));
|
||||
assert.deepEqual(m.validatePosition(new Position(1, 4)), new Position(1, 4));
|
||||
assert.deepEqual(m.validatePosition(new Position(1, 5)), new Position(1, 5));
|
||||
assert.deepEqual(m.validatePosition(new Position(1, 30)), new Position(1, 5));
|
||||
|
||||
assert.deepEqual(m.validatePosition(new Position(2, 0)), new Position(1, 5));
|
||||
assert.deepEqual(m.validatePosition(new Position(2, 1)), new Position(1, 5));
|
||||
assert.deepEqual(m.validatePosition(new Position(2, 2)), new Position(1, 5));
|
||||
assert.deepEqual(m.validatePosition(new Position(2, 30)), new Position(1, 5));
|
||||
|
||||
assert.deepEqual(m.validatePosition(new Position(-123.123, -0.5)), new Position(1, 1));
|
||||
assert.deepEqual(m.validatePosition(new Position(Number.MIN_VALUE, Number.MIN_VALUE)), new Position(1, 1));
|
||||
|
||||
assert.deepEqual(m.validatePosition(new Position(Number.MAX_VALUE, Number.MAX_VALUE)), new Position(1, 5));
|
||||
assert.deepEqual(m.validatePosition(new Position(123.23, 47.5)), new Position(1, 5));
|
||||
});
|
||||
|
||||
test('validatePosition around high-low surrogate pairs 2', () => {
|
||||
|
||||
let m = TextModel.createFromString('a📚📚b');
|
||||
|
||||
assert.deepEqual(m.validatePosition(new Position(1, 1)), new Position(1, 1));
|
||||
assert.deepEqual(m.validatePosition(new Position(1, 2)), new Position(1, 2));
|
||||
assert.deepEqual(m.validatePosition(new Position(1, 3)), new Position(1, 2));
|
||||
assert.deepEqual(m.validatePosition(new Position(1, 4)), new Position(1, 4));
|
||||
assert.deepEqual(m.validatePosition(new Position(1, 5)), new Position(1, 4));
|
||||
assert.deepEqual(m.validatePosition(new Position(1, 6)), new Position(1, 6));
|
||||
assert.deepEqual(m.validatePosition(new Position(1, 7)), new Position(1, 7));
|
||||
|
||||
});
|
||||
|
||||
test('validateRange around high-low surrogate pairs 1', () => {
|
||||
|
||||
let m = TextModel.createFromString('a📚b');
|
||||
|
||||
assert.deepEqual(m.validateRange(new Range(0, 0, 0, 1)), new Range(1, 1, 1, 1));
|
||||
assert.deepEqual(m.validateRange(new Range(0, 0, 0, 7)), new Range(1, 1, 1, 1));
|
||||
|
||||
assert.deepEqual(m.validateRange(new Range(1, 1, 1, 1)), new Range(1, 1, 1, 1));
|
||||
assert.deepEqual(m.validateRange(new Range(1, 1, 1, 2)), new Range(1, 1, 1, 2));
|
||||
assert.deepEqual(m.validateRange(new Range(1, 1, 1, 3)), new Range(1, 1, 1, 4));
|
||||
assert.deepEqual(m.validateRange(new Range(1, 1, 1, 4)), new Range(1, 1, 1, 4));
|
||||
assert.deepEqual(m.validateRange(new Range(1, 1, 1, 5)), new Range(1, 1, 1, 5));
|
||||
|
||||
assert.deepEqual(m.validateRange(new Range(1, 2, 1, 2)), new Range(1, 2, 1, 2));
|
||||
assert.deepEqual(m.validateRange(new Range(1, 2, 1, 3)), new Range(1, 2, 1, 4));
|
||||
assert.deepEqual(m.validateRange(new Range(1, 2, 1, 4)), new Range(1, 2, 1, 4));
|
||||
assert.deepEqual(m.validateRange(new Range(1, 2, 1, 5)), new Range(1, 2, 1, 5));
|
||||
|
||||
assert.deepEqual(m.validateRange(new Range(1, 3, 1, 3)), new Range(1, 2, 1, 2));
|
||||
assert.deepEqual(m.validateRange(new Range(1, 3, 1, 4)), new Range(1, 2, 1, 4));
|
||||
assert.deepEqual(m.validateRange(new Range(1, 3, 1, 5)), new Range(1, 2, 1, 5));
|
||||
|
||||
assert.deepEqual(m.validateRange(new Range(1, 4, 1, 4)), new Range(1, 4, 1, 4));
|
||||
assert.deepEqual(m.validateRange(new Range(1, 4, 1, 5)), new Range(1, 4, 1, 5));
|
||||
|
||||
assert.deepEqual(m.validateRange(new Range(1, 5, 1, 5)), new Range(1, 5, 1, 5));
|
||||
});
|
||||
|
||||
test('validateRange around high-low surrogate pairs 2', () => {
|
||||
|
||||
let m = TextModel.createFromString('a📚📚b');
|
||||
|
||||
assert.deepEqual(m.validateRange(new Range(0, 0, 0, 1)), new Range(1, 1, 1, 1));
|
||||
assert.deepEqual(m.validateRange(new Range(0, 0, 0, 7)), new Range(1, 1, 1, 1));
|
||||
|
||||
assert.deepEqual(m.validateRange(new Range(1, 1, 1, 1)), new Range(1, 1, 1, 1));
|
||||
assert.deepEqual(m.validateRange(new Range(1, 1, 1, 2)), new Range(1, 1, 1, 2));
|
||||
assert.deepEqual(m.validateRange(new Range(1, 1, 1, 3)), new Range(1, 1, 1, 4));
|
||||
assert.deepEqual(m.validateRange(new Range(1, 1, 1, 4)), new Range(1, 1, 1, 4));
|
||||
assert.deepEqual(m.validateRange(new Range(1, 1, 1, 5)), new Range(1, 1, 1, 6));
|
||||
assert.deepEqual(m.validateRange(new Range(1, 1, 1, 6)), new Range(1, 1, 1, 6));
|
||||
assert.deepEqual(m.validateRange(new Range(1, 1, 1, 7)), new Range(1, 1, 1, 7));
|
||||
|
||||
assert.deepEqual(m.validateRange(new Range(1, 2, 1, 2)), new Range(1, 2, 1, 2));
|
||||
assert.deepEqual(m.validateRange(new Range(1, 2, 1, 3)), new Range(1, 2, 1, 4));
|
||||
assert.deepEqual(m.validateRange(new Range(1, 2, 1, 4)), new Range(1, 2, 1, 4));
|
||||
assert.deepEqual(m.validateRange(new Range(1, 2, 1, 5)), new Range(1, 2, 1, 6));
|
||||
assert.deepEqual(m.validateRange(new Range(1, 2, 1, 6)), new Range(1, 2, 1, 6));
|
||||
assert.deepEqual(m.validateRange(new Range(1, 2, 1, 7)), new Range(1, 2, 1, 7));
|
||||
|
||||
assert.deepEqual(m.validateRange(new Range(1, 3, 1, 3)), new Range(1, 2, 1, 2));
|
||||
assert.deepEqual(m.validateRange(new Range(1, 3, 1, 4)), new Range(1, 2, 1, 4));
|
||||
assert.deepEqual(m.validateRange(new Range(1, 3, 1, 5)), new Range(1, 2, 1, 6));
|
||||
assert.deepEqual(m.validateRange(new Range(1, 3, 1, 6)), new Range(1, 2, 1, 6));
|
||||
assert.deepEqual(m.validateRange(new Range(1, 3, 1, 7)), new Range(1, 2, 1, 7));
|
||||
|
||||
assert.deepEqual(m.validateRange(new Range(1, 4, 1, 4)), new Range(1, 4, 1, 4));
|
||||
assert.deepEqual(m.validateRange(new Range(1, 4, 1, 5)), new Range(1, 4, 1, 6));
|
||||
assert.deepEqual(m.validateRange(new Range(1, 4, 1, 6)), new Range(1, 4, 1, 6));
|
||||
assert.deepEqual(m.validateRange(new Range(1, 4, 1, 7)), new Range(1, 4, 1, 7));
|
||||
|
||||
assert.deepEqual(m.validateRange(new Range(1, 5, 1, 5)), new Range(1, 4, 1, 4));
|
||||
assert.deepEqual(m.validateRange(new Range(1, 5, 1, 6)), new Range(1, 4, 1, 6));
|
||||
assert.deepEqual(m.validateRange(new Range(1, 5, 1, 7)), new Range(1, 4, 1, 7));
|
||||
|
||||
assert.deepEqual(m.validateRange(new Range(1, 6, 1, 6)), new Range(1, 6, 1, 6));
|
||||
assert.deepEqual(m.validateRange(new Range(1, 6, 1, 7)), new Range(1, 6, 1, 7));
|
||||
|
||||
assert.deepEqual(m.validateRange(new Range(1, 7, 1, 7)), new Range(1, 7, 1, 7));
|
||||
});
|
||||
|
||||
test('modifyPosition', () => {
|
||||
|
||||
var m = TextModel.createFromString('line one\nline two');
|
||||
assert.deepEqual(m.modifyPosition(new Position(1, 1), 0), new Position(1, 1));
|
||||
assert.deepEqual(m.modifyPosition(new Position(0, 0), 0), new Position(1, 1));
|
||||
assert.deepEqual(m.modifyPosition(new Position(30, 1), 0), new Position(2, 9));
|
||||
|
||||
assert.deepEqual(m.modifyPosition(new Position(1, 1), 17), new Position(2, 9));
|
||||
assert.deepEqual(m.modifyPosition(new Position(1, 1), 1), new Position(1, 2));
|
||||
assert.deepEqual(m.modifyPosition(new Position(1, 1), 3), new Position(1, 4));
|
||||
assert.deepEqual(m.modifyPosition(new Position(1, 2), 10), new Position(2, 3));
|
||||
assert.deepEqual(m.modifyPosition(new Position(1, 5), 13), new Position(2, 9));
|
||||
assert.deepEqual(m.modifyPosition(new Position(1, 2), 16), new Position(2, 9));
|
||||
|
||||
assert.deepEqual(m.modifyPosition(new Position(2, 9), -17), new Position(1, 1));
|
||||
assert.deepEqual(m.modifyPosition(new Position(1, 2), -1), new Position(1, 1));
|
||||
assert.deepEqual(m.modifyPosition(new Position(1, 4), -3), new Position(1, 1));
|
||||
assert.deepEqual(m.modifyPosition(new Position(2, 3), -10), new Position(1, 2));
|
||||
assert.deepEqual(m.modifyPosition(new Position(2, 9), -13), new Position(1, 5));
|
||||
assert.deepEqual(m.modifyPosition(new Position(2, 9), -16), new Position(1, 2));
|
||||
|
||||
assert.deepEqual(m.modifyPosition(new Position(1, 2), 17), new Position(2, 9));
|
||||
assert.deepEqual(m.modifyPosition(new Position(1, 2), 100), new Position(2, 9));
|
||||
|
||||
assert.deepEqual(m.modifyPosition(new Position(1, 2), -2), new Position(1, 1));
|
||||
assert.deepEqual(m.modifyPosition(new Position(1, 2), -100), new Position(1, 1));
|
||||
assert.deepEqual(m.modifyPosition(new Position(2, 2), -100), new Position(1, 1));
|
||||
assert.deepEqual(m.modifyPosition(new Position(2, 9), -18), new Position(1, 1));
|
||||
});
|
||||
|
||||
test('normalizeIndentation 1', () => {
|
||||
let model = TextModel.createFromString('',
|
||||
{
|
||||
detectIndentation: false,
|
||||
tabSize: 4,
|
||||
insertSpaces: false,
|
||||
trimAutoWhitespace: true,
|
||||
defaultEOL: DefaultEndOfLine.LF
|
||||
}
|
||||
);
|
||||
|
||||
assert.equal(model.normalizeIndentation('\t'), '\t');
|
||||
assert.equal(model.normalizeIndentation(' '), '\t');
|
||||
assert.equal(model.normalizeIndentation(' '), ' ');
|
||||
assert.equal(model.normalizeIndentation(' '), ' ');
|
||||
assert.equal(model.normalizeIndentation(' '), ' ');
|
||||
assert.equal(model.normalizeIndentation(''), '');
|
||||
assert.equal(model.normalizeIndentation(' \t '), '\t\t');
|
||||
assert.equal(model.normalizeIndentation(' \t '), '\t ');
|
||||
assert.equal(model.normalizeIndentation(' \t '), '\t ');
|
||||
assert.equal(model.normalizeIndentation(' \t'), '\t ');
|
||||
|
||||
assert.equal(model.normalizeIndentation('\ta'), '\ta');
|
||||
assert.equal(model.normalizeIndentation(' a'), '\ta');
|
||||
assert.equal(model.normalizeIndentation(' a'), ' a');
|
||||
assert.equal(model.normalizeIndentation(' a'), ' a');
|
||||
assert.equal(model.normalizeIndentation(' a'), ' a');
|
||||
assert.equal(model.normalizeIndentation('a'), 'a');
|
||||
assert.equal(model.normalizeIndentation(' \t a'), '\t\ta');
|
||||
assert.equal(model.normalizeIndentation(' \t a'), '\t a');
|
||||
assert.equal(model.normalizeIndentation(' \t a'), '\t a');
|
||||
assert.equal(model.normalizeIndentation(' \ta'), '\t a');
|
||||
|
||||
model.dispose();
|
||||
});
|
||||
|
||||
test('normalizeIndentation 2', () => {
|
||||
let model = TextModel.createFromString('',
|
||||
{
|
||||
detectIndentation: false,
|
||||
tabSize: 4,
|
||||
insertSpaces: true,
|
||||
trimAutoWhitespace: true,
|
||||
defaultEOL: DefaultEndOfLine.LF
|
||||
}
|
||||
);
|
||||
|
||||
assert.equal(model.normalizeIndentation('\ta'), ' a');
|
||||
assert.equal(model.normalizeIndentation(' a'), ' a');
|
||||
assert.equal(model.normalizeIndentation(' a'), ' a');
|
||||
assert.equal(model.normalizeIndentation(' a'), ' a');
|
||||
assert.equal(model.normalizeIndentation(' a'), ' a');
|
||||
assert.equal(model.normalizeIndentation('a'), 'a');
|
||||
assert.equal(model.normalizeIndentation(' \t a'), ' a');
|
||||
assert.equal(model.normalizeIndentation(' \t a'), ' a');
|
||||
assert.equal(model.normalizeIndentation(' \t a'), ' a');
|
||||
assert.equal(model.normalizeIndentation(' \ta'), ' a');
|
||||
|
||||
model.dispose();
|
||||
});
|
||||
});
|
||||
|
||||
suite('TextModel.mightContainRTL', () => {
|
||||
|
||||
test('nope', () => {
|
||||
let model = TextModel.createFromString('hello world!');
|
||||
assert.equal(model.mightContainRTL(), false);
|
||||
});
|
||||
|
||||
test('yes', () => {
|
||||
let model = TextModel.createFromString('Hello,\nזוהי עובדה מבוססת שדעתו');
|
||||
assert.equal(model.mightContainRTL(), true);
|
||||
});
|
||||
|
||||
test('setValue resets 1', () => {
|
||||
let model = TextModel.createFromString('hello world!');
|
||||
assert.equal(model.mightContainRTL(), false);
|
||||
model.setValue('Hello,\nזוהי עובדה מבוססת שדעתו');
|
||||
assert.equal(model.mightContainRTL(), true);
|
||||
});
|
||||
|
||||
test('setValue resets 2', () => {
|
||||
let model = TextModel.createFromString('Hello,\nهناك حقيقة مثبتة منذ زمن طويل');
|
||||
assert.equal(model.mightContainRTL(), true);
|
||||
model.setValue('hello world!');
|
||||
assert.equal(model.mightContainRTL(), false);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
suite('TextModel.getLineIndentGuide', () => {
|
||||
function assertIndentGuides(lines: [number, string][]): void {
|
||||
let text = lines.map(l => l[1]).join('\n');
|
||||
let model = TextModel.createFromString(text);
|
||||
|
||||
let actual: [number, string][] = [];
|
||||
for (let line = 1; line <= model.getLineCount(); line++) {
|
||||
actual[line - 1] = [model.getLineIndentGuide(line), model.getLineContent(line)];
|
||||
}
|
||||
|
||||
// let expected = lines.map(l => l[0]);
|
||||
|
||||
assert.deepEqual(actual, lines);
|
||||
|
||||
model.dispose();
|
||||
}
|
||||
|
||||
test('getLineIndentGuide one level', () => {
|
||||
assertIndentGuides([
|
||||
[0, 'A'],
|
||||
[1, ' A'],
|
||||
[1, ' A'],
|
||||
[1, ' A'],
|
||||
]);
|
||||
});
|
||||
|
||||
test('getLineIndentGuide two levels', () => {
|
||||
assertIndentGuides([
|
||||
[0, 'A'],
|
||||
[1, ' A'],
|
||||
[1, ' A'],
|
||||
[1, ' A'],
|
||||
[1, ' A'],
|
||||
]);
|
||||
});
|
||||
|
||||
test('getLineIndentGuide three levels', () => {
|
||||
assertIndentGuides([
|
||||
[0, 'A'],
|
||||
[1, ' A'],
|
||||
[1, ' A'],
|
||||
[2, ' A'],
|
||||
[0, 'A'],
|
||||
]);
|
||||
});
|
||||
|
||||
test('getLineIndentGuide decreasing indent', () => {
|
||||
assertIndentGuides([
|
||||
[0, ' A'],
|
||||
[0, ' A'],
|
||||
[0, 'A'],
|
||||
]);
|
||||
});
|
||||
|
||||
test('getLineIndentGuide Java', () => {
|
||||
assertIndentGuides([
|
||||
/* 1*/[0, 'class A {'],
|
||||
/* 2*/[1, ' void foo() {'],
|
||||
/* 3*/[1, ' console.log(1);'],
|
||||
/* 4*/[1, ' console.log(2);'],
|
||||
/* 5*/[1, ' }'],
|
||||
/* 6*/[1, ''],
|
||||
/* 7*/[1, ' void bar() {'],
|
||||
/* 8*/[1, ' console.log(3);'],
|
||||
/* 9*/[1, ' }'],
|
||||
/*10*/[0, '}'],
|
||||
/*11*/[0, 'interface B {'],
|
||||
/*12*/[1, ' void bar();'],
|
||||
/*13*/[0, '}'],
|
||||
]);
|
||||
});
|
||||
|
||||
test('getLineIndentGuide Javadoc', () => {
|
||||
assertIndentGuides([
|
||||
[0, '/**'],
|
||||
[1, ' * Comment'],
|
||||
[1, ' */'],
|
||||
[0, 'class A {'],
|
||||
[1, ' void foo() {'],
|
||||
[1, ' }'],
|
||||
[0, '}'],
|
||||
]);
|
||||
});
|
||||
|
||||
test('getLineIndentGuide Whitespace', () => {
|
||||
assertIndentGuides([
|
||||
[0, 'class A {'],
|
||||
[1, ''],
|
||||
[1, ' void foo() {'],
|
||||
[1, ' '],
|
||||
[1, ' return 1;'],
|
||||
[1, ' }'],
|
||||
[1, ' '],
|
||||
[0, '}'],
|
||||
]);
|
||||
});
|
||||
|
||||
test('getLineIndentGuide Tabs', () => {
|
||||
assertIndentGuides([
|
||||
[0, 'class A {'],
|
||||
[1, '\t\t'],
|
||||
[1, '\tvoid foo() {'],
|
||||
[2, '\t \t//hello'],
|
||||
[2, '\t return 2;'],
|
||||
[1, ' \t}'],
|
||||
[1, ' '],
|
||||
[0, '}'],
|
||||
]);
|
||||
});
|
||||
|
||||
test('getLineIndentGuide checker.ts', () => {
|
||||
assertIndentGuides([
|
||||
/* 1*/[0, '/// <reference path="binder.ts"/>'],
|
||||
/* 2*/[0, ''],
|
||||
/* 3*/[0, '/* @internal */'],
|
||||
/* 4*/[0, 'namespace ts {'],
|
||||
/* 5*/[1, ' let nextSymbolId = 1;'],
|
||||
/* 6*/[1, ' let nextNodeId = 1;'],
|
||||
/* 7*/[1, ' let nextMergeId = 1;'],
|
||||
/* 8*/[1, ' let nextFlowId = 1;'],
|
||||
/* 9*/[1, ''],
|
||||
/*10*/[1, ' export function getNodeId(node: Node): number {'],
|
||||
/*11*/[2, ' if (!node.id) {'],
|
||||
/*12*/[3, ' node.id = nextNodeId;'],
|
||||
/*13*/[3, ' nextNodeId++;'],
|
||||
/*14*/[2, ' }'],
|
||||
/*15*/[2, ' return node.id;'],
|
||||
/*16*/[1, ' }'],
|
||||
/*17*/[0, '}'],
|
||||
]);
|
||||
});
|
||||
|
||||
test('issue #8425 - Missing indentation lines for first level indentation', () => {
|
||||
assertIndentGuides([
|
||||
[1, '\tindent1'],
|
||||
[2, '\t\tindent2'],
|
||||
[2, '\t\tindent2'],
|
||||
[1, '\tindent1'],
|
||||
]);
|
||||
});
|
||||
|
||||
test('issue #8952 - Indentation guide lines going through text on .yml file', () => {
|
||||
assertIndentGuides([
|
||||
[0, 'properties:'],
|
||||
[1, ' emailAddress:'],
|
||||
[2, ' - bla'],
|
||||
[2, ' - length:'],
|
||||
[3, ' max: 255'],
|
||||
[0, 'getters:'],
|
||||
]);
|
||||
});
|
||||
|
||||
test('issue #11892 - Indent guides look funny', () => {
|
||||
assertIndentGuides([
|
||||
[0, 'function test(base) {'],
|
||||
[1, '\tswitch (base) {'],
|
||||
[2, '\t\tcase 1:'],
|
||||
[3, '\t\t\treturn 1;'],
|
||||
[2, '\t\tcase 2:'],
|
||||
[3, '\t\t\treturn 2;'],
|
||||
[1, '\t}'],
|
||||
[0, '}'],
|
||||
]);
|
||||
});
|
||||
|
||||
test('issue #12398 - Problem in indent guidelines', () => {
|
||||
assertIndentGuides([
|
||||
[2, '\t\t.bla'],
|
||||
[3, '\t\t\tlabel(for)'],
|
||||
[0, 'include script'],
|
||||
]);
|
||||
});
|
||||
});
|
||||
636
src/vs/editor/test/common/model/textModelSearch.test.ts
Normal file
636
src/vs/editor/test/common/model/textModelSearch.test.ts
Normal file
@@ -0,0 +1,636 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { Position } from 'vs/editor/common/core/position';
|
||||
import { FindMatch, EndOfLineSequence } from 'vs/editor/common/editorCommon';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { TextModel } from 'vs/editor/common/model/textModel';
|
||||
import { TextModelSearch, SearchParams, SearchData } from 'vs/editor/common/model/textModelSearch';
|
||||
import { getMapForWordSeparators } from 'vs/editor/common/controller/wordCharacterClassifier';
|
||||
import { USUAL_WORD_SEPARATORS } from 'vs/editor/common/model/wordHelper';
|
||||
|
||||
// --------- Find
|
||||
suite('TextModelSearch', () => {
|
||||
|
||||
const usualWordSeparators = getMapForWordSeparators(USUAL_WORD_SEPARATORS);
|
||||
|
||||
function assertFindMatch(actual: FindMatch, expectedRange: Range, expectedMatches: string[] = null): void {
|
||||
assert.deepEqual(actual, new FindMatch(expectedRange, expectedMatches));
|
||||
}
|
||||
|
||||
function _assertFindMatches(model: TextModel, searchParams: SearchParams, expectedMatches: FindMatch[]): void {
|
||||
let actual = TextModelSearch.findMatches(model, searchParams, model.getFullModelRange(), false, 1000);
|
||||
assert.deepEqual(actual, expectedMatches, 'findMatches OK');
|
||||
|
||||
// test `findNextMatch`
|
||||
let startPos = new Position(1, 1);
|
||||
let match = TextModelSearch.findNextMatch(model, searchParams, startPos, false);
|
||||
assert.deepEqual(match, expectedMatches[0], `findNextMatch ${startPos}`);
|
||||
for (let i = 0; i < expectedMatches.length; i++) {
|
||||
startPos = expectedMatches[i].range.getStartPosition();
|
||||
match = TextModelSearch.findNextMatch(model, searchParams, startPos, false);
|
||||
assert.deepEqual(match, expectedMatches[i], `findNextMatch ${startPos}`);
|
||||
}
|
||||
|
||||
// test `findPrevMatch`
|
||||
startPos = new Position(model.getLineCount(), model.getLineMaxColumn(model.getLineCount()));
|
||||
match = TextModelSearch.findPreviousMatch(model, searchParams, startPos, false);
|
||||
assert.deepEqual(match, expectedMatches[expectedMatches.length - 1], `findPrevMatch ${startPos}`);
|
||||
for (let i = 0; i < expectedMatches.length; i++) {
|
||||
startPos = expectedMatches[i].range.getEndPosition();
|
||||
match = TextModelSearch.findPreviousMatch(model, searchParams, startPos, false);
|
||||
assert.deepEqual(match, expectedMatches[i], `findPrevMatch ${startPos}`);
|
||||
}
|
||||
}
|
||||
|
||||
function assertFindMatches(text: string, searchString: string, isRegex: boolean, matchCase: boolean, wordSeparators: string, _expected: [number, number, number, number][]): void {
|
||||
let expectedRanges = _expected.map(entry => new Range(entry[0], entry[1], entry[2], entry[3]));
|
||||
let expectedMatches = expectedRanges.map(entry => new FindMatch(entry, null));
|
||||
let searchParams = new SearchParams(searchString, isRegex, matchCase, wordSeparators);
|
||||
|
||||
let model = TextModel.createFromString(text);
|
||||
_assertFindMatches(model, searchParams, expectedMatches);
|
||||
model.dispose();
|
||||
|
||||
|
||||
let model2 = TextModel.createFromString(text);
|
||||
model2.setEOL(EndOfLineSequence.CRLF);
|
||||
_assertFindMatches(model2, searchParams, expectedMatches);
|
||||
model2.dispose();
|
||||
}
|
||||
|
||||
let regularText = [
|
||||
'This is some foo - bar text which contains foo and bar - as in Barcelona.',
|
||||
'Now it begins a word fooBar and now it is caps Foo-isn\'t this great?',
|
||||
'And here\'s a dull line with nothing interesting in it',
|
||||
'It is also interesting if it\'s part of a word like amazingFooBar',
|
||||
'Again nothing interesting here'
|
||||
];
|
||||
|
||||
test('Simple find', () => {
|
||||
assertFindMatches(
|
||||
regularText.join('\n'),
|
||||
'foo', false, false, null,
|
||||
[
|
||||
[1, 14, 1, 17],
|
||||
[1, 44, 1, 47],
|
||||
[2, 22, 2, 25],
|
||||
[2, 48, 2, 51],
|
||||
[4, 59, 4, 62]
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
test('Case sensitive find', () => {
|
||||
assertFindMatches(
|
||||
regularText.join('\n'),
|
||||
'foo', false, true, null,
|
||||
[
|
||||
[1, 14, 1, 17],
|
||||
[1, 44, 1, 47],
|
||||
[2, 22, 2, 25]
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
test('Whole words find', () => {
|
||||
assertFindMatches(
|
||||
regularText.join('\n'),
|
||||
'foo', false, false, USUAL_WORD_SEPARATORS,
|
||||
[
|
||||
[1, 14, 1, 17],
|
||||
[1, 44, 1, 47],
|
||||
[2, 48, 2, 51]
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
test('/^/ find', () => {
|
||||
assertFindMatches(
|
||||
regularText.join('\n'),
|
||||
'^', true, false, null,
|
||||
[
|
||||
[1, 1, 1, 1],
|
||||
[2, 1, 2, 1],
|
||||
[3, 1, 3, 1],
|
||||
[4, 1, 4, 1],
|
||||
[5, 1, 5, 1]
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
test('/$/ find', () => {
|
||||
assertFindMatches(
|
||||
regularText.join('\n'),
|
||||
'$', true, false, null,
|
||||
[
|
||||
[1, 74, 1, 74],
|
||||
[2, 69, 2, 69],
|
||||
[3, 54, 3, 54],
|
||||
[4, 65, 4, 65],
|
||||
[5, 31, 5, 31]
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
test('/.*/ find', () => {
|
||||
assertFindMatches(
|
||||
regularText.join('\n'),
|
||||
'.*', true, false, null,
|
||||
[
|
||||
[1, 1, 1, 74],
|
||||
[2, 1, 2, 69],
|
||||
[3, 1, 3, 54],
|
||||
[4, 1, 4, 65],
|
||||
[5, 1, 5, 31]
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
test('/^$/ find', () => {
|
||||
assertFindMatches(
|
||||
[
|
||||
'This is some foo - bar text which contains foo and bar - as in Barcelona.',
|
||||
'',
|
||||
'And here\'s a dull line with nothing interesting in it',
|
||||
'',
|
||||
'Again nothing interesting here'
|
||||
].join('\n'),
|
||||
'^$', true, false, null,
|
||||
[
|
||||
[2, 1, 2, 1],
|
||||
[4, 1, 4, 1]
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
test('multiline find 1', () => {
|
||||
assertFindMatches(
|
||||
[
|
||||
'Just some text text',
|
||||
'Just some text text',
|
||||
'some text again',
|
||||
'again some text'
|
||||
].join('\n'),
|
||||
'text\\n', true, false, null,
|
||||
[
|
||||
[1, 16, 2, 1],
|
||||
[2, 16, 3, 1],
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
test('multiline find 2', () => {
|
||||
assertFindMatches(
|
||||
[
|
||||
'Just some text text',
|
||||
'Just some text text',
|
||||
'some text again',
|
||||
'again some text'
|
||||
].join('\n'),
|
||||
'text\\nJust', true, false, null,
|
||||
[
|
||||
[1, 16, 2, 5]
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
test('multiline find 3', () => {
|
||||
assertFindMatches(
|
||||
[
|
||||
'Just some text text',
|
||||
'Just some text text',
|
||||
'some text again',
|
||||
'again some text'
|
||||
].join('\n'),
|
||||
'\\nagain', true, false, null,
|
||||
[
|
||||
[3, 16, 4, 6]
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
test('multiline find 4', () => {
|
||||
assertFindMatches(
|
||||
[
|
||||
'Just some text text',
|
||||
'Just some text text',
|
||||
'some text again',
|
||||
'again some text'
|
||||
].join('\n'),
|
||||
'.*\\nJust.*\\n', true, false, null,
|
||||
[
|
||||
[1, 1, 3, 1]
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
test('multiline find with line beginning regex', () => {
|
||||
assertFindMatches(
|
||||
[
|
||||
'if',
|
||||
'else',
|
||||
'',
|
||||
'if',
|
||||
'else'
|
||||
].join('\n'),
|
||||
'^if\\nelse', true, false, null,
|
||||
[
|
||||
[1, 1, 2, 5],
|
||||
[4, 1, 5, 5]
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
test('matching empty lines using boundary expression', () => {
|
||||
assertFindMatches(
|
||||
[
|
||||
'if',
|
||||
'',
|
||||
'else',
|
||||
' ',
|
||||
'if',
|
||||
' ',
|
||||
'else'
|
||||
].join('\n'),
|
||||
'^\\s*$\\n', true, false, null,
|
||||
[
|
||||
[2, 1, 3, 1],
|
||||
[4, 1, 5, 1],
|
||||
[6, 1, 7, 1]
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
test('matching lines starting with A and ending with B', () => {
|
||||
assertFindMatches(
|
||||
[
|
||||
'a if b',
|
||||
'a',
|
||||
'ab',
|
||||
'eb'
|
||||
].join('\n'),
|
||||
'^a.*b$', true, false, null,
|
||||
[
|
||||
[1, 1, 1, 7],
|
||||
[3, 1, 3, 3]
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
test('multiline find with line ending regex', () => {
|
||||
assertFindMatches(
|
||||
[
|
||||
'if',
|
||||
'else',
|
||||
'',
|
||||
'if',
|
||||
'elseif',
|
||||
'else'
|
||||
].join('\n'),
|
||||
'if\\nelse$', true, false, null,
|
||||
[
|
||||
[1, 1, 2, 5],
|
||||
[5, 5, 6, 5]
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
test('issue #4836 - ^.*$', () => {
|
||||
assertFindMatches(
|
||||
[
|
||||
'Just some text text',
|
||||
'',
|
||||
'some text again',
|
||||
'',
|
||||
'again some text'
|
||||
].join('\n'),
|
||||
'^.*$', true, false, null,
|
||||
[
|
||||
[1, 1, 1, 20],
|
||||
[2, 1, 2, 1],
|
||||
[3, 1, 3, 16],
|
||||
[4, 1, 4, 1],
|
||||
[5, 1, 5, 16],
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
test('multiline find for non-regex string', () => {
|
||||
assertFindMatches(
|
||||
[
|
||||
'Just some text text',
|
||||
'some text text',
|
||||
'some text again',
|
||||
'again some text',
|
||||
'but not some'
|
||||
].join('\n'),
|
||||
'text\nsome', false, false, null,
|
||||
[
|
||||
[1, 16, 2, 5],
|
||||
[2, 11, 3, 5],
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
test('issue #3623: Match whole word does not work for not latin characters', () => {
|
||||
assertFindMatches(
|
||||
[
|
||||
'я',
|
||||
'компилятор',
|
||||
'обфускация',
|
||||
':я-я'
|
||||
].join('\n'),
|
||||
'я', false, false, USUAL_WORD_SEPARATORS,
|
||||
[
|
||||
[1, 1, 1, 2],
|
||||
[4, 2, 4, 3],
|
||||
[4, 4, 4, 5],
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
test('issue #27459: Match whole words regression', () => {
|
||||
assertFindMatches(
|
||||
[
|
||||
'this._register(this._textAreaInput.onKeyDown((e: IKeyboardEvent) => {',
|
||||
' this._viewController.emitKeyDown(e);',
|
||||
'}));',
|
||||
].join('\n'),
|
||||
'((e: ', false, false, USUAL_WORD_SEPARATORS,
|
||||
[
|
||||
[1, 45, 1, 50]
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
test('issue #27594: Search results disappear', () => {
|
||||
assertFindMatches(
|
||||
[
|
||||
'this.server.listen(0);',
|
||||
].join('\n'),
|
||||
'listen(', false, false, USUAL_WORD_SEPARATORS,
|
||||
[
|
||||
[1, 13, 1, 20]
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
test('findNextMatch without regex', () => {
|
||||
let model = TextModel.createFromString('line line one\nline two\nthree');
|
||||
|
||||
let searchParams = new SearchParams('line', false, false, null);
|
||||
|
||||
let actual = TextModelSearch.findNextMatch(model, searchParams, new Position(1, 1), false);
|
||||
assertFindMatch(actual, new Range(1, 1, 1, 5));
|
||||
|
||||
actual = TextModelSearch.findNextMatch(model, searchParams, actual.range.getEndPosition(), false);
|
||||
assertFindMatch(actual, new Range(1, 6, 1, 10));
|
||||
|
||||
actual = TextModelSearch.findNextMatch(model, searchParams, new Position(1, 3), false);
|
||||
assertFindMatch(actual, new Range(1, 6, 1, 10));
|
||||
|
||||
actual = TextModelSearch.findNextMatch(model, searchParams, actual.range.getEndPosition(), false);
|
||||
assertFindMatch(actual, new Range(2, 1, 2, 5));
|
||||
|
||||
actual = TextModelSearch.findNextMatch(model, searchParams, actual.range.getEndPosition(), false);
|
||||
assertFindMatch(actual, new Range(1, 1, 1, 5));
|
||||
|
||||
model.dispose();
|
||||
});
|
||||
|
||||
test('findNextMatch with beginning boundary regex', () => {
|
||||
let model = TextModel.createFromString('line one\nline two\nthree');
|
||||
|
||||
let searchParams = new SearchParams('^line', true, false, null);
|
||||
|
||||
let actual = TextModelSearch.findNextMatch(model, searchParams, new Position(1, 1), false);
|
||||
assertFindMatch(actual, new Range(1, 1, 1, 5));
|
||||
|
||||
actual = TextModelSearch.findNextMatch(model, searchParams, actual.range.getEndPosition(), false);
|
||||
assertFindMatch(actual, new Range(2, 1, 2, 5));
|
||||
|
||||
actual = TextModelSearch.findNextMatch(model, searchParams, new Position(1, 3), false);
|
||||
assertFindMatch(actual, new Range(2, 1, 2, 5));
|
||||
|
||||
actual = TextModelSearch.findNextMatch(model, searchParams, actual.range.getEndPosition(), false);
|
||||
assertFindMatch(actual, new Range(1, 1, 1, 5));
|
||||
|
||||
model.dispose();
|
||||
});
|
||||
|
||||
test('findNextMatch with beginning boundary regex and line has repetitive beginnings', () => {
|
||||
let model = TextModel.createFromString('line line one\nline two\nthree');
|
||||
|
||||
let searchParams = new SearchParams('^line', true, false, null);
|
||||
|
||||
let actual = TextModelSearch.findNextMatch(model, searchParams, new Position(1, 1), false);
|
||||
assertFindMatch(actual, new Range(1, 1, 1, 5));
|
||||
|
||||
actual = TextModelSearch.findNextMatch(model, searchParams, actual.range.getEndPosition(), false);
|
||||
assertFindMatch(actual, new Range(2, 1, 2, 5));
|
||||
|
||||
actual = TextModelSearch.findNextMatch(model, searchParams, new Position(1, 3), false);
|
||||
assertFindMatch(actual, new Range(2, 1, 2, 5));
|
||||
|
||||
actual = TextModelSearch.findNextMatch(model, searchParams, actual.range.getEndPosition(), false);
|
||||
assertFindMatch(actual, new Range(1, 1, 1, 5));
|
||||
|
||||
model.dispose();
|
||||
});
|
||||
|
||||
test('findNextMatch with beginning boundary multiline regex and line has repetitive beginnings', () => {
|
||||
let model = TextModel.createFromString('line line one\nline two\nline three\nline four');
|
||||
|
||||
let searchParams = new SearchParams('^line.*\\nline', true, false, null);
|
||||
|
||||
let actual = TextModelSearch.findNextMatch(model, searchParams, new Position(1, 1), false);
|
||||
assertFindMatch(actual, new Range(1, 1, 2, 5));
|
||||
|
||||
actual = TextModelSearch.findNextMatch(model, searchParams, actual.range.getEndPosition(), false);
|
||||
assertFindMatch(actual, new Range(3, 1, 4, 5));
|
||||
|
||||
actual = TextModelSearch.findNextMatch(model, searchParams, new Position(2, 1), false);
|
||||
assertFindMatch(actual, new Range(2, 1, 3, 5));
|
||||
|
||||
model.dispose();
|
||||
});
|
||||
|
||||
test('findNextMatch with ending boundary regex', () => {
|
||||
let model = TextModel.createFromString('one line line\ntwo line\nthree');
|
||||
|
||||
let searchParams = new SearchParams('line$', true, false, null);
|
||||
|
||||
let actual = TextModelSearch.findNextMatch(model, searchParams, new Position(1, 1), false);
|
||||
assertFindMatch(actual, new Range(1, 10, 1, 14));
|
||||
|
||||
actual = TextModelSearch.findNextMatch(model, searchParams, new Position(1, 4), false);
|
||||
assertFindMatch(actual, new Range(1, 10, 1, 14));
|
||||
|
||||
actual = TextModelSearch.findNextMatch(model, searchParams, actual.range.getEndPosition(), false);
|
||||
assertFindMatch(actual, new Range(2, 5, 2, 9));
|
||||
|
||||
actual = TextModelSearch.findNextMatch(model, searchParams, actual.range.getEndPosition(), false);
|
||||
assertFindMatch(actual, new Range(1, 10, 1, 14));
|
||||
|
||||
model.dispose();
|
||||
});
|
||||
|
||||
test('findMatches with capturing matches', () => {
|
||||
let model = TextModel.createFromString('one line line\ntwo line\nthree');
|
||||
|
||||
let searchParams = new SearchParams('(l(in)e)', true, false, null);
|
||||
|
||||
let actual = TextModelSearch.findMatches(model, searchParams, model.getFullModelRange(), true, 100);
|
||||
assert.deepEqual(actual, [
|
||||
new FindMatch(new Range(1, 5, 1, 9), ['line', 'line', 'in']),
|
||||
new FindMatch(new Range(1, 10, 1, 14), ['line', 'line', 'in']),
|
||||
new FindMatch(new Range(2, 5, 2, 9), ['line', 'line', 'in']),
|
||||
]);
|
||||
|
||||
model.dispose();
|
||||
});
|
||||
|
||||
test('findMatches multiline with capturing matches', () => {
|
||||
let model = TextModel.createFromString('one line line\ntwo line\nthree');
|
||||
|
||||
let searchParams = new SearchParams('(l(in)e)\\n', true, false, null);
|
||||
|
||||
let actual = TextModelSearch.findMatches(model, searchParams, model.getFullModelRange(), true, 100);
|
||||
assert.deepEqual(actual, [
|
||||
new FindMatch(new Range(1, 10, 2, 1), ['line\n', 'line', 'in']),
|
||||
new FindMatch(new Range(2, 5, 3, 1), ['line\n', 'line', 'in']),
|
||||
]);
|
||||
|
||||
model.dispose();
|
||||
});
|
||||
|
||||
test('findNextMatch with capturing matches', () => {
|
||||
let model = TextModel.createFromString('one line line\ntwo line\nthree');
|
||||
|
||||
let searchParams = new SearchParams('(l(in)e)', true, false, null);
|
||||
|
||||
let actual = TextModelSearch.findNextMatch(model, searchParams, new Position(1, 1), true);
|
||||
assertFindMatch(actual, new Range(1, 5, 1, 9), ['line', 'line', 'in']);
|
||||
|
||||
model.dispose();
|
||||
});
|
||||
|
||||
test('findNextMatch multiline with capturing matches', () => {
|
||||
let model = TextModel.createFromString('one line line\ntwo line\nthree');
|
||||
|
||||
let searchParams = new SearchParams('(l(in)e)\\n', true, false, null);
|
||||
|
||||
let actual = TextModelSearch.findNextMatch(model, searchParams, new Position(1, 1), true);
|
||||
assertFindMatch(actual, new Range(1, 10, 2, 1), ['line\n', 'line', 'in']);
|
||||
|
||||
model.dispose();
|
||||
});
|
||||
|
||||
test('findPreviousMatch with capturing matches', () => {
|
||||
let model = TextModel.createFromString('one line line\ntwo line\nthree');
|
||||
|
||||
let searchParams = new SearchParams('(l(in)e)', true, false, null);
|
||||
|
||||
let actual = TextModelSearch.findPreviousMatch(model, searchParams, new Position(1, 1), true);
|
||||
assertFindMatch(actual, new Range(2, 5, 2, 9), ['line', 'line', 'in']);
|
||||
|
||||
model.dispose();
|
||||
});
|
||||
|
||||
test('findPreviousMatch multiline with capturing matches', () => {
|
||||
let model = TextModel.createFromString('one line line\ntwo line\nthree');
|
||||
|
||||
let searchParams = new SearchParams('(l(in)e)\\n', true, false, null);
|
||||
|
||||
let actual = TextModelSearch.findPreviousMatch(model, searchParams, new Position(1, 1), true);
|
||||
assertFindMatch(actual, new Range(2, 5, 3, 1), ['line\n', 'line', 'in']);
|
||||
|
||||
model.dispose();
|
||||
});
|
||||
|
||||
test('\\n matches \\r\\n', () => {
|
||||
let model = TextModel.createFromString('a\r\nb\r\nc\r\nd\r\ne\r\nf\r\ng\r\nh\r\ni');
|
||||
|
||||
assert.equal(model.getEOL(), '\r\n');
|
||||
|
||||
let searchParams = new SearchParams('h\\n', true, false, null);
|
||||
let actual = TextModelSearch.findNextMatch(model, searchParams, new Position(1, 1), true);
|
||||
actual = TextModelSearch.findMatches(model, searchParams, model.getFullModelRange(), true, 1000)[0];
|
||||
assertFindMatch(actual, new Range(8, 1, 9, 1), ['h\n']);
|
||||
|
||||
searchParams = new SearchParams('g\\nh\\n', true, false, null);
|
||||
actual = TextModelSearch.findNextMatch(model, searchParams, new Position(1, 1), true);
|
||||
actual = TextModelSearch.findMatches(model, searchParams, model.getFullModelRange(), true, 1000)[0];
|
||||
assertFindMatch(actual, new Range(7, 1, 9, 1), ['g\nh\n']);
|
||||
|
||||
searchParams = new SearchParams('\\ni', true, false, null);
|
||||
actual = TextModelSearch.findNextMatch(model, searchParams, new Position(1, 1), true);
|
||||
actual = TextModelSearch.findMatches(model, searchParams, model.getFullModelRange(), true, 1000)[0];
|
||||
assertFindMatch(actual, new Range(8, 2, 9, 2), ['\ni']);
|
||||
|
||||
model.dispose();
|
||||
});
|
||||
|
||||
test('\\r can never be found', () => {
|
||||
let model = TextModel.createFromString('a\r\nb\r\nc\r\nd\r\ne\r\nf\r\ng\r\nh\r\ni');
|
||||
|
||||
assert.equal(model.getEOL(), '\r\n');
|
||||
|
||||
let searchParams = new SearchParams('\\r\\n', true, false, null);
|
||||
let actual = TextModelSearch.findNextMatch(model, searchParams, new Position(1, 1), true);
|
||||
assert.equal(actual, null);
|
||||
assert.deepEqual(TextModelSearch.findMatches(model, searchParams, model.getFullModelRange(), true, 1000), []);
|
||||
|
||||
model.dispose();
|
||||
});
|
||||
|
||||
function assertParseSearchResult(searchString: string, isRegex: boolean, matchCase: boolean, wordSeparators: string, expected: SearchData): void {
|
||||
let searchParams = new SearchParams(searchString, isRegex, matchCase, wordSeparators);
|
||||
let actual = searchParams.parseSearchRequest();
|
||||
|
||||
if (expected === null) {
|
||||
assert.ok(actual === null);
|
||||
} else {
|
||||
assert.deepEqual(actual.regex, expected.regex);
|
||||
assert.deepEqual(actual.simpleSearch, expected.simpleSearch);
|
||||
if (wordSeparators) {
|
||||
assert.ok(actual.wordSeparators !== null);
|
||||
} else {
|
||||
assert.ok(actual.wordSeparators === null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test('parseSearchRequest invalid', () => {
|
||||
assertParseSearchResult('', true, true, USUAL_WORD_SEPARATORS, null);
|
||||
assertParseSearchResult(null, true, true, USUAL_WORD_SEPARATORS, null);
|
||||
assertParseSearchResult('(', true, false, null, null);
|
||||
});
|
||||
|
||||
test('parseSearchRequest non regex', () => {
|
||||
assertParseSearchResult('foo', false, false, null, new SearchData(/foo/gi, null, null));
|
||||
assertParseSearchResult('foo', false, false, USUAL_WORD_SEPARATORS, new SearchData(/foo/gi, usualWordSeparators, null));
|
||||
assertParseSearchResult('foo', false, true, null, new SearchData(/foo/g, null, 'foo'));
|
||||
assertParseSearchResult('foo', false, true, USUAL_WORD_SEPARATORS, new SearchData(/foo/g, usualWordSeparators, 'foo'));
|
||||
assertParseSearchResult('foo\\n', false, false, null, new SearchData(/foo\\n/gi, null, null));
|
||||
assertParseSearchResult('foo\\\\n', false, false, null, new SearchData(/foo\\\\n/gi, null, null));
|
||||
assertParseSearchResult('foo\\r', false, false, null, new SearchData(/foo\\r/gi, null, null));
|
||||
assertParseSearchResult('foo\\\\r', false, false, null, new SearchData(/foo\\\\r/gi, null, null));
|
||||
});
|
||||
|
||||
test('parseSearchRequest regex', () => {
|
||||
assertParseSearchResult('foo', true, false, null, new SearchData(/foo/gi, null, null));
|
||||
assertParseSearchResult('foo', true, false, USUAL_WORD_SEPARATORS, new SearchData(/foo/gi, usualWordSeparators, null));
|
||||
assertParseSearchResult('foo', true, true, null, new SearchData(/foo/g, null, null));
|
||||
assertParseSearchResult('foo', true, true, USUAL_WORD_SEPARATORS, new SearchData(/foo/g, usualWordSeparators, null));
|
||||
assertParseSearchResult('foo\\n', true, false, null, new SearchData(/foo\n/gim, null, null));
|
||||
assertParseSearchResult('foo\\\\n', true, false, null, new SearchData(/foo\\n/gi, null, null));
|
||||
assertParseSearchResult('foo\\r', true, false, null, new SearchData(/foo\r/gim, null, null));
|
||||
assertParseSearchResult('foo\\\\r', true, false, null, new SearchData(/foo\\r/gi, null, null));
|
||||
});
|
||||
});
|
||||
361
src/vs/editor/test/common/model/textModelWithTokens.test.ts
Normal file
361
src/vs/editor/test/common/model/textModelWithTokens.test.ts
Normal file
@@ -0,0 +1,361 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { Model } from 'vs/editor/common/model/model';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { ViewLineToken } from 'vs/editor/common/core/viewLineToken';
|
||||
import { ITokenizationSupport, TokenizationRegistry, LanguageId, LanguageIdentifier, MetadataConsts } from 'vs/editor/common/modes';
|
||||
import { CharacterPair } from 'vs/editor/common/modes/languageConfiguration';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { IFoundBracket } from 'vs/editor/common/editorCommon';
|
||||
import { TextModel } from 'vs/editor/common/model/textModel';
|
||||
import { TextModelWithTokens } from 'vs/editor/common/model/textModelWithTokens';
|
||||
import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry';
|
||||
import { NULL_STATE } from 'vs/editor/common/modes/nullMode';
|
||||
import { TokenizationResult2 } from 'vs/editor/common/core/token';
|
||||
import { RawTextSource } from 'vs/editor/common/model/textSource';
|
||||
|
||||
suite('TextModelWithTokens', () => {
|
||||
|
||||
function testBrackets(contents: string[], brackets: CharacterPair[]): void {
|
||||
function toRelaxedFoundBracket(a: IFoundBracket) {
|
||||
if (!a) {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
range: a.range.toString(),
|
||||
open: a.open,
|
||||
close: a.close,
|
||||
isOpen: a.isOpen
|
||||
};
|
||||
}
|
||||
|
||||
let charIsBracket: { [char: string]: boolean } = {};
|
||||
let charIsOpenBracket: { [char: string]: boolean } = {};
|
||||
let openForChar: { [char: string]: string } = {};
|
||||
let closeForChar: { [char: string]: string } = {};
|
||||
brackets.forEach((b) => {
|
||||
charIsBracket[b[0]] = true;
|
||||
charIsBracket[b[1]] = true;
|
||||
|
||||
charIsOpenBracket[b[0]] = true;
|
||||
charIsOpenBracket[b[1]] = false;
|
||||
|
||||
openForChar[b[0]] = b[0];
|
||||
closeForChar[b[0]] = b[1];
|
||||
|
||||
openForChar[b[1]] = b[0];
|
||||
closeForChar[b[1]] = b[1];
|
||||
});
|
||||
|
||||
let expectedBrackets: IFoundBracket[] = [];
|
||||
for (let lineIndex = 0; lineIndex < contents.length; lineIndex++) {
|
||||
let lineText = contents[lineIndex];
|
||||
|
||||
for (let charIndex = 0; charIndex < lineText.length; charIndex++) {
|
||||
let ch = lineText.charAt(charIndex);
|
||||
if (charIsBracket[ch]) {
|
||||
expectedBrackets.push({
|
||||
open: openForChar[ch],
|
||||
close: closeForChar[ch],
|
||||
isOpen: charIsOpenBracket[ch],
|
||||
range: new Range(lineIndex + 1, charIndex + 1, lineIndex + 1, charIndex + 2)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const languageIdentifier = new LanguageIdentifier('testMode', LanguageId.PlainText);
|
||||
|
||||
let registration = LanguageConfigurationRegistry.register(languageIdentifier, {
|
||||
brackets: brackets
|
||||
});
|
||||
|
||||
let model = new TextModelWithTokens(
|
||||
RawTextSource.fromString(contents.join('\n')),
|
||||
TextModel.DEFAULT_CREATION_OPTIONS,
|
||||
languageIdentifier
|
||||
);
|
||||
|
||||
// findPrevBracket
|
||||
{
|
||||
let expectedBracketIndex = expectedBrackets.length - 1;
|
||||
let currentExpectedBracket = expectedBracketIndex >= 0 ? expectedBrackets[expectedBracketIndex] : null;
|
||||
for (let lineNumber = contents.length; lineNumber >= 1; lineNumber--) {
|
||||
let lineText = contents[lineNumber - 1];
|
||||
|
||||
for (let column = lineText.length + 1; column >= 1; column--) {
|
||||
|
||||
if (currentExpectedBracket) {
|
||||
if (lineNumber === currentExpectedBracket.range.startLineNumber && column < currentExpectedBracket.range.endColumn) {
|
||||
expectedBracketIndex--;
|
||||
currentExpectedBracket = expectedBracketIndex >= 0 ? expectedBrackets[expectedBracketIndex] : null;
|
||||
}
|
||||
}
|
||||
|
||||
let actual = model.findPrevBracket({
|
||||
lineNumber: lineNumber,
|
||||
column: column
|
||||
});
|
||||
|
||||
assert.deepEqual(toRelaxedFoundBracket(actual), toRelaxedFoundBracket(currentExpectedBracket), 'findPrevBracket of ' + lineNumber + ', ' + column);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// findNextBracket
|
||||
{
|
||||
let expectedBracketIndex = 0;
|
||||
let currentExpectedBracket = expectedBracketIndex < expectedBrackets.length ? expectedBrackets[expectedBracketIndex] : null;
|
||||
for (let lineNumber = 1; lineNumber <= contents.length; lineNumber++) {
|
||||
let lineText = contents[lineNumber - 1];
|
||||
|
||||
for (let column = 1; column <= lineText.length + 1; column++) {
|
||||
|
||||
if (currentExpectedBracket) {
|
||||
if (lineNumber === currentExpectedBracket.range.startLineNumber && column > currentExpectedBracket.range.startColumn) {
|
||||
expectedBracketIndex++;
|
||||
currentExpectedBracket = expectedBracketIndex < expectedBrackets.length ? expectedBrackets[expectedBracketIndex] : null;
|
||||
}
|
||||
}
|
||||
|
||||
let actual = model.findNextBracket({
|
||||
lineNumber: lineNumber,
|
||||
column: column
|
||||
});
|
||||
|
||||
assert.deepEqual(toRelaxedFoundBracket(actual), toRelaxedFoundBracket(currentExpectedBracket), 'findNextBracket of ' + lineNumber + ', ' + column);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
model.dispose();
|
||||
registration.dispose();
|
||||
}
|
||||
|
||||
test('brackets', () => {
|
||||
testBrackets([
|
||||
'if (a == 3) { return (7 * (a + 5)); }'
|
||||
], [
|
||||
['{', '}'],
|
||||
['[', ']'],
|
||||
['(', ')']
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
suite('TextModelWithTokens - bracket matching', () => {
|
||||
|
||||
function isNotABracket(model: Model, lineNumber: number, column: number) {
|
||||
let match = model.matchBracket(new Position(lineNumber, column));
|
||||
assert.equal(match, null, 'is not matching brackets at ' + lineNumber + ', ' + column);
|
||||
}
|
||||
|
||||
function isBracket2(model: Model, testPosition: Position, expected: [Range, Range]): void {
|
||||
let actual = model.matchBracket(testPosition);
|
||||
assert.deepEqual(actual, expected, 'matches brackets at ' + testPosition);
|
||||
}
|
||||
|
||||
const languageIdentifier = new LanguageIdentifier('bracketMode1', LanguageId.PlainText);
|
||||
let registration: IDisposable = null;
|
||||
|
||||
setup(() => {
|
||||
registration = LanguageConfigurationRegistry.register(languageIdentifier, {
|
||||
brackets: [
|
||||
['{', '}'],
|
||||
['[', ']'],
|
||||
['(', ')'],
|
||||
]
|
||||
});
|
||||
});
|
||||
|
||||
teardown(() => {
|
||||
registration.dispose();
|
||||
registration = null;
|
||||
});
|
||||
|
||||
test('bracket matching 1', () => {
|
||||
let text =
|
||||
')]}{[(' + '\n' +
|
||||
')]}{[(';
|
||||
let model = Model.createFromString(text, undefined, languageIdentifier);
|
||||
|
||||
isNotABracket(model, 1, 1);
|
||||
isNotABracket(model, 1, 2);
|
||||
isNotABracket(model, 1, 3);
|
||||
isBracket2(model, new Position(1, 4), [new Range(1, 4, 1, 5), new Range(2, 3, 2, 4)]);
|
||||
isBracket2(model, new Position(1, 5), [new Range(1, 5, 1, 6), new Range(2, 2, 2, 3)]);
|
||||
isBracket2(model, new Position(1, 6), [new Range(1, 6, 1, 7), new Range(2, 1, 2, 2)]);
|
||||
isBracket2(model, new Position(1, 7), [new Range(1, 6, 1, 7), new Range(2, 1, 2, 2)]);
|
||||
|
||||
isBracket2(model, new Position(2, 1), [new Range(2, 1, 2, 2), new Range(1, 6, 1, 7)]);
|
||||
isBracket2(model, new Position(2, 2), [new Range(2, 2, 2, 3), new Range(1, 5, 1, 6)]);
|
||||
isBracket2(model, new Position(2, 3), [new Range(2, 3, 2, 4), new Range(1, 4, 1, 5)]);
|
||||
isBracket2(model, new Position(2, 4), [new Range(2, 3, 2, 4), new Range(1, 4, 1, 5)]);
|
||||
isNotABracket(model, 2, 5);
|
||||
isNotABracket(model, 2, 6);
|
||||
isNotABracket(model, 2, 7);
|
||||
|
||||
model.dispose();
|
||||
});
|
||||
|
||||
test('bracket matching 2', () => {
|
||||
let text =
|
||||
'var bar = {' + '\n' +
|
||||
'foo: {' + '\n' +
|
||||
'}, bar: {hallo: [{' + '\n' +
|
||||
'}, {' + '\n' +
|
||||
'}]}}';
|
||||
let model = Model.createFromString(text, undefined, languageIdentifier);
|
||||
|
||||
let brackets: [Position, Range, Range][] = [
|
||||
[new Position(1, 11), new Range(1, 11, 1, 12), new Range(5, 4, 5, 5)],
|
||||
[new Position(1, 12), new Range(1, 11, 1, 12), new Range(5, 4, 5, 5)],
|
||||
|
||||
[new Position(2, 6), new Range(2, 6, 2, 7), new Range(3, 1, 3, 2)],
|
||||
[new Position(2, 7), new Range(2, 6, 2, 7), new Range(3, 1, 3, 2)],
|
||||
|
||||
[new Position(3, 1), new Range(3, 1, 3, 2), new Range(2, 6, 2, 7)],
|
||||
[new Position(3, 2), new Range(3, 1, 3, 2), new Range(2, 6, 2, 7)],
|
||||
[new Position(3, 9), new Range(3, 9, 3, 10), new Range(5, 3, 5, 4)],
|
||||
[new Position(3, 10), new Range(3, 9, 3, 10), new Range(5, 3, 5, 4)],
|
||||
[new Position(3, 17), new Range(3, 17, 3, 18), new Range(5, 2, 5, 3)],
|
||||
[new Position(3, 18), new Range(3, 18, 3, 19), new Range(4, 1, 4, 2)],
|
||||
[new Position(3, 19), new Range(3, 18, 3, 19), new Range(4, 1, 4, 2)],
|
||||
|
||||
[new Position(4, 1), new Range(4, 1, 4, 2), new Range(3, 18, 3, 19)],
|
||||
[new Position(4, 2), new Range(4, 1, 4, 2), new Range(3, 18, 3, 19)],
|
||||
[new Position(4, 4), new Range(4, 4, 4, 5), new Range(5, 1, 5, 2)],
|
||||
[new Position(4, 5), new Range(4, 4, 4, 5), new Range(5, 1, 5, 2)],
|
||||
|
||||
[new Position(5, 1), new Range(5, 1, 5, 2), new Range(4, 4, 4, 5)],
|
||||
[new Position(5, 2), new Range(5, 2, 5, 3), new Range(3, 17, 3, 18)],
|
||||
[new Position(5, 3), new Range(5, 3, 5, 4), new Range(3, 9, 3, 10)],
|
||||
[new Position(5, 4), new Range(5, 4, 5, 5), new Range(1, 11, 1, 12)],
|
||||
[new Position(5, 5), new Range(5, 4, 5, 5), new Range(1, 11, 1, 12)],
|
||||
];
|
||||
|
||||
let isABracket: { [lineNumber: number]: { [col: number]: boolean; }; } = { 1: {}, 2: {}, 3: {}, 4: {}, 5: {} };
|
||||
for (let i = 0, len = brackets.length; i < len; i++) {
|
||||
let [testPos, b1, b2] = brackets[i];
|
||||
isBracket2(model, testPos, [b1, b2]);
|
||||
isABracket[testPos.lineNumber][testPos.column] = true;
|
||||
}
|
||||
|
||||
for (let i = 1, len = model.getLineCount(); i <= len; i++) {
|
||||
let line = model.getLineContent(i);
|
||||
for (let j = 1, lenJ = line.length + 1; j <= lenJ; j++) {
|
||||
if (!isABracket[i].hasOwnProperty(<any>j)) {
|
||||
isNotABracket(model, i, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
model.dispose();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
suite('TextModelWithTokens regression tests', () => {
|
||||
|
||||
test('Microsoft/monaco-editor#122: Unhandled Exception: TypeError: Unable to get property \'replace\' of undefined or null reference', () => {
|
||||
function assertViewLineTokens(model: Model, lineNumber: number, forceTokenization: boolean, expected: ViewLineToken[]): void {
|
||||
if (forceTokenization) {
|
||||
model.forceTokenization(lineNumber);
|
||||
}
|
||||
let actual = model.getLineTokens(lineNumber).inflate();
|
||||
let decode = (token: ViewLineToken) => {
|
||||
return {
|
||||
endIndex: token.endIndex,
|
||||
foreground: token.getForeground()
|
||||
};
|
||||
};
|
||||
assert.deepEqual(actual.map(decode), expected.map(decode));
|
||||
}
|
||||
|
||||
let _tokenId = 10;
|
||||
const LANG_ID1 = 'indicisiveMode1';
|
||||
const LANG_ID2 = 'indicisiveMode2';
|
||||
const languageIdentifier1 = new LanguageIdentifier(LANG_ID1, 3);
|
||||
const languageIdentifier2 = new LanguageIdentifier(LANG_ID2, 4);
|
||||
|
||||
const tokenizationSupport: ITokenizationSupport = {
|
||||
getInitialState: () => NULL_STATE,
|
||||
tokenize: undefined,
|
||||
tokenize2: (line, state) => {
|
||||
let myId = ++_tokenId;
|
||||
let tokens = new Uint32Array(2);
|
||||
tokens[0] = 0;
|
||||
tokens[1] = (
|
||||
myId << MetadataConsts.FOREGROUND_OFFSET
|
||||
) >>> 0;
|
||||
return new TokenizationResult2(tokens, state);
|
||||
}
|
||||
};
|
||||
|
||||
let registration1 = TokenizationRegistry.register(LANG_ID1, tokenizationSupport);
|
||||
let registration2 = TokenizationRegistry.register(LANG_ID2, tokenizationSupport);
|
||||
|
||||
let model = Model.createFromString('A model with\ntwo lines');
|
||||
|
||||
assertViewLineTokens(model, 1, true, [createViewLineToken(12, 1)]);
|
||||
assertViewLineTokens(model, 2, true, [createViewLineToken(9, 1)]);
|
||||
|
||||
model.setMode(languageIdentifier1);
|
||||
|
||||
assertViewLineTokens(model, 1, true, [createViewLineToken(12, 11)]);
|
||||
assertViewLineTokens(model, 2, true, [createViewLineToken(9, 12)]);
|
||||
|
||||
model.setMode(languageIdentifier2);
|
||||
|
||||
assertViewLineTokens(model, 1, false, [createViewLineToken(12, 1)]);
|
||||
assertViewLineTokens(model, 2, false, [createViewLineToken(9, 1)]);
|
||||
|
||||
model.dispose();
|
||||
registration1.dispose();
|
||||
registration2.dispose();
|
||||
|
||||
function createViewLineToken(endIndex: number, foreground: number): ViewLineToken {
|
||||
let metadata = (
|
||||
(foreground << MetadataConsts.FOREGROUND_OFFSET)
|
||||
) >>> 0;
|
||||
return new ViewLineToken(endIndex, metadata);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
test('Microsoft/monaco-editor#133: Error: Cannot read property \'modeId\' of undefined', () => {
|
||||
|
||||
const languageIdentifier = new LanguageIdentifier('testMode', LanguageId.PlainText);
|
||||
|
||||
let registration = LanguageConfigurationRegistry.register(languageIdentifier, {
|
||||
brackets: [
|
||||
['module', 'end module'],
|
||||
['sub', 'end sub']
|
||||
]
|
||||
});
|
||||
|
||||
let model = Model.createFromString([
|
||||
'Imports System',
|
||||
'Imports System.Collections.Generic',
|
||||
'',
|
||||
'Module m1',
|
||||
'',
|
||||
'\tSub Main()',
|
||||
'\tEnd Sub',
|
||||
'',
|
||||
'End Module',
|
||||
].join('\n'), undefined, languageIdentifier);
|
||||
|
||||
let actual = model.matchBracket(new Position(4, 1));
|
||||
assert.deepEqual(actual, [new Range(4, 1, 4, 7), new Range(9, 1, 9, 11)]);
|
||||
|
||||
model.dispose();
|
||||
registration.dispose();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,93 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { StandardAutoClosingPairConditional } from 'vs/editor/common/modes/languageConfiguration';
|
||||
import { StandardTokenType } from 'vs/editor/common/modes';
|
||||
|
||||
suite('StandardAutoClosingPairConditional', () => {
|
||||
|
||||
test('Missing notIn', () => {
|
||||
let v = new StandardAutoClosingPairConditional({ open: '{', close: '}' });
|
||||
assert.equal(v.isOK(StandardTokenType.Other), true);
|
||||
assert.equal(v.isOK(StandardTokenType.Comment), true);
|
||||
assert.equal(v.isOK(StandardTokenType.String), true);
|
||||
assert.equal(v.isOK(StandardTokenType.RegEx), true);
|
||||
});
|
||||
|
||||
test('Empty notIn', () => {
|
||||
let v = new StandardAutoClosingPairConditional({ open: '{', close: '}', notIn: [] });
|
||||
assert.equal(v.isOK(StandardTokenType.Other), true);
|
||||
assert.equal(v.isOK(StandardTokenType.Comment), true);
|
||||
assert.equal(v.isOK(StandardTokenType.String), true);
|
||||
assert.equal(v.isOK(StandardTokenType.RegEx), true);
|
||||
});
|
||||
|
||||
test('Invalid notIn', () => {
|
||||
let v = new StandardAutoClosingPairConditional({ open: '{', close: '}', notIn: ['bla'] });
|
||||
assert.equal(v.isOK(StandardTokenType.Other), true);
|
||||
assert.equal(v.isOK(StandardTokenType.Comment), true);
|
||||
assert.equal(v.isOK(StandardTokenType.String), true);
|
||||
assert.equal(v.isOK(StandardTokenType.RegEx), true);
|
||||
});
|
||||
|
||||
test('notIn in strings', () => {
|
||||
let v = new StandardAutoClosingPairConditional({ open: '{', close: '}', notIn: ['string'] });
|
||||
assert.equal(v.isOK(StandardTokenType.Other), true);
|
||||
assert.equal(v.isOK(StandardTokenType.Comment), true);
|
||||
assert.equal(v.isOK(StandardTokenType.String), false);
|
||||
assert.equal(v.isOK(StandardTokenType.RegEx), true);
|
||||
});
|
||||
|
||||
test('notIn in comments', () => {
|
||||
let v = new StandardAutoClosingPairConditional({ open: '{', close: '}', notIn: ['comment'] });
|
||||
assert.equal(v.isOK(StandardTokenType.Other), true);
|
||||
assert.equal(v.isOK(StandardTokenType.Comment), false);
|
||||
assert.equal(v.isOK(StandardTokenType.String), true);
|
||||
assert.equal(v.isOK(StandardTokenType.RegEx), true);
|
||||
});
|
||||
|
||||
test('notIn in regex', () => {
|
||||
let v = new StandardAutoClosingPairConditional({ open: '{', close: '}', notIn: ['regex'] });
|
||||
assert.equal(v.isOK(StandardTokenType.Other), true);
|
||||
assert.equal(v.isOK(StandardTokenType.Comment), true);
|
||||
assert.equal(v.isOK(StandardTokenType.String), true);
|
||||
assert.equal(v.isOK(StandardTokenType.RegEx), false);
|
||||
});
|
||||
|
||||
test('notIn in strings nor comments', () => {
|
||||
let v = new StandardAutoClosingPairConditional({ open: '{', close: '}', notIn: ['string', 'comment'] });
|
||||
assert.equal(v.isOK(StandardTokenType.Other), true);
|
||||
assert.equal(v.isOK(StandardTokenType.Comment), false);
|
||||
assert.equal(v.isOK(StandardTokenType.String), false);
|
||||
assert.equal(v.isOK(StandardTokenType.RegEx), true);
|
||||
});
|
||||
|
||||
test('notIn in strings nor regex', () => {
|
||||
let v = new StandardAutoClosingPairConditional({ open: '{', close: '}', notIn: ['string', 'regex'] });
|
||||
assert.equal(v.isOK(StandardTokenType.Other), true);
|
||||
assert.equal(v.isOK(StandardTokenType.Comment), true);
|
||||
assert.equal(v.isOK(StandardTokenType.String), false);
|
||||
assert.equal(v.isOK(StandardTokenType.RegEx), false);
|
||||
});
|
||||
|
||||
test('notIn in comments nor regex', () => {
|
||||
let v = new StandardAutoClosingPairConditional({ open: '{', close: '}', notIn: ['comment', 'regex'] });
|
||||
assert.equal(v.isOK(StandardTokenType.Other), true);
|
||||
assert.equal(v.isOK(StandardTokenType.Comment), false);
|
||||
assert.equal(v.isOK(StandardTokenType.String), true);
|
||||
assert.equal(v.isOK(StandardTokenType.RegEx), false);
|
||||
});
|
||||
|
||||
test('notIn in strings, comments nor regex', () => {
|
||||
let v = new StandardAutoClosingPairConditional({ open: '{', close: '}', notIn: ['string', 'comment', 'regex'] });
|
||||
assert.equal(v.isOK(StandardTokenType.Other), true);
|
||||
assert.equal(v.isOK(StandardTokenType.Comment), false);
|
||||
assert.equal(v.isOK(StandardTokenType.String), false);
|
||||
assert.equal(v.isOK(StandardTokenType.RegEx), false);
|
||||
});
|
||||
});
|
||||
84
src/vs/editor/test/common/modes/languageSelector.test.ts
Normal file
84
src/vs/editor/test/common/modes/languageSelector.test.ts
Normal file
@@ -0,0 +1,84 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 URI from 'vs/base/common/uri';
|
||||
import { score } from 'vs/editor/common/modes/languageSelector';
|
||||
|
||||
suite('LanguageSelector', function () {
|
||||
|
||||
let model = {
|
||||
language: 'farboo',
|
||||
uri: URI.parse('file:///testbed/file.fb')
|
||||
};
|
||||
|
||||
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);
|
||||
});
|
||||
|
||||
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('*', URI.parse('foo:bar'), model.language), 5);
|
||||
assert.equal(score('farboo', URI.parse('foo:bar'), model.language), 10);
|
||||
});
|
||||
|
||||
test('score, default schemes', 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({ scheme: '*' }, uri, language), 5);
|
||||
assert.equal(score({ scheme: 'git' }, uri, language), 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({ 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);
|
||||
|
||||
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
|
||||
});
|
||||
|
||||
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);
|
||||
});
|
||||
});
|
||||
193
src/vs/editor/test/common/modes/linkComputer.test.ts
Normal file
193
src/vs/editor/test/common/modes/linkComputer.test.ts
Normal file
@@ -0,0 +1,193 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { ILink } from 'vs/editor/common/modes';
|
||||
import { ILinkComputerTarget, computeLinks } from 'vs/editor/common/modes/linkComputer';
|
||||
|
||||
class SimpleLinkComputerTarget implements ILinkComputerTarget {
|
||||
|
||||
constructor(private _lines: string[]) {
|
||||
// Intentional Empty
|
||||
}
|
||||
|
||||
public getLineCount(): number {
|
||||
return this._lines.length;
|
||||
}
|
||||
|
||||
public getLineContent(lineNumber: number): string {
|
||||
return this._lines[lineNumber - 1];
|
||||
}
|
||||
}
|
||||
|
||||
function myComputeLinks(lines: string[]): ILink[] {
|
||||
var target = new SimpleLinkComputerTarget(lines);
|
||||
return computeLinks(target);
|
||||
}
|
||||
|
||||
function assertLink(text: string, extractedLink: string): void {
|
||||
var startColumn = 0,
|
||||
endColumn = 0,
|
||||
chr: string,
|
||||
i = 0;
|
||||
|
||||
for (i = 0; i < extractedLink.length; i++) {
|
||||
chr = extractedLink.charAt(i);
|
||||
if (chr !== ' ' && chr !== '\t') {
|
||||
startColumn = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = extractedLink.length - 1; i >= 0; i--) {
|
||||
chr = extractedLink.charAt(i);
|
||||
if (chr !== ' ' && chr !== '\t') {
|
||||
endColumn = i + 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var r = myComputeLinks([text]);
|
||||
assert.deepEqual(r, [{
|
||||
range: {
|
||||
startLineNumber: 1,
|
||||
startColumn: startColumn,
|
||||
endLineNumber: 1,
|
||||
endColumn: endColumn
|
||||
},
|
||||
url: extractedLink.substring(startColumn - 1, endColumn - 1)
|
||||
}]);
|
||||
}
|
||||
|
||||
suite('Editor Modes - Link Computer', () => {
|
||||
|
||||
test('Null model', () => {
|
||||
var r = computeLinks(null);
|
||||
assert.deepEqual(r, []);
|
||||
});
|
||||
|
||||
test('Parsing', () => {
|
||||
|
||||
assertLink(
|
||||
'x = "http://foo.bar";',
|
||||
' http://foo.bar '
|
||||
);
|
||||
|
||||
assertLink(
|
||||
'x = (http://foo.bar);',
|
||||
' http://foo.bar '
|
||||
);
|
||||
|
||||
assertLink(
|
||||
'x = [http://foo.bar];',
|
||||
' http://foo.bar '
|
||||
);
|
||||
|
||||
assertLink(
|
||||
'x = \'http://foo.bar\';',
|
||||
' http://foo.bar '
|
||||
);
|
||||
|
||||
assertLink(
|
||||
'x = http://foo.bar ;',
|
||||
' http://foo.bar '
|
||||
);
|
||||
|
||||
assertLink(
|
||||
'x = <http://foo.bar>;',
|
||||
' http://foo.bar '
|
||||
);
|
||||
|
||||
assertLink(
|
||||
'x = {http://foo.bar};',
|
||||
' http://foo.bar '
|
||||
);
|
||||
|
||||
assertLink(
|
||||
'(see http://foo.bar)',
|
||||
' http://foo.bar '
|
||||
);
|
||||
assertLink(
|
||||
'[see http://foo.bar]',
|
||||
' http://foo.bar '
|
||||
);
|
||||
assertLink(
|
||||
'{see http://foo.bar}',
|
||||
' http://foo.bar '
|
||||
);
|
||||
assertLink(
|
||||
'<see http://foo.bar>',
|
||||
' http://foo.bar '
|
||||
);
|
||||
assertLink(
|
||||
'<url>http://mylink.com</url>',
|
||||
' http://mylink.com '
|
||||
);
|
||||
assertLink(
|
||||
'// Click here to learn more. https://go.microsoft.com/fwlink/?LinkID=513275&clcid=0x409',
|
||||
' https://go.microsoft.com/fwlink/?LinkID=513275&clcid=0x409'
|
||||
);
|
||||
assertLink(
|
||||
'// Click here to learn more. https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx',
|
||||
' https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx'
|
||||
);
|
||||
assertLink(
|
||||
'// https://github.com/projectkudu/kudu/blob/master/Kudu.Core/Scripts/selectNodeVersion.js',
|
||||
' https://github.com/projectkudu/kudu/blob/master/Kudu.Core/Scripts/selectNodeVersion.js'
|
||||
);
|
||||
assertLink(
|
||||
'<!-- !!! Do not remove !!! WebContentRef(link:https://go.microsoft.com/fwlink/?LinkId=166007, area:Admin, updated:2015, nextUpdate:2016, tags:SqlServer) !!! Do not remove !!! -->',
|
||||
' https://go.microsoft.com/fwlink/?LinkId=166007 '
|
||||
);
|
||||
assertLink(
|
||||
'For instructions, see https://go.microsoft.com/fwlink/?LinkId=166007.</value>',
|
||||
' https://go.microsoft.com/fwlink/?LinkId=166007 '
|
||||
);
|
||||
assertLink(
|
||||
'For instructions, see https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx.</value>',
|
||||
' https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx '
|
||||
);
|
||||
assertLink(
|
||||
'x = "https://en.wikipedia.org/wiki/Zürich";',
|
||||
' https://en.wikipedia.org/wiki/Zürich '
|
||||
);
|
||||
assertLink(
|
||||
'請參閱 http://go.microsoft.com/fwlink/?LinkId=761051。',
|
||||
' http://go.microsoft.com/fwlink/?LinkId=761051 '
|
||||
);
|
||||
assertLink(
|
||||
'(請參閱 http://go.microsoft.com/fwlink/?LinkId=761051)',
|
||||
' http://go.microsoft.com/fwlink/?LinkId=761051 '
|
||||
);
|
||||
|
||||
assertLink(
|
||||
'x = "file:///foo.bar";',
|
||||
' file:///foo.bar '
|
||||
);
|
||||
assertLink(
|
||||
'x = "file://c:/foo.bar";',
|
||||
' file://c:/foo.bar '
|
||||
);
|
||||
|
||||
assertLink(
|
||||
'x = "file://shares/foo.bar";',
|
||||
' file://shares/foo.bar '
|
||||
);
|
||||
|
||||
assertLink(
|
||||
'x = "file://shäres/foo.bar";',
|
||||
' file://shäres/foo.bar '
|
||||
);
|
||||
assertLink(
|
||||
'Some text, then http://www.bing.com.',
|
||||
' http://www.bing.com '
|
||||
);
|
||||
assertLink(
|
||||
'let url = `http://***/_api/web/lists/GetByTitle(\'Teambuildingaanvragen\')/items`;',
|
||||
' http://***/_api/web/lists/GetByTitle(\'Teambuildingaanvragen\')/items '
|
||||
);
|
||||
});
|
||||
});
|
||||
122
src/vs/editor/test/common/modes/supports/characterPair.test.ts
Normal file
122
src/vs/editor/test/common/modes/supports/characterPair.test.ts
Normal file
@@ -0,0 +1,122 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { CharacterPairSupport } from 'vs/editor/common/modes/supports/characterPair';
|
||||
import { TokenText, createFakeScopedLineTokens } from 'vs/editor/test/common/modesTestUtils';
|
||||
import { StandardTokenType } from 'vs/editor/common/modes';
|
||||
|
||||
suite('CharacterPairSupport', () => {
|
||||
|
||||
test('only autoClosingPairs', () => {
|
||||
let characaterPairSupport = new CharacterPairSupport({ autoClosingPairs: [{ open: 'a', close: 'b' }] });
|
||||
assert.deepEqual(characaterPairSupport.getAutoClosingPairs(), [{ open: 'a', close: 'b', _standardTokenMask: 0 }]);
|
||||
assert.deepEqual(characaterPairSupport.getSurroundingPairs(), [{ open: 'a', close: 'b', _standardTokenMask: 0 }]);
|
||||
});
|
||||
|
||||
test('only empty autoClosingPairs', () => {
|
||||
let characaterPairSupport = new CharacterPairSupport({ autoClosingPairs: [] });
|
||||
assert.deepEqual(characaterPairSupport.getAutoClosingPairs(), []);
|
||||
assert.deepEqual(characaterPairSupport.getSurroundingPairs(), []);
|
||||
});
|
||||
|
||||
test('only brackets', () => {
|
||||
let characaterPairSupport = new CharacterPairSupport({ brackets: [['a', 'b']] });
|
||||
assert.deepEqual(characaterPairSupport.getAutoClosingPairs(), [{ open: 'a', close: 'b', _standardTokenMask: 0 }]);
|
||||
assert.deepEqual(characaterPairSupport.getSurroundingPairs(), [{ open: 'a', close: 'b', _standardTokenMask: 0 }]);
|
||||
});
|
||||
|
||||
test('only empty brackets', () => {
|
||||
let characaterPairSupport = new CharacterPairSupport({ brackets: [] });
|
||||
assert.deepEqual(characaterPairSupport.getAutoClosingPairs(), []);
|
||||
assert.deepEqual(characaterPairSupport.getSurroundingPairs(), []);
|
||||
});
|
||||
|
||||
test('only surroundingPairs', () => {
|
||||
let characaterPairSupport = new CharacterPairSupport({ surroundingPairs: [{ open: 'a', close: 'b' }] });
|
||||
assert.deepEqual(characaterPairSupport.getAutoClosingPairs(), []);
|
||||
assert.deepEqual(characaterPairSupport.getSurroundingPairs(), [{ open: 'a', close: 'b' }]);
|
||||
});
|
||||
|
||||
test('only empty surroundingPairs', () => {
|
||||
let characaterPairSupport = new CharacterPairSupport({ surroundingPairs: [] });
|
||||
assert.deepEqual(characaterPairSupport.getAutoClosingPairs(), []);
|
||||
assert.deepEqual(characaterPairSupport.getSurroundingPairs(), []);
|
||||
});
|
||||
|
||||
test('brackets is ignored when having autoClosingPairs', () => {
|
||||
let characaterPairSupport = new CharacterPairSupport({ autoClosingPairs: [], brackets: [['a', 'b']] });
|
||||
assert.deepEqual(characaterPairSupport.getAutoClosingPairs(), []);
|
||||
assert.deepEqual(characaterPairSupport.getSurroundingPairs(), []);
|
||||
});
|
||||
|
||||
function testShouldAutoClose(characterPairSupport: CharacterPairSupport, line: TokenText[], character: string, column: number): boolean {
|
||||
return characterPairSupport.shouldAutoClosePair(character, createFakeScopedLineTokens(line), column);
|
||||
}
|
||||
|
||||
test('shouldAutoClosePair in empty line', () => {
|
||||
let sup = new CharacterPairSupport({ autoClosingPairs: [{ open: '{', close: '}', notIn: ['string', 'comment'] }] });
|
||||
assert.equal(testShouldAutoClose(sup, [], 'a', 1), true);
|
||||
assert.equal(testShouldAutoClose(sup, [], '{', 1), true);
|
||||
});
|
||||
|
||||
test('shouldAutoClosePair in not interesting line 1', () => {
|
||||
let sup = new CharacterPairSupport({ autoClosingPairs: [{ open: '{', close: '}', notIn: ['string', 'comment'] }] });
|
||||
assert.equal(testShouldAutoClose(sup, [{ text: 'do', type: StandardTokenType.Other }], '{', 3), true);
|
||||
assert.equal(testShouldAutoClose(sup, [{ text: 'do', type: StandardTokenType.Other }], 'a', 3), true);
|
||||
});
|
||||
|
||||
test('shouldAutoClosePair in not interesting line 2', () => {
|
||||
let sup = new CharacterPairSupport({ autoClosingPairs: [{ open: '{', close: '}' }] });
|
||||
assert.equal(testShouldAutoClose(sup, [{ text: 'do', type: StandardTokenType.String }], '{', 3), true);
|
||||
assert.equal(testShouldAutoClose(sup, [{ text: 'do', type: StandardTokenType.String }], 'a', 3), true);
|
||||
});
|
||||
|
||||
test('shouldAutoClosePair in interesting line 1', () => {
|
||||
let sup = new CharacterPairSupport({ autoClosingPairs: [{ open: '{', close: '}', notIn: ['string', 'comment'] }] });
|
||||
assert.equal(testShouldAutoClose(sup, [{ text: '"a"', type: StandardTokenType.String }], '{', 1), false);
|
||||
assert.equal(testShouldAutoClose(sup, [{ text: '"a"', type: StandardTokenType.String }], 'a', 1), true);
|
||||
assert.equal(testShouldAutoClose(sup, [{ text: '"a"', type: StandardTokenType.String }], '{', 2), false);
|
||||
assert.equal(testShouldAutoClose(sup, [{ text: '"a"', type: StandardTokenType.String }], 'a', 2), true);
|
||||
assert.equal(testShouldAutoClose(sup, [{ text: '"a"', type: StandardTokenType.String }], '{', 3), false);
|
||||
assert.equal(testShouldAutoClose(sup, [{ text: '"a"', type: StandardTokenType.String }], 'a', 3), true);
|
||||
assert.equal(testShouldAutoClose(sup, [{ text: '"a"', type: StandardTokenType.String }], '{', 4), false);
|
||||
assert.equal(testShouldAutoClose(sup, [{ text: '"a"', type: StandardTokenType.String }], 'a', 4), true);
|
||||
});
|
||||
|
||||
test('shouldAutoClosePair in interesting line 2', () => {
|
||||
let sup = new CharacterPairSupport({ autoClosingPairs: [{ open: '{', close: '}', notIn: ['string', 'comment'] }] });
|
||||
assert.equal(testShouldAutoClose(sup, [{ text: 'x=', type: StandardTokenType.Other }, { text: '"a"', type: StandardTokenType.String }, { text: ';', type: StandardTokenType.Other }], '{', 1), true);
|
||||
assert.equal(testShouldAutoClose(sup, [{ text: 'x=', type: StandardTokenType.Other }, { text: '"a"', type: StandardTokenType.String }, { text: ';', type: StandardTokenType.Other }], 'a', 1), true);
|
||||
assert.equal(testShouldAutoClose(sup, [{ text: 'x=', type: StandardTokenType.Other }, { text: '"a"', type: StandardTokenType.String }, { text: ';', type: StandardTokenType.Other }], '{', 2), true);
|
||||
assert.equal(testShouldAutoClose(sup, [{ text: 'x=', type: StandardTokenType.Other }, { text: '"a"', type: StandardTokenType.String }, { text: ';', type: StandardTokenType.Other }], 'a', 2), true);
|
||||
assert.equal(testShouldAutoClose(sup, [{ text: 'x=', type: StandardTokenType.Other }, { text: '"a"', type: StandardTokenType.String }, { text: ';', type: StandardTokenType.Other }], '{', 3), true);
|
||||
assert.equal(testShouldAutoClose(sup, [{ text: 'x=', type: StandardTokenType.Other }, { text: '"a"', type: StandardTokenType.String }, { text: ';', type: StandardTokenType.Other }], 'a', 3), true);
|
||||
assert.equal(testShouldAutoClose(sup, [{ text: 'x=', type: StandardTokenType.Other }, { text: '"a"', type: StandardTokenType.String }, { text: ';', type: StandardTokenType.Other }], '{', 4), false);
|
||||
assert.equal(testShouldAutoClose(sup, [{ text: 'x=', type: StandardTokenType.Other }, { text: '"a"', type: StandardTokenType.String }, { text: ';', type: StandardTokenType.Other }], 'a', 4), true);
|
||||
assert.equal(testShouldAutoClose(sup, [{ text: 'x=', type: StandardTokenType.Other }, { text: '"a"', type: StandardTokenType.String }, { text: ';', type: StandardTokenType.Other }], '{', 5), false);
|
||||
assert.equal(testShouldAutoClose(sup, [{ text: 'x=', type: StandardTokenType.Other }, { text: '"a"', type: StandardTokenType.String }, { text: ';', type: StandardTokenType.Other }], 'a', 5), true);
|
||||
assert.equal(testShouldAutoClose(sup, [{ text: 'x=', type: StandardTokenType.Other }, { text: '"a"', type: StandardTokenType.String }, { text: ';', type: StandardTokenType.Other }], '{', 6), false);
|
||||
assert.equal(testShouldAutoClose(sup, [{ text: 'x=', type: StandardTokenType.Other }, { text: '"a"', type: StandardTokenType.String }, { text: ';', type: StandardTokenType.Other }], 'a', 6), true);
|
||||
assert.equal(testShouldAutoClose(sup, [{ text: 'x=', type: StandardTokenType.Other }, { text: '"a"', type: StandardTokenType.String }, { text: ';', type: StandardTokenType.Other }], '{', 7), true);
|
||||
assert.equal(testShouldAutoClose(sup, [{ text: 'x=', type: StandardTokenType.Other }, { text: '"a"', type: StandardTokenType.String }, { text: ';', type: StandardTokenType.Other }], 'a', 7), true);
|
||||
});
|
||||
|
||||
test('shouldAutoClosePair in interesting line 3', () => {
|
||||
let sup = new CharacterPairSupport({ autoClosingPairs: [{ open: '{', close: '}', notIn: ['string', 'comment'] }] });
|
||||
assert.equal(testShouldAutoClose(sup, [{ text: ' ', type: StandardTokenType.Other }, { text: '//a', type: StandardTokenType.Comment }], '{', 1), true);
|
||||
assert.equal(testShouldAutoClose(sup, [{ text: ' ', type: StandardTokenType.Other }, { text: '//a', type: StandardTokenType.Comment }], 'a', 1), true);
|
||||
assert.equal(testShouldAutoClose(sup, [{ text: ' ', type: StandardTokenType.Other }, { text: '//a', type: StandardTokenType.Comment }], '{', 2), true);
|
||||
assert.equal(testShouldAutoClose(sup, [{ text: ' ', type: StandardTokenType.Other }, { text: '//a', type: StandardTokenType.Comment }], 'a', 2), true);
|
||||
assert.equal(testShouldAutoClose(sup, [{ text: ' ', type: StandardTokenType.Other }, { text: '//a', type: StandardTokenType.Comment }], '{', 3), false);
|
||||
assert.equal(testShouldAutoClose(sup, [{ text: ' ', type: StandardTokenType.Other }, { text: '//a', type: StandardTokenType.Comment }], 'a', 3), true);
|
||||
assert.equal(testShouldAutoClose(sup, [{ text: ' ', type: StandardTokenType.Other }, { text: '//a', type: StandardTokenType.Comment }], '{', 4), false);
|
||||
assert.equal(testShouldAutoClose(sup, [{ text: ' ', type: StandardTokenType.Other }, { text: '//a', type: StandardTokenType.Comment }], 'a', 4), true);
|
||||
assert.equal(testShouldAutoClose(sup, [{ text: ' ', type: StandardTokenType.Other }, { text: '//a', type: StandardTokenType.Comment }], '{', 5), false);
|
||||
assert.equal(testShouldAutoClose(sup, [{ text: ' ', type: StandardTokenType.Other }, { text: '//a', type: StandardTokenType.Comment }], 'a', 5), true);
|
||||
});
|
||||
|
||||
});
|
||||
@@ -0,0 +1,128 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { BracketElectricCharacterSupport, IElectricAction } from 'vs/editor/common/modes/supports/electricCharacter';
|
||||
import { createFakeScopedLineTokens, TokenText } from 'vs/editor/test/common/modesTestUtils';
|
||||
import { RichEditBrackets } from 'vs/editor/common/modes/supports/richEditBrackets';
|
||||
import { LanguageIdentifier, StandardTokenType } from 'vs/editor/common/modes';
|
||||
|
||||
const fakeLanguageIdentifier = new LanguageIdentifier('test', 3);
|
||||
|
||||
suite('Editor Modes - Auto Indentation', () => {
|
||||
function _testOnElectricCharacter(electricCharacterSupport: BracketElectricCharacterSupport, line: TokenText[], character: string, offset: number): IElectricAction {
|
||||
return electricCharacterSupport.onElectricCharacter(character, createFakeScopedLineTokens(line), offset);
|
||||
}
|
||||
|
||||
function testDoesNothing(electricCharacterSupport: BracketElectricCharacterSupport, line: TokenText[], character: string, offset: number): void {
|
||||
let actual = _testOnElectricCharacter(electricCharacterSupport, line, character, offset);
|
||||
assert.deepEqual(actual, null);
|
||||
}
|
||||
|
||||
function testAppends(electricCharacterSupport: BracketElectricCharacterSupport, line: TokenText[], character: string, offset: number, appendText: string): void {
|
||||
let actual = _testOnElectricCharacter(electricCharacterSupport, line, character, offset);
|
||||
assert.deepEqual(actual, { appendText: appendText });
|
||||
}
|
||||
|
||||
function testMatchBracket(electricCharacterSupport: BracketElectricCharacterSupport, line: TokenText[], character: string, offset: number, matchOpenBracket: string): void {
|
||||
let actual = _testOnElectricCharacter(electricCharacterSupport, line, character, offset);
|
||||
assert.deepEqual(actual, { matchOpenBracket: matchOpenBracket });
|
||||
}
|
||||
|
||||
test('Doc comments', () => {
|
||||
var brackets = new BracketElectricCharacterSupport(null, [{ open: '/**', close: ' */' }], null);
|
||||
|
||||
testAppends(brackets, [
|
||||
{ text: '/*', type: StandardTokenType.Other },
|
||||
], '*', 3, ' */');
|
||||
|
||||
testDoesNothing(brackets, [
|
||||
{ text: '/*', type: StandardTokenType.Other },
|
||||
{ text: ' ', type: StandardTokenType.Other },
|
||||
{ text: '*/', type: StandardTokenType.Other },
|
||||
], '*', 3);
|
||||
});
|
||||
|
||||
test('getElectricCharacters uses all sources and dedups', () => {
|
||||
var sup = new BracketElectricCharacterSupport(
|
||||
new RichEditBrackets(fakeLanguageIdentifier, [
|
||||
['{', '}'],
|
||||
['(', ')']
|
||||
]), [
|
||||
{ open: '{', close: '}', notIn: ['string', 'comment'] },
|
||||
{ open: '"', close: '"', notIn: ['string', 'comment'] },
|
||||
{ open: 'begin', close: 'end', notIn: ['string'] }
|
||||
],
|
||||
{ docComment: { open: '/**', close: ' */' } }
|
||||
);
|
||||
|
||||
assert.deepEqual(sup.getElectricCharacters(), ['}', ')', 'n', '*']);
|
||||
});
|
||||
|
||||
test('auto-close', () => {
|
||||
var sup = new BracketElectricCharacterSupport(
|
||||
new RichEditBrackets(fakeLanguageIdentifier, [
|
||||
['{', '}'],
|
||||
['(', ')']
|
||||
]), [
|
||||
{ open: '{', close: '}', notIn: ['string', 'comment'] },
|
||||
{ open: '"', close: '"', notIn: ['string', 'comment'] },
|
||||
{ open: 'begin', close: 'end', notIn: ['string'] }
|
||||
],
|
||||
{ docComment: { open: '/**', close: ' */' } }
|
||||
);
|
||||
|
||||
testDoesNothing(sup, [], 'a', 0);
|
||||
|
||||
testDoesNothing(sup, [{ text: 'egi', type: StandardTokenType.Other }], 'b', 1);
|
||||
testDoesNothing(sup, [{ text: 'bgi', type: StandardTokenType.Other }], 'e', 2);
|
||||
testDoesNothing(sup, [{ text: 'bei', type: StandardTokenType.Other }], 'g', 3);
|
||||
testDoesNothing(sup, [{ text: 'beg', type: StandardTokenType.Other }], 'i', 4);
|
||||
|
||||
testDoesNothing(sup, [{ text: 'egin', type: StandardTokenType.Other }], 'b', 1);
|
||||
testDoesNothing(sup, [{ text: 'bgin', type: StandardTokenType.Other }], 'e', 2);
|
||||
testDoesNothing(sup, [{ text: 'bein', type: StandardTokenType.Other }], 'g', 3);
|
||||
testDoesNothing(sup, [{ text: 'begn', type: StandardTokenType.Other }], 'i', 4);
|
||||
testAppends(sup, [{ text: 'begi', type: StandardTokenType.Other }], 'n', 5, 'end');
|
||||
|
||||
testDoesNothing(sup, [{ text: '3gin', type: StandardTokenType.Other }], 'b', 1);
|
||||
testDoesNothing(sup, [{ text: 'bgin', type: StandardTokenType.Other }], '3', 2);
|
||||
testDoesNothing(sup, [{ text: 'b3in', type: StandardTokenType.Other }], 'g', 3);
|
||||
testDoesNothing(sup, [{ text: 'b3gn', type: StandardTokenType.Other }], 'i', 4);
|
||||
testDoesNothing(sup, [{ text: 'b3gi', type: StandardTokenType.Other }], 'n', 5);
|
||||
|
||||
testDoesNothing(sup, [{ text: 'begi', type: StandardTokenType.String }], 'n', 5);
|
||||
|
||||
testAppends(sup, [{ text: '"', type: StandardTokenType.String }, { text: 'begi', type: StandardTokenType.Other }], 'n', 6, 'end');
|
||||
testDoesNothing(sup, [{ text: '"', type: StandardTokenType.String }, { text: 'begi', type: StandardTokenType.String }], 'n', 6);
|
||||
|
||||
testAppends(sup, [{ text: '/*', type: StandardTokenType.String }], '*', 3, ' */');
|
||||
|
||||
testDoesNothing(sup, [{ text: 'begi', type: StandardTokenType.Other }, { text: 'end', type: StandardTokenType.Other }], 'n', 5);
|
||||
});
|
||||
|
||||
test('matchOpenBracket', () => {
|
||||
var sup = new BracketElectricCharacterSupport(
|
||||
new RichEditBrackets(fakeLanguageIdentifier, [
|
||||
['{', '}'],
|
||||
['(', ')']
|
||||
]), [
|
||||
{ open: '{', close: '}', notIn: ['string', 'comment'] },
|
||||
{ open: '"', close: '"', notIn: ['string', 'comment'] },
|
||||
{ open: 'begin', close: 'end', notIn: ['string'] }
|
||||
],
|
||||
{ docComment: { open: '/**', close: ' */' } }
|
||||
);
|
||||
|
||||
testDoesNothing(sup, [{ text: '\t{', type: StandardTokenType.Other }], '\t', 1);
|
||||
testDoesNothing(sup, [{ text: '\t{', type: StandardTokenType.Other }], '\t', 2);
|
||||
testDoesNothing(sup, [{ text: '\t\t', type: StandardTokenType.Other }], '{', 3);
|
||||
|
||||
testDoesNothing(sup, [{ text: '\t}', type: StandardTokenType.Other }], '\t', 1);
|
||||
testDoesNothing(sup, [{ text: '\t}', type: StandardTokenType.Other }], '\t', 2);
|
||||
testMatchBracket(sup, [{ text: '\t\t', type: StandardTokenType.Other }], '}', 3, '}');
|
||||
});
|
||||
});
|
||||
128
src/vs/editor/test/common/modes/supports/onEnter.test.ts
Normal file
128
src/vs/editor/test/common/modes/supports/onEnter.test.ts
Normal file
@@ -0,0 +1,128 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { CharacterPair, IndentAction } from 'vs/editor/common/modes/languageConfiguration';
|
||||
import { OnEnterSupport } from 'vs/editor/common/modes/supports/onEnter';
|
||||
|
||||
suite('OnEnter', () => {
|
||||
|
||||
test('uses brackets', () => {
|
||||
var brackets: CharacterPair[] = [
|
||||
['(', ')'],
|
||||
['begin', 'end']
|
||||
];
|
||||
var support = new OnEnterSupport({
|
||||
brackets: brackets
|
||||
});
|
||||
var testIndentAction = (beforeText: string, afterText: string, expected: IndentAction) => {
|
||||
var actual = support.onEnter('', beforeText, afterText);
|
||||
if (expected === IndentAction.None) {
|
||||
assert.equal(actual, null);
|
||||
} else {
|
||||
assert.equal(actual.indentAction, expected);
|
||||
}
|
||||
};
|
||||
|
||||
testIndentAction('a', '', IndentAction.None);
|
||||
testIndentAction('', 'b', IndentAction.None);
|
||||
testIndentAction('(', 'b', IndentAction.Indent);
|
||||
testIndentAction('a', ')', IndentAction.None);
|
||||
testIndentAction('begin', 'ending', IndentAction.Indent);
|
||||
testIndentAction('abegin', 'end', IndentAction.None);
|
||||
testIndentAction('begin', ')', IndentAction.Indent);
|
||||
testIndentAction('begin', 'end', IndentAction.IndentOutdent);
|
||||
testIndentAction('begin ', ' end', IndentAction.IndentOutdent);
|
||||
testIndentAction(' begin', 'end//as', IndentAction.IndentOutdent);
|
||||
testIndentAction('(', ')', IndentAction.IndentOutdent);
|
||||
testIndentAction('( ', ')', IndentAction.IndentOutdent);
|
||||
testIndentAction('a(', ')b', IndentAction.IndentOutdent);
|
||||
|
||||
testIndentAction('(', '', IndentAction.Indent);
|
||||
testIndentAction('(', 'foo', IndentAction.Indent);
|
||||
testIndentAction('begin', 'foo', IndentAction.Indent);
|
||||
testIndentAction('begin', '', IndentAction.Indent);
|
||||
});
|
||||
|
||||
test('uses regExpRules', () => {
|
||||
var support = new OnEnterSupport({
|
||||
regExpRules: [
|
||||
{
|
||||
beforeText: /^\s*\/\*\*(?!\/)([^\*]|\*(?!\/))*$/,
|
||||
afterText: /^\s*\*\/$/,
|
||||
action: { indentAction: IndentAction.IndentOutdent, appendText: ' * ' }
|
||||
},
|
||||
{
|
||||
beforeText: /^\s*\/\*\*(?!\/)([^\*]|\*(?!\/))*$/,
|
||||
action: { indentAction: IndentAction.None, appendText: ' * ' }
|
||||
},
|
||||
{
|
||||
beforeText: /^(\t|(\ \ ))*\ \*(\ ([^\*]|\*(?!\/))*)?$/,
|
||||
action: { indentAction: IndentAction.None, appendText: '* ' }
|
||||
},
|
||||
{
|
||||
beforeText: /^(\t|(\ \ ))*\ \*\/\s*$/,
|
||||
action: { indentAction: IndentAction.None, removeText: 1 }
|
||||
},
|
||||
{
|
||||
beforeText: /^(\t|(\ \ ))*\ \*[^/]*\*\/\s*$/,
|
||||
action: { indentAction: IndentAction.None, removeText: 1 }
|
||||
}
|
||||
]
|
||||
});
|
||||
var testIndentAction = (beforeText: string, afterText: string, expectedIndentAction: IndentAction, expectedAppendText: string, removeText: number = 0) => {
|
||||
var actual = support.onEnter('', beforeText, afterText);
|
||||
if (expectedIndentAction === null) {
|
||||
assert.equal(actual, null, 'isNull:' + beforeText);
|
||||
} else {
|
||||
assert.equal(actual !== null, true, 'isNotNull:' + beforeText);
|
||||
assert.equal(actual.indentAction, expectedIndentAction, 'indentAction:' + beforeText);
|
||||
if (expectedAppendText !== null) {
|
||||
assert.equal(actual.appendText, expectedAppendText, 'appendText:' + beforeText);
|
||||
}
|
||||
if (removeText !== 0) {
|
||||
assert.equal(actual.removeText, removeText, 'removeText:' + beforeText);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
testIndentAction('\t/**', ' */', IndentAction.IndentOutdent, ' * ');
|
||||
testIndentAction('\t/**', '', IndentAction.None, ' * ');
|
||||
testIndentAction('\t/** * / * / * /', '', IndentAction.None, ' * ');
|
||||
testIndentAction('\t/** /*', '', IndentAction.None, ' * ');
|
||||
testIndentAction('/**', '', IndentAction.None, ' * ');
|
||||
testIndentAction('\t/**/', '', null, null);
|
||||
testIndentAction('\t/***/', '', null, null);
|
||||
testIndentAction('\t/*******/', '', null, null);
|
||||
testIndentAction('\t/** * * * * */', '', null, null);
|
||||
testIndentAction('\t/** */', '', null, null);
|
||||
testIndentAction('\t/** asdfg */', '', null, null);
|
||||
testIndentAction('\t/* asdfg */', '', null, null);
|
||||
testIndentAction('\t/* asdfg */', '', null, null);
|
||||
testIndentAction('\t/** asdfg */', '', null, null);
|
||||
testIndentAction('*/', '', null, null);
|
||||
testIndentAction('\t/*', '', null, null);
|
||||
testIndentAction('\t*', '', null, null);
|
||||
testIndentAction('\t *', '', IndentAction.None, '* ');
|
||||
testIndentAction('\t */', '', IndentAction.None, null, 1);
|
||||
testIndentAction('\t * */', '', IndentAction.None, null, 1);
|
||||
testIndentAction('\t * * / * / * / */', '', null, null);
|
||||
testIndentAction('\t * ', '', IndentAction.None, '* ');
|
||||
testIndentAction(' * ', '', IndentAction.None, '* ');
|
||||
testIndentAction(' * asdfsfagadfg', '', IndentAction.None, '* ');
|
||||
testIndentAction(' * asdfsfagadfg * * * ', '', IndentAction.None, '* ');
|
||||
testIndentAction(' * /*', '', IndentAction.None, '* ');
|
||||
testIndentAction(' * asdfsfagadfg * / * / * /', '', IndentAction.None, '* ');
|
||||
testIndentAction(' * asdfsfagadfg * / * / * /*', '', IndentAction.None, '* ');
|
||||
testIndentAction(' */', '', IndentAction.None, null, 1);
|
||||
testIndentAction('\t */', '', IndentAction.None, null, 1);
|
||||
testIndentAction('\t\t */', '', IndentAction.None, null, 1);
|
||||
testIndentAction(' */', '', IndentAction.None, null, 1);
|
||||
testIndentAction(' */', '', IndentAction.None, null, 1);
|
||||
testIndentAction('\t */', '', IndentAction.None, null, 1);
|
||||
testIndentAction(' *--------------------------------------------------------------------------------------------*/', '', IndentAction.None, null, 1);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,75 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { BracketsUtils } from 'vs/editor/common/modes/supports/richEditBrackets';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
|
||||
suite('richEditBrackets', () => {
|
||||
|
||||
function findPrevBracketInToken(reversedBracketRegex: RegExp, lineText: string, currentTokenStart: number, currentTokenEnd: number): Range {
|
||||
return BracketsUtils.findPrevBracketInToken(reversedBracketRegex, 1, lineText, currentTokenStart, currentTokenEnd);
|
||||
}
|
||||
|
||||
function findNextBracketInToken(forwardBracketRegex: RegExp, lineText: string, currentTokenStart: number, currentTokenEnd: number): Range {
|
||||
return BracketsUtils.findNextBracketInToken(forwardBracketRegex, 1, lineText, currentTokenStart, currentTokenEnd);
|
||||
}
|
||||
|
||||
test('findPrevBracketInToken one char 1', () => {
|
||||
let result = findPrevBracketInToken(/(\{)|(\})/i, '{', 0, 1);
|
||||
assert.equal(result.startColumn, 1);
|
||||
assert.equal(result.endColumn, 2);
|
||||
});
|
||||
|
||||
test('findPrevBracketInToken one char 2', () => {
|
||||
let result = findPrevBracketInToken(/(\{)|(\})/i, '{{', 0, 1);
|
||||
assert.equal(result.startColumn, 1);
|
||||
assert.equal(result.endColumn, 2);
|
||||
});
|
||||
|
||||
test('findPrevBracketInToken one char 3', () => {
|
||||
let result = findPrevBracketInToken(/(\{)|(\})/i, '{hello world!', 0, 13);
|
||||
assert.equal(result.startColumn, 1);
|
||||
assert.equal(result.endColumn, 2);
|
||||
});
|
||||
|
||||
test('findPrevBracketInToken more chars 1', () => {
|
||||
let result = findPrevBracketInToken(/(olleh)/i, 'hello world!', 0, 12);
|
||||
assert.equal(result.startColumn, 1);
|
||||
assert.equal(result.endColumn, 6);
|
||||
});
|
||||
|
||||
test('findPrevBracketInToken more chars 2', () => {
|
||||
let result = findPrevBracketInToken(/(olleh)/i, 'hello world!', 0, 5);
|
||||
assert.equal(result.startColumn, 1);
|
||||
assert.equal(result.endColumn, 6);
|
||||
});
|
||||
|
||||
test('findPrevBracketInToken more chars 3', () => {
|
||||
let result = findPrevBracketInToken(/(olleh)/i, ' hello world!', 0, 6);
|
||||
assert.equal(result.startColumn, 2);
|
||||
assert.equal(result.endColumn, 7);
|
||||
});
|
||||
|
||||
test('findNextBracketInToken one char', () => {
|
||||
let result = findNextBracketInToken(/(\{)|(\})/i, '{', 0, 1);
|
||||
assert.equal(result.startColumn, 1);
|
||||
assert.equal(result.endColumn, 2);
|
||||
});
|
||||
|
||||
test('findNextBracketInToken more chars', () => {
|
||||
let result = findNextBracketInToken(/(world)/i, 'hello world!', 0, 12);
|
||||
assert.equal(result.startColumn, 7);
|
||||
assert.equal(result.endColumn, 12);
|
||||
});
|
||||
|
||||
test('issue #3894: [Handlebars] Curly braces edit issues', () => {
|
||||
let result = findPrevBracketInToken(/(\-\-!<)|(>\-\-)|(\{\{)|(\}\})/i, '{{asd}}', 0, 2);
|
||||
assert.equal(result.startColumn, 1);
|
||||
assert.equal(result.endColumn, 3);
|
||||
});
|
||||
|
||||
});
|
||||
333
src/vs/editor/test/common/modes/supports/tokenization.test.ts
Normal file
333
src/vs/editor/test/common/modes/supports/tokenization.test.ts
Normal file
@@ -0,0 +1,333 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { strcmp, parseTokenTheme, TokenTheme, ParsedTokenThemeRule, ColorMap, ExternalThemeTrieElement, ThemeTrieElementRule } from 'vs/editor/common/modes/supports/tokenization';
|
||||
import { FontStyle } from 'vs/editor/common/modes';
|
||||
|
||||
suite('Token theme matching', () => {
|
||||
|
||||
test('gives higher priority to deeper matches', () => {
|
||||
let theme = TokenTheme.createFromRawTokenTheme([
|
||||
{ token: '', foreground: '100000', background: '200000' },
|
||||
{ token: 'punctuation.definition.string.begin.html', foreground: '300000' },
|
||||
{ token: 'punctuation.definition.string', foreground: '400000' },
|
||||
]);
|
||||
|
||||
let colorMap = new ColorMap();
|
||||
colorMap.getId('100000');
|
||||
const _B = colorMap.getId('200000');
|
||||
colorMap.getId('400000');
|
||||
const _D = colorMap.getId('300000');
|
||||
|
||||
let actual = theme._match('punctuation.definition.string.begin.html');
|
||||
|
||||
assert.deepEqual(actual, new ThemeTrieElementRule(FontStyle.None, _D, _B));
|
||||
});
|
||||
|
||||
test('can match', () => {
|
||||
let theme = TokenTheme.createFromRawTokenTheme([
|
||||
{ token: '', foreground: 'F8F8F2', background: '272822' },
|
||||
{ token: 'source', background: '100000' },
|
||||
{ token: 'something', background: '100000' },
|
||||
{ token: 'bar', background: '200000' },
|
||||
{ token: 'baz', background: '200000' },
|
||||
{ token: 'bar', fontStyle: 'bold' },
|
||||
{ token: 'constant', fontStyle: 'italic', foreground: '300000' },
|
||||
{ token: 'constant.numeric', foreground: '400000' },
|
||||
{ token: 'constant.numeric.hex', fontStyle: 'bold' },
|
||||
{ token: 'constant.numeric.oct', fontStyle: 'bold italic underline' },
|
||||
{ token: 'constant.numeric.dec', fontStyle: '', foreground: '500000' },
|
||||
{ token: 'storage.object.bar', fontStyle: '', foreground: '600000' },
|
||||
]);
|
||||
|
||||
let colorMap = new ColorMap();
|
||||
const _A = colorMap.getId('F8F8F2');
|
||||
const _B = colorMap.getId('272822');
|
||||
const _C = colorMap.getId('200000');
|
||||
const _D = colorMap.getId('300000');
|
||||
const _E = colorMap.getId('400000');
|
||||
const _F = colorMap.getId('500000');
|
||||
const _G = colorMap.getId('100000');
|
||||
const _H = colorMap.getId('600000');
|
||||
|
||||
function assertMatch(scopeName: string, expected: ThemeTrieElementRule): void {
|
||||
let actual = theme._match(scopeName);
|
||||
assert.deepEqual(actual, expected, 'when matching <<' + scopeName + '>>');
|
||||
}
|
||||
|
||||
function assertSimpleMatch(scopeName: string, fontStyle: FontStyle, foreground: number, background: number): void {
|
||||
assertMatch(scopeName, new ThemeTrieElementRule(fontStyle, foreground, background));
|
||||
}
|
||||
|
||||
function assertNoMatch(scopeName: string): void {
|
||||
assertMatch(scopeName, new ThemeTrieElementRule(FontStyle.None, _A, _B));
|
||||
}
|
||||
|
||||
// matches defaults
|
||||
assertNoMatch('');
|
||||
assertNoMatch('bazz');
|
||||
assertNoMatch('asdfg');
|
||||
|
||||
// matches source
|
||||
assertSimpleMatch('source', FontStyle.None, _A, _G);
|
||||
assertSimpleMatch('source.ts', FontStyle.None, _A, _G);
|
||||
assertSimpleMatch('source.tss', FontStyle.None, _A, _G);
|
||||
|
||||
// matches something
|
||||
assertSimpleMatch('something', FontStyle.None, _A, _G);
|
||||
assertSimpleMatch('something.ts', FontStyle.None, _A, _G);
|
||||
assertSimpleMatch('something.tss', FontStyle.None, _A, _G);
|
||||
|
||||
// matches baz
|
||||
assertSimpleMatch('baz', FontStyle.None, _A, _C);
|
||||
assertSimpleMatch('baz.ts', FontStyle.None, _A, _C);
|
||||
assertSimpleMatch('baz.tss', FontStyle.None, _A, _C);
|
||||
|
||||
// matches constant
|
||||
assertSimpleMatch('constant', FontStyle.Italic, _D, _B);
|
||||
assertSimpleMatch('constant.string', FontStyle.Italic, _D, _B);
|
||||
assertSimpleMatch('constant.hex', FontStyle.Italic, _D, _B);
|
||||
|
||||
// matches constant.numeric
|
||||
assertSimpleMatch('constant.numeric', FontStyle.Italic, _E, _B);
|
||||
assertSimpleMatch('constant.numeric.baz', FontStyle.Italic, _E, _B);
|
||||
|
||||
// matches constant.numeric.hex
|
||||
assertSimpleMatch('constant.numeric.hex', FontStyle.Bold, _E, _B);
|
||||
assertSimpleMatch('constant.numeric.hex.baz', FontStyle.Bold, _E, _B);
|
||||
|
||||
// matches constant.numeric.oct
|
||||
assertSimpleMatch('constant.numeric.oct', FontStyle.Bold | FontStyle.Italic | FontStyle.Underline, _E, _B);
|
||||
assertSimpleMatch('constant.numeric.oct.baz', FontStyle.Bold | FontStyle.Italic | FontStyle.Underline, _E, _B);
|
||||
|
||||
// matches constant.numeric.dec
|
||||
assertSimpleMatch('constant.numeric.dec', FontStyle.None, _F, _B);
|
||||
assertSimpleMatch('constant.numeric.dec.baz', FontStyle.None, _F, _B);
|
||||
|
||||
// matches storage.object.bar
|
||||
assertSimpleMatch('storage.object.bar', FontStyle.None, _H, _B);
|
||||
assertSimpleMatch('storage.object.bar.baz', FontStyle.None, _H, _B);
|
||||
|
||||
// does not match storage.object.bar
|
||||
assertSimpleMatch('storage.object.bart', FontStyle.None, _A, _B);
|
||||
assertSimpleMatch('storage.object', FontStyle.None, _A, _B);
|
||||
assertSimpleMatch('storage', FontStyle.None, _A, _B);
|
||||
|
||||
assertSimpleMatch('bar', FontStyle.Bold, _A, _C);
|
||||
});
|
||||
});
|
||||
|
||||
suite('Token theme parsing', () => {
|
||||
|
||||
test('can parse', () => {
|
||||
|
||||
let actual = parseTokenTheme([
|
||||
{ token: '', foreground: 'F8F8F2', background: '272822' },
|
||||
{ token: 'source', background: '100000' },
|
||||
{ token: 'something', background: '100000' },
|
||||
{ token: 'bar', background: '010000' },
|
||||
{ token: 'baz', background: '010000' },
|
||||
{ token: 'bar', fontStyle: 'bold' },
|
||||
{ token: 'constant', fontStyle: 'italic', foreground: 'ff0000' },
|
||||
{ token: 'constant.numeric', foreground: '00ff00' },
|
||||
{ token: 'constant.numeric.hex', fontStyle: 'bold' },
|
||||
{ token: 'constant.numeric.oct', fontStyle: 'bold italic underline' },
|
||||
{ token: 'constant.numeric.dec', fontStyle: '', foreground: '0000ff' },
|
||||
]);
|
||||
|
||||
let expected = [
|
||||
new ParsedTokenThemeRule('', 0, FontStyle.NotSet, 'F8F8F2', '272822'),
|
||||
new ParsedTokenThemeRule('source', 1, FontStyle.NotSet, null, '100000'),
|
||||
new ParsedTokenThemeRule('something', 2, FontStyle.NotSet, null, '100000'),
|
||||
new ParsedTokenThemeRule('bar', 3, FontStyle.NotSet, null, '010000'),
|
||||
new ParsedTokenThemeRule('baz', 4, FontStyle.NotSet, null, '010000'),
|
||||
new ParsedTokenThemeRule('bar', 5, FontStyle.Bold, null, null),
|
||||
new ParsedTokenThemeRule('constant', 6, FontStyle.Italic, 'ff0000', null),
|
||||
new ParsedTokenThemeRule('constant.numeric', 7, FontStyle.NotSet, '00ff00', null),
|
||||
new ParsedTokenThemeRule('constant.numeric.hex', 8, FontStyle.Bold, null, null),
|
||||
new ParsedTokenThemeRule('constant.numeric.oct', 9, FontStyle.Bold | FontStyle.Italic | FontStyle.Underline, null, null),
|
||||
new ParsedTokenThemeRule('constant.numeric.dec', 10, FontStyle.None, '0000ff', null),
|
||||
];
|
||||
|
||||
assert.deepEqual(actual, expected);
|
||||
});
|
||||
});
|
||||
|
||||
suite('Token theme resolving', () => {
|
||||
|
||||
test('strcmp works', () => {
|
||||
let actual = ['bar', 'z', 'zu', 'a', 'ab', ''].sort(strcmp);
|
||||
|
||||
let expected = ['', 'a', 'ab', 'bar', 'z', 'zu'];
|
||||
assert.deepEqual(actual, expected);
|
||||
});
|
||||
|
||||
test('always has defaults', () => {
|
||||
let actual = TokenTheme.createFromParsedTokenTheme([]);
|
||||
let colorMap = new ColorMap();
|
||||
const _A = colorMap.getId('000000');
|
||||
const _B = colorMap.getId('ffffff');
|
||||
assert.deepEqual(actual.getColorMap(), colorMap.getColorMap());
|
||||
assert.deepEqual(actual.getThemeTrieElement(), new ExternalThemeTrieElement(new ThemeTrieElementRule(FontStyle.None, _A, _B)));
|
||||
});
|
||||
|
||||
test('respects incoming defaults 1', () => {
|
||||
let actual = TokenTheme.createFromParsedTokenTheme([
|
||||
new ParsedTokenThemeRule('', -1, FontStyle.NotSet, null, null)
|
||||
]);
|
||||
let colorMap = new ColorMap();
|
||||
const _A = colorMap.getId('000000');
|
||||
const _B = colorMap.getId('ffffff');
|
||||
assert.deepEqual(actual.getColorMap(), colorMap.getColorMap());
|
||||
assert.deepEqual(actual.getThemeTrieElement(), new ExternalThemeTrieElement(new ThemeTrieElementRule(FontStyle.None, _A, _B)));
|
||||
});
|
||||
|
||||
test('respects incoming defaults 2', () => {
|
||||
let actual = TokenTheme.createFromParsedTokenTheme([
|
||||
new ParsedTokenThemeRule('', -1, FontStyle.None, null, null)
|
||||
]);
|
||||
let colorMap = new ColorMap();
|
||||
const _A = colorMap.getId('000000');
|
||||
const _B = colorMap.getId('ffffff');
|
||||
assert.deepEqual(actual.getColorMap(), colorMap.getColorMap());
|
||||
assert.deepEqual(actual.getThemeTrieElement(), new ExternalThemeTrieElement(new ThemeTrieElementRule(FontStyle.None, _A, _B)));
|
||||
});
|
||||
|
||||
test('respects incoming defaults 3', () => {
|
||||
let actual = TokenTheme.createFromParsedTokenTheme([
|
||||
new ParsedTokenThemeRule('', -1, FontStyle.Bold, null, null)
|
||||
]);
|
||||
let colorMap = new ColorMap();
|
||||
const _A = colorMap.getId('000000');
|
||||
const _B = colorMap.getId('ffffff');
|
||||
assert.deepEqual(actual.getColorMap(), colorMap.getColorMap());
|
||||
assert.deepEqual(actual.getThemeTrieElement(), new ExternalThemeTrieElement(new ThemeTrieElementRule(FontStyle.Bold, _A, _B)));
|
||||
});
|
||||
|
||||
test('respects incoming defaults 4', () => {
|
||||
let actual = TokenTheme.createFromParsedTokenTheme([
|
||||
new ParsedTokenThemeRule('', -1, FontStyle.NotSet, 'ff0000', null)
|
||||
]);
|
||||
let colorMap = new ColorMap();
|
||||
const _A = colorMap.getId('ff0000');
|
||||
const _B = colorMap.getId('ffffff');
|
||||
assert.deepEqual(actual.getColorMap(), colorMap.getColorMap());
|
||||
assert.deepEqual(actual.getThemeTrieElement(), new ExternalThemeTrieElement(new ThemeTrieElementRule(FontStyle.None, _A, _B)));
|
||||
});
|
||||
|
||||
test('respects incoming defaults 5', () => {
|
||||
let actual = TokenTheme.createFromParsedTokenTheme([
|
||||
new ParsedTokenThemeRule('', -1, FontStyle.NotSet, null, 'ff0000')
|
||||
]);
|
||||
let colorMap = new ColorMap();
|
||||
const _A = colorMap.getId('000000');
|
||||
const _B = colorMap.getId('ff0000');
|
||||
assert.deepEqual(actual.getColorMap(), colorMap.getColorMap());
|
||||
assert.deepEqual(actual.getThemeTrieElement(), new ExternalThemeTrieElement(new ThemeTrieElementRule(FontStyle.None, _A, _B)));
|
||||
});
|
||||
|
||||
test('can merge incoming defaults', () => {
|
||||
let actual = TokenTheme.createFromParsedTokenTheme([
|
||||
new ParsedTokenThemeRule('', -1, FontStyle.NotSet, null, 'ff0000'),
|
||||
new ParsedTokenThemeRule('', -1, FontStyle.NotSet, '00ff00', null),
|
||||
new ParsedTokenThemeRule('', -1, FontStyle.Bold, null, null),
|
||||
]);
|
||||
let colorMap = new ColorMap();
|
||||
const _A = colorMap.getId('00ff00');
|
||||
const _B = colorMap.getId('ff0000');
|
||||
assert.deepEqual(actual.getColorMap(), colorMap.getColorMap());
|
||||
assert.deepEqual(actual.getThemeTrieElement(), new ExternalThemeTrieElement(new ThemeTrieElementRule(FontStyle.Bold, _A, _B)));
|
||||
});
|
||||
|
||||
test('defaults are inherited', () => {
|
||||
let actual = TokenTheme.createFromParsedTokenTheme([
|
||||
new ParsedTokenThemeRule('', -1, FontStyle.NotSet, 'F8F8F2', '272822'),
|
||||
new ParsedTokenThemeRule('var', -1, FontStyle.NotSet, 'ff0000', null)
|
||||
]);
|
||||
let colorMap = new ColorMap();
|
||||
const _A = colorMap.getId('F8F8F2');
|
||||
const _B = colorMap.getId('272822');
|
||||
const _C = colorMap.getId('ff0000');
|
||||
assert.deepEqual(actual.getColorMap(), colorMap.getColorMap());
|
||||
let root = new ExternalThemeTrieElement(new ThemeTrieElementRule(FontStyle.None, _A, _B), {
|
||||
'var': new ExternalThemeTrieElement(new ThemeTrieElementRule(FontStyle.None, _C, _B))
|
||||
});
|
||||
assert.deepEqual(actual.getThemeTrieElement(), root);
|
||||
});
|
||||
|
||||
test('same rules get merged', () => {
|
||||
let actual = TokenTheme.createFromParsedTokenTheme([
|
||||
new ParsedTokenThemeRule('', -1, FontStyle.NotSet, 'F8F8F2', '272822'),
|
||||
new ParsedTokenThemeRule('var', 1, FontStyle.Bold, null, null),
|
||||
new ParsedTokenThemeRule('var', 0, FontStyle.NotSet, 'ff0000', null),
|
||||
]);
|
||||
let colorMap = new ColorMap();
|
||||
const _A = colorMap.getId('F8F8F2');
|
||||
const _B = colorMap.getId('272822');
|
||||
const _C = colorMap.getId('ff0000');
|
||||
assert.deepEqual(actual.getColorMap(), colorMap.getColorMap());
|
||||
let root = new ExternalThemeTrieElement(new ThemeTrieElementRule(FontStyle.None, _A, _B), {
|
||||
'var': new ExternalThemeTrieElement(new ThemeTrieElementRule(FontStyle.Bold, _C, _B))
|
||||
});
|
||||
assert.deepEqual(actual.getThemeTrieElement(), root);
|
||||
});
|
||||
|
||||
test('rules are inherited 1', () => {
|
||||
let actual = TokenTheme.createFromParsedTokenTheme([
|
||||
new ParsedTokenThemeRule('', -1, FontStyle.NotSet, 'F8F8F2', '272822'),
|
||||
new ParsedTokenThemeRule('var', -1, FontStyle.Bold, 'ff0000', null),
|
||||
new ParsedTokenThemeRule('var.identifier', -1, FontStyle.NotSet, '00ff00', null),
|
||||
]);
|
||||
let colorMap = new ColorMap();
|
||||
const _A = colorMap.getId('F8F8F2');
|
||||
const _B = colorMap.getId('272822');
|
||||
const _C = colorMap.getId('ff0000');
|
||||
const _D = colorMap.getId('00ff00');
|
||||
assert.deepEqual(actual.getColorMap(), colorMap.getColorMap());
|
||||
let root = new ExternalThemeTrieElement(new ThemeTrieElementRule(FontStyle.None, _A, _B), {
|
||||
'var': new ExternalThemeTrieElement(new ThemeTrieElementRule(FontStyle.Bold, _C, _B), {
|
||||
'identifier': new ExternalThemeTrieElement(new ThemeTrieElementRule(FontStyle.Bold, _D, _B))
|
||||
})
|
||||
});
|
||||
assert.deepEqual(actual.getThemeTrieElement(), root);
|
||||
});
|
||||
|
||||
test('rules are inherited 2', () => {
|
||||
let actual = TokenTheme.createFromParsedTokenTheme([
|
||||
new ParsedTokenThemeRule('', -1, FontStyle.NotSet, 'F8F8F2', '272822'),
|
||||
new ParsedTokenThemeRule('var', -1, FontStyle.Bold, 'ff0000', null),
|
||||
new ParsedTokenThemeRule('var.identifier', -1, FontStyle.NotSet, '00ff00', null),
|
||||
new ParsedTokenThemeRule('constant', 4, FontStyle.Italic, '100000', null),
|
||||
new ParsedTokenThemeRule('constant.numeric', 5, FontStyle.NotSet, '200000', null),
|
||||
new ParsedTokenThemeRule('constant.numeric.hex', 6, FontStyle.Bold, null, null),
|
||||
new ParsedTokenThemeRule('constant.numeric.oct', 7, FontStyle.Bold | FontStyle.Italic | FontStyle.Underline, null, null),
|
||||
new ParsedTokenThemeRule('constant.numeric.dec', 8, FontStyle.None, '300000', null),
|
||||
]);
|
||||
let colorMap = new ColorMap();
|
||||
const _A = colorMap.getId('F8F8F2');
|
||||
const _B = colorMap.getId('272822');
|
||||
const _C = colorMap.getId('100000');
|
||||
const _D = colorMap.getId('200000');
|
||||
const _E = colorMap.getId('300000');
|
||||
const _F = colorMap.getId('ff0000');
|
||||
const _G = colorMap.getId('00ff00');
|
||||
assert.deepEqual(actual.getColorMap(), colorMap.getColorMap());
|
||||
let root = new ExternalThemeTrieElement(new ThemeTrieElementRule(FontStyle.None, _A, _B), {
|
||||
'var': new ExternalThemeTrieElement(new ThemeTrieElementRule(FontStyle.Bold, _F, _B), {
|
||||
'identifier': new ExternalThemeTrieElement(new ThemeTrieElementRule(FontStyle.Bold, _G, _B))
|
||||
}),
|
||||
'constant': new ExternalThemeTrieElement(new ThemeTrieElementRule(FontStyle.Italic, _C, _B), {
|
||||
'numeric': new ExternalThemeTrieElement(new ThemeTrieElementRule(FontStyle.Italic, _D, _B), {
|
||||
'hex': new ExternalThemeTrieElement(new ThemeTrieElementRule(FontStyle.Bold, _D, _B)),
|
||||
'oct': new ExternalThemeTrieElement(new ThemeTrieElementRule(FontStyle.Bold | FontStyle.Italic | FontStyle.Underline, _D, _B)),
|
||||
'dec': new ExternalThemeTrieElement(new ThemeTrieElementRule(FontStyle.None, _E, _B)),
|
||||
})
|
||||
})
|
||||
});
|
||||
assert.deepEqual(actual.getThemeTrieElement(), root);
|
||||
});
|
||||
});
|
||||
229
src/vs/editor/test/common/modes/textToHtmlTokenizer.test.ts
Normal file
229
src/vs/editor/test/common/modes/textToHtmlTokenizer.test.ts
Normal file
@@ -0,0 +1,229 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { TokenizationRegistry, IState, LanguageIdentifier, ColorId, FontStyle, MetadataConsts } from 'vs/editor/common/modes';
|
||||
import { tokenizeToString, tokenizeLineToHTML } from 'vs/editor/common/modes/textToHtmlTokenizer';
|
||||
import { MockMode } from 'vs/editor/test/common/mocks/mockMode';
|
||||
import { TokenizationResult2 } from 'vs/editor/common/core/token';
|
||||
import { ViewLineToken } from 'vs/editor/common/core/viewLineToken';
|
||||
|
||||
suite('Editor Modes - textToHtmlTokenizer', () => {
|
||||
function toStr(pieces: { className: string; text: string }[]): string {
|
||||
let resultArr = pieces.map((t) => `<span class="${t.className}">${t.text}</span>`);
|
||||
return resultArr.join('');
|
||||
}
|
||||
|
||||
test('TextToHtmlTokenizer 1', () => {
|
||||
let mode = new Mode();
|
||||
|
||||
let actual = tokenizeToString('.abc..def...gh', mode.getId());
|
||||
let expected = [
|
||||
{ className: 'mtk7', text: '.' },
|
||||
{ className: 'mtk9', text: 'abc' },
|
||||
{ className: 'mtk7', text: '..' },
|
||||
{ className: 'mtk9', text: 'def' },
|
||||
{ className: 'mtk7', text: '...' },
|
||||
{ className: 'mtk9', text: 'gh' },
|
||||
];
|
||||
let expectedStr = `<div class="monaco-tokenized-source">${toStr(expected)}</div>`;
|
||||
|
||||
assert.equal(actual, expectedStr);
|
||||
|
||||
mode.dispose();
|
||||
});
|
||||
|
||||
test('TextToHtmlTokenizer 2', () => {
|
||||
let mode = new Mode();
|
||||
|
||||
let actual = tokenizeToString('.abc..def...gh\n.abc..def...gh', mode.getId());
|
||||
let expected1 = [
|
||||
{ className: 'mtk7', text: '.' },
|
||||
{ className: 'mtk9', text: 'abc' },
|
||||
{ className: 'mtk7', text: '..' },
|
||||
{ className: 'mtk9', text: 'def' },
|
||||
{ className: 'mtk7', text: '...' },
|
||||
{ className: 'mtk9', text: 'gh' },
|
||||
];
|
||||
let expected2 = [
|
||||
{ className: 'mtk7', text: '.' },
|
||||
{ className: 'mtk9', text: 'abc' },
|
||||
{ className: 'mtk7', text: '..' },
|
||||
{ className: 'mtk9', text: 'def' },
|
||||
{ className: 'mtk7', text: '...' },
|
||||
{ className: 'mtk9', text: 'gh' },
|
||||
];
|
||||
let expectedStr1 = toStr(expected1);
|
||||
let expectedStr2 = toStr(expected2);
|
||||
let expectedStr = `<div class="monaco-tokenized-source">${expectedStr1}<br/>${expectedStr2}</div>`;
|
||||
|
||||
assert.equal(actual, expectedStr);
|
||||
|
||||
mode.dispose();
|
||||
});
|
||||
|
||||
test('tokenizeLineToHTML', () => {
|
||||
const text = 'Ciao hello world!';
|
||||
const lineTokens = [
|
||||
new ViewLineToken(
|
||||
4,
|
||||
(
|
||||
(3 << MetadataConsts.FOREGROUND_OFFSET)
|
||||
| ((FontStyle.Bold | FontStyle.Italic) << MetadataConsts.FONT_STYLE_OFFSET)
|
||||
) >>> 0
|
||||
),
|
||||
new ViewLineToken(
|
||||
5,
|
||||
(
|
||||
(1 << MetadataConsts.FOREGROUND_OFFSET)
|
||||
) >>> 0
|
||||
),
|
||||
new ViewLineToken(
|
||||
10,
|
||||
(
|
||||
(4 << MetadataConsts.FOREGROUND_OFFSET)
|
||||
) >>> 0
|
||||
),
|
||||
new ViewLineToken(
|
||||
11,
|
||||
(
|
||||
(1 << MetadataConsts.FOREGROUND_OFFSET)
|
||||
) >>> 0
|
||||
),
|
||||
new ViewLineToken(
|
||||
17,
|
||||
(
|
||||
(5 << MetadataConsts.FOREGROUND_OFFSET)
|
||||
| ((FontStyle.Underline) << MetadataConsts.FONT_STYLE_OFFSET)
|
||||
) >>> 0
|
||||
)
|
||||
];
|
||||
const colorMap = [null, '#000000', '#ffffff', '#ff0000', '#00ff00', '#0000ff'];
|
||||
|
||||
assert.equal(
|
||||
tokenizeLineToHTML(text, lineTokens, colorMap, 0, 17, 4),
|
||||
[
|
||||
'<div>',
|
||||
'<span style="color: #ff0000;font-style: italic;font-weight: bold;">Ciao</span>',
|
||||
'<span style="color: #000000;"> </span>',
|
||||
'<span style="color: #00ff00;">hello</span>',
|
||||
'<span style="color: #000000;"> </span>',
|
||||
'<span style="color: #0000ff;text-decoration: underline;">world!</span>',
|
||||
'</div>'
|
||||
].join('')
|
||||
);
|
||||
|
||||
assert.equal(
|
||||
tokenizeLineToHTML(text, lineTokens, colorMap, 0, 12, 4),
|
||||
[
|
||||
'<div>',
|
||||
'<span style="color: #ff0000;font-style: italic;font-weight: bold;">Ciao</span>',
|
||||
'<span style="color: #000000;"> </span>',
|
||||
'<span style="color: #00ff00;">hello</span>',
|
||||
'<span style="color: #000000;"> </span>',
|
||||
'<span style="color: #0000ff;text-decoration: underline;">w</span>',
|
||||
'</div>'
|
||||
].join('')
|
||||
);
|
||||
|
||||
assert.equal(
|
||||
tokenizeLineToHTML(text, lineTokens, colorMap, 0, 11, 4),
|
||||
[
|
||||
'<div>',
|
||||
'<span style="color: #ff0000;font-style: italic;font-weight: bold;">Ciao</span>',
|
||||
'<span style="color: #000000;"> </span>',
|
||||
'<span style="color: #00ff00;">hello</span>',
|
||||
'<span style="color: #000000;"> </span>',
|
||||
'</div>'
|
||||
].join('')
|
||||
);
|
||||
|
||||
assert.equal(
|
||||
tokenizeLineToHTML(text, lineTokens, colorMap, 1, 11, 4),
|
||||
[
|
||||
'<div>',
|
||||
'<span style="color: #ff0000;font-style: italic;font-weight: bold;">iao</span>',
|
||||
'<span style="color: #000000;"> </span>',
|
||||
'<span style="color: #00ff00;">hello</span>',
|
||||
'<span style="color: #000000;"> </span>',
|
||||
'</div>'
|
||||
].join('')
|
||||
);
|
||||
|
||||
assert.equal(
|
||||
tokenizeLineToHTML(text, lineTokens, colorMap, 4, 11, 4),
|
||||
[
|
||||
'<div>',
|
||||
'<span style="color: #000000;"> </span>',
|
||||
'<span style="color: #00ff00;">hello</span>',
|
||||
'<span style="color: #000000;"> </span>',
|
||||
'</div>'
|
||||
].join('')
|
||||
);
|
||||
|
||||
assert.equal(
|
||||
tokenizeLineToHTML(text, lineTokens, colorMap, 5, 11, 4),
|
||||
[
|
||||
'<div>',
|
||||
'<span style="color: #00ff00;">hello</span>',
|
||||
'<span style="color: #000000;"> </span>',
|
||||
'</div>'
|
||||
].join('')
|
||||
);
|
||||
|
||||
assert.equal(
|
||||
tokenizeLineToHTML(text, lineTokens, colorMap, 5, 10, 4),
|
||||
[
|
||||
'<div>',
|
||||
'<span style="color: #00ff00;">hello</span>',
|
||||
'</div>'
|
||||
].join('')
|
||||
);
|
||||
|
||||
assert.equal(
|
||||
tokenizeLineToHTML(text, lineTokens, colorMap, 6, 9, 4),
|
||||
[
|
||||
'<div>',
|
||||
'<span style="color: #00ff00;">ell</span>',
|
||||
'</div>'
|
||||
].join('')
|
||||
);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
class Mode extends MockMode {
|
||||
|
||||
private static _id = new LanguageIdentifier('textToHtmlTokenizerMode', 3);
|
||||
|
||||
constructor() {
|
||||
super(Mode._id);
|
||||
this._register(TokenizationRegistry.register(this.getId(), {
|
||||
getInitialState: (): IState => null,
|
||||
tokenize: undefined,
|
||||
tokenize2: (line: string, state: IState): TokenizationResult2 => {
|
||||
let tokensArr: number[] = [];
|
||||
let prevColor: ColorId = -1;
|
||||
for (let i = 0; i < line.length; i++) {
|
||||
let colorId = line.charAt(i) === '.' ? 7 : 9;
|
||||
if (prevColor !== colorId) {
|
||||
tokensArr.push(i);
|
||||
tokensArr.push((
|
||||
colorId << MetadataConsts.FOREGROUND_OFFSET
|
||||
) >>> 0);
|
||||
}
|
||||
prevColor = colorId;
|
||||
}
|
||||
|
||||
let tokens = new Uint32Array(tokensArr.length);
|
||||
for (let i = 0; i < tokens.length; i++) {
|
||||
tokens[i] = tokensArr[i];
|
||||
}
|
||||
return new TokenizationResult2(tokens, null);
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
34
src/vs/editor/test/common/modesTestUtils.ts
Normal file
34
src/vs/editor/test/common/modesTestUtils.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { LineTokens } from 'vs/editor/common/core/lineTokens';
|
||||
import { createScopedLineTokens, ScopedLineTokens } from 'vs/editor/common/modes/supports';
|
||||
import { StandardTokenType, MetadataConsts } from 'vs/editor/common/modes';
|
||||
|
||||
export interface TokenText {
|
||||
text: string;
|
||||
type: StandardTokenType;
|
||||
}
|
||||
|
||||
export function createFakeScopedLineTokens(rawTokens: TokenText[]): ScopedLineTokens {
|
||||
let tokens = new Uint32Array(rawTokens.length << 1);
|
||||
let line = '';
|
||||
|
||||
for (let i = 0, len = rawTokens.length; i < len; i++) {
|
||||
let rawToken = rawTokens[i];
|
||||
|
||||
let startOffset = line.length;
|
||||
let metadata = (
|
||||
(rawToken.type << MetadataConsts.TOKEN_TYPE_OFFSET)
|
||||
) >>> 0;
|
||||
|
||||
tokens[(i << 1)] = startOffset;
|
||||
tokens[(i << 1) + 1] = metadata;
|
||||
line += rawToken.text;
|
||||
}
|
||||
|
||||
return createScopedLineTokens(new LineTokens(tokens, line), 0);
|
||||
}
|
||||
171
src/vs/editor/test/common/services/editorSimpleWorker.test.ts
Normal file
171
src/vs/editor/test/common/services/editorSimpleWorker.test.ts
Normal file
@@ -0,0 +1,171 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { EditorSimpleWorkerImpl, ICommonModel } from 'vs/editor/common/services/editorSimpleWorker';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
|
||||
suite('EditorSimpleWorker', () => {
|
||||
|
||||
class WorkerWithModels extends EditorSimpleWorkerImpl {
|
||||
|
||||
getModel(uri: string) {
|
||||
return this._getModel(uri);
|
||||
}
|
||||
|
||||
addModel(lines: string[], eol: string = '\n') {
|
||||
const uri = 'test:file#' + Date.now();
|
||||
this.acceptNewModel({
|
||||
url: uri,
|
||||
versionId: 1,
|
||||
lines: lines,
|
||||
EOL: eol
|
||||
});
|
||||
return this._getModel(uri);
|
||||
}
|
||||
}
|
||||
|
||||
let worker: WorkerWithModels;
|
||||
let model: ICommonModel;
|
||||
|
||||
setup(() => {
|
||||
worker = new WorkerWithModels();
|
||||
model = worker.addModel([
|
||||
'This is line one', //16
|
||||
'and this is line number two', //27
|
||||
'it is followed by #3', //20
|
||||
'and finished with the fourth.', //29
|
||||
]);
|
||||
});
|
||||
|
||||
function assertPositionAt(offset: number, line: number, column: number) {
|
||||
let position = model.positionAt(offset);
|
||||
assert.equal(position.lineNumber, line);
|
||||
assert.equal(position.column, column);
|
||||
}
|
||||
|
||||
function assertOffsetAt(lineNumber: number, column: number, offset: number) {
|
||||
let actual = model.offsetAt({ lineNumber, column });
|
||||
assert.equal(actual, offset);
|
||||
}
|
||||
|
||||
test('ICommonModel#offsetAt', function () {
|
||||
assertOffsetAt(1, 1, 0);
|
||||
assertOffsetAt(1, 2, 1);
|
||||
assertOffsetAt(1, 17, 16);
|
||||
assertOffsetAt(2, 1, 17);
|
||||
assertOffsetAt(2, 4, 20);
|
||||
assertOffsetAt(3, 1, 45);
|
||||
assertOffsetAt(5, 30, 95);
|
||||
assertOffsetAt(5, 31, 95);
|
||||
assertOffsetAt(5, Number.MAX_VALUE, 95);
|
||||
assertOffsetAt(6, 30, 95);
|
||||
assertOffsetAt(Number.MAX_VALUE, 30, 95);
|
||||
assertOffsetAt(Number.MAX_VALUE, Number.MAX_VALUE, 95);
|
||||
});
|
||||
|
||||
test('ICommonModel#positionAt', function () {
|
||||
assertPositionAt(0, 1, 1);
|
||||
assertPositionAt(Number.MIN_VALUE, 1, 1);
|
||||
assertPositionAt(1, 1, 2);
|
||||
assertPositionAt(16, 1, 17);
|
||||
assertPositionAt(17, 2, 1);
|
||||
assertPositionAt(20, 2, 4);
|
||||
assertPositionAt(45, 3, 1);
|
||||
assertPositionAt(95, 4, 30);
|
||||
assertPositionAt(96, 4, 30);
|
||||
assertPositionAt(99, 4, 30);
|
||||
assertPositionAt(Number.MAX_VALUE, 4, 30);
|
||||
});
|
||||
|
||||
test('ICommonModel#validatePosition, issue #15882', function () {
|
||||
let model = worker.addModel(['{"id": "0001","type": "donut","name": "Cake","image":{"url": "images/0001.jpg","width": 200,"height": 200},"thumbnail":{"url": "images/thumbnails/0001.jpg","width": 32,"height": 32}}']);
|
||||
assert.equal(model.offsetAt({ lineNumber: 1, column: 2 }), 1);
|
||||
});
|
||||
|
||||
test('MoreMinimal', function () {
|
||||
|
||||
return worker.computeMoreMinimalEdits(model.uri.toString(), [{ text: 'This is line One', range: new Range(1, 1, 1, 17) }], []).then(edits => {
|
||||
assert.equal(edits.length, 1);
|
||||
const [first] = edits;
|
||||
assert.equal(first.text, 'O');
|
||||
assert.deepEqual(first.range, { startLineNumber: 1, startColumn: 14, endLineNumber: 1, endColumn: 15 });
|
||||
});
|
||||
});
|
||||
|
||||
test('MoreMinimal, issue #15385 newline changes only', function () {
|
||||
|
||||
let model = worker.addModel([
|
||||
'{',
|
||||
'\t"a":1',
|
||||
'}'
|
||||
], '\n');
|
||||
|
||||
return worker.computeMoreMinimalEdits(model.uri.toString(), [{ text: '{\r\n\t"a":1\r\n}', range: new Range(1, 1, 3, 2) }], []).then(edits => {
|
||||
assert.equal(edits.length, 0);
|
||||
});
|
||||
});
|
||||
|
||||
test('MoreMinimal, issue #15385 newline changes and other', function () {
|
||||
|
||||
let model = worker.addModel([
|
||||
'{',
|
||||
'\t"a":1',
|
||||
'}'
|
||||
], '\n');
|
||||
|
||||
return worker.computeMoreMinimalEdits(model.uri.toString(), [{ text: '{\r\n\t"b":1\r\n}', range: new Range(1, 1, 3, 2) }], []).then(edits => {
|
||||
assert.equal(edits.length, 1);
|
||||
const [first] = edits;
|
||||
assert.equal(first.text, 'b');
|
||||
assert.deepEqual(first.range, { startLineNumber: 2, startColumn: 3, endLineNumber: 2, endColumn: 4 });
|
||||
});
|
||||
});
|
||||
|
||||
test('MoreMinimal, issue #15385 newline changes and other', function () {
|
||||
|
||||
let model = worker.addModel([
|
||||
'package main', // 1
|
||||
'func foo() {', // 2
|
||||
'}' // 3
|
||||
]);
|
||||
|
||||
return worker.computeMoreMinimalEdits(model.uri.toString(), [{ text: '\n', range: new Range(3, 2, 4, 1000) }], []).then(edits => {
|
||||
assert.equal(edits.length, 1);
|
||||
const [first] = edits;
|
||||
assert.equal(first.text, '\n');
|
||||
assert.deepEqual(first.range, { startLineNumber: 3, startColumn: 2, endLineNumber: 3, endColumn: 2 });
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
test('ICommonModel#getValueInRange, issue #17424', function () {
|
||||
|
||||
let model = worker.addModel([
|
||||
'package main', // 1
|
||||
'func foo() {', // 2
|
||||
'}' // 3
|
||||
]);
|
||||
|
||||
const value = model.getValueInRange({ startLineNumber: 3, startColumn: 1, endLineNumber: 4, endColumn: 1 });
|
||||
assert.equal(value, '}');
|
||||
});
|
||||
|
||||
|
||||
test('textualSuggest, issue #17785', function () {
|
||||
|
||||
let model = worker.addModel([
|
||||
'foobar', // 1
|
||||
'f f' // 2
|
||||
]);
|
||||
|
||||
return worker.textualSuggest(model.uri.toString(), { lineNumber: 2, column: 2 }, '[a-z]+', 'img').then((result) => {
|
||||
const { suggestions } = result;
|
||||
assert.equal(suggestions.length, 1);
|
||||
assert.equal(suggestions[0].label, 'foobar');
|
||||
});
|
||||
});
|
||||
});
|
||||
269
src/vs/editor/test/common/services/languagesRegistry.test.ts
Normal file
269
src/vs/editor/test/common/services/languagesRegistry.test.ts
Normal file
@@ -0,0 +1,269 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { LanguagesRegistry } from 'vs/editor/common/services/languagesRegistry';
|
||||
|
||||
suite('LanguagesRegistry', () => {
|
||||
|
||||
test('output mode does not have a name', () => {
|
||||
let registry = new LanguagesRegistry(false);
|
||||
|
||||
registry._registerLanguages([{
|
||||
id: 'outputModeId',
|
||||
extensions: [],
|
||||
aliases: [null],
|
||||
mimetypes: ['outputModeMimeType'],
|
||||
}]);
|
||||
|
||||
assert.deepEqual(registry.getRegisteredLanguageNames(), []);
|
||||
});
|
||||
|
||||
test('mode with alias does have a name', () => {
|
||||
let registry = new LanguagesRegistry(false);
|
||||
|
||||
registry._registerLanguages([{
|
||||
id: 'modeId',
|
||||
extensions: [],
|
||||
aliases: ['ModeName'],
|
||||
mimetypes: ['bla'],
|
||||
}]);
|
||||
|
||||
assert.deepEqual(registry.getRegisteredLanguageNames(), ['ModeName']);
|
||||
assert.deepEqual(registry.getLanguageName('modeId'), 'ModeName');
|
||||
});
|
||||
|
||||
test('mode without alias gets a name', () => {
|
||||
let registry = new LanguagesRegistry(false);
|
||||
|
||||
registry._registerLanguages([{
|
||||
id: 'modeId',
|
||||
extensions: [],
|
||||
mimetypes: ['bla'],
|
||||
}]);
|
||||
|
||||
assert.deepEqual(registry.getRegisteredLanguageNames(), ['modeId']);
|
||||
assert.deepEqual(registry.getLanguageName('modeId'), 'modeId');
|
||||
});
|
||||
|
||||
test('bug #4360: f# not shown in status bar', () => {
|
||||
let registry = new LanguagesRegistry(false);
|
||||
|
||||
registry._registerLanguages([{
|
||||
id: 'modeId',
|
||||
extensions: ['.ext1'],
|
||||
aliases: ['ModeName'],
|
||||
mimetypes: ['bla'],
|
||||
}]);
|
||||
|
||||
registry._registerLanguages([{
|
||||
id: 'modeId',
|
||||
extensions: ['.ext2'],
|
||||
aliases: [],
|
||||
mimetypes: ['bla'],
|
||||
}]);
|
||||
|
||||
assert.deepEqual(registry.getRegisteredLanguageNames(), ['ModeName']);
|
||||
assert.deepEqual(registry.getLanguageName('modeId'), 'ModeName');
|
||||
});
|
||||
|
||||
test('issue #5278: Extension cannot override language name anymore', () => {
|
||||
let registry = new LanguagesRegistry(false);
|
||||
|
||||
registry._registerLanguages([{
|
||||
id: 'modeId',
|
||||
extensions: ['.ext1'],
|
||||
aliases: ['ModeName'],
|
||||
mimetypes: ['bla'],
|
||||
}]);
|
||||
|
||||
registry._registerLanguages([{
|
||||
id: 'modeId',
|
||||
extensions: ['.ext2'],
|
||||
aliases: ['BetterModeName'],
|
||||
mimetypes: ['bla'],
|
||||
}]);
|
||||
|
||||
assert.deepEqual(registry.getRegisteredLanguageNames(), ['BetterModeName']);
|
||||
assert.deepEqual(registry.getLanguageName('modeId'), 'BetterModeName');
|
||||
});
|
||||
|
||||
test('mimetypes are generated if necessary', () => {
|
||||
let registry = new LanguagesRegistry(false);
|
||||
|
||||
registry._registerLanguages([{
|
||||
id: 'modeId'
|
||||
}]);
|
||||
|
||||
assert.deepEqual(registry.getMimeForMode('modeId'), 'text/x-modeId');
|
||||
});
|
||||
|
||||
test('first mimetype wins', () => {
|
||||
let registry = new LanguagesRegistry(false);
|
||||
|
||||
registry._registerLanguages([{
|
||||
id: 'modeId',
|
||||
mimetypes: ['text/modeId', 'text/modeId2']
|
||||
}]);
|
||||
|
||||
assert.deepEqual(registry.getMimeForMode('modeId'), 'text/modeId');
|
||||
});
|
||||
|
||||
test('first mimetype wins 2', () => {
|
||||
let registry = new LanguagesRegistry(false);
|
||||
|
||||
registry._registerLanguages([{
|
||||
id: 'modeId'
|
||||
}]);
|
||||
|
||||
registry._registerLanguages([{
|
||||
id: 'modeId',
|
||||
mimetypes: ['text/modeId']
|
||||
}]);
|
||||
|
||||
assert.deepEqual(registry.getMimeForMode('modeId'), 'text/x-modeId');
|
||||
});
|
||||
|
||||
test('aliases', () => {
|
||||
let registry = new LanguagesRegistry(false);
|
||||
|
||||
registry._registerLanguages([{
|
||||
id: 'a'
|
||||
}]);
|
||||
|
||||
assert.deepEqual(registry.getRegisteredLanguageNames(), ['a']);
|
||||
assert.deepEqual(registry.getModeIdsFromLanguageName('a'), ['a']);
|
||||
assert.deepEqual(registry.getModeIdForLanguageNameLowercase('a'), 'a');
|
||||
assert.deepEqual(registry.getLanguageName('a'), 'a');
|
||||
|
||||
registry._registerLanguages([{
|
||||
id: 'a',
|
||||
aliases: ['A1', 'A2']
|
||||
}]);
|
||||
|
||||
assert.deepEqual(registry.getRegisteredLanguageNames(), ['A1']);
|
||||
assert.deepEqual(registry.getModeIdsFromLanguageName('a'), []);
|
||||
assert.deepEqual(registry.getModeIdsFromLanguageName('A1'), ['a']);
|
||||
assert.deepEqual(registry.getModeIdsFromLanguageName('A2'), []);
|
||||
assert.deepEqual(registry.getModeIdForLanguageNameLowercase('a'), 'a');
|
||||
assert.deepEqual(registry.getModeIdForLanguageNameLowercase('a1'), 'a');
|
||||
assert.deepEqual(registry.getModeIdForLanguageNameLowercase('a2'), 'a');
|
||||
assert.deepEqual(registry.getLanguageName('a'), 'A1');
|
||||
|
||||
registry._registerLanguages([{
|
||||
id: 'a',
|
||||
aliases: ['A3', 'A4']
|
||||
}]);
|
||||
|
||||
assert.deepEqual(registry.getRegisteredLanguageNames(), ['A3']);
|
||||
assert.deepEqual(registry.getModeIdsFromLanguageName('a'), []);
|
||||
assert.deepEqual(registry.getModeIdsFromLanguageName('A1'), []);
|
||||
assert.deepEqual(registry.getModeIdsFromLanguageName('A2'), []);
|
||||
assert.deepEqual(registry.getModeIdsFromLanguageName('A3'), ['a']);
|
||||
assert.deepEqual(registry.getModeIdsFromLanguageName('A4'), []);
|
||||
assert.deepEqual(registry.getModeIdForLanguageNameLowercase('a'), 'a');
|
||||
assert.deepEqual(registry.getModeIdForLanguageNameLowercase('a1'), 'a');
|
||||
assert.deepEqual(registry.getModeIdForLanguageNameLowercase('a2'), 'a');
|
||||
assert.deepEqual(registry.getModeIdForLanguageNameLowercase('a3'), 'a');
|
||||
assert.deepEqual(registry.getModeIdForLanguageNameLowercase('a4'), 'a');
|
||||
assert.deepEqual(registry.getLanguageName('a'), 'A3');
|
||||
});
|
||||
|
||||
test('empty aliases array means no alias', () => {
|
||||
let registry = new LanguagesRegistry(false);
|
||||
|
||||
registry._registerLanguages([{
|
||||
id: 'a'
|
||||
}]);
|
||||
|
||||
assert.deepEqual(registry.getRegisteredLanguageNames(), ['a']);
|
||||
assert.deepEqual(registry.getModeIdsFromLanguageName('a'), ['a']);
|
||||
assert.deepEqual(registry.getModeIdForLanguageNameLowercase('a'), 'a');
|
||||
assert.deepEqual(registry.getLanguageName('a'), 'a');
|
||||
|
||||
registry._registerLanguages([{
|
||||
id: 'b',
|
||||
aliases: []
|
||||
}]);
|
||||
|
||||
assert.deepEqual(registry.getRegisteredLanguageNames(), ['a']);
|
||||
assert.deepEqual(registry.getModeIdsFromLanguageName('a'), ['a']);
|
||||
assert.deepEqual(registry.getModeIdsFromLanguageName('b'), []);
|
||||
assert.deepEqual(registry.getModeIdForLanguageNameLowercase('a'), 'a');
|
||||
assert.deepEqual(registry.getModeIdForLanguageNameLowercase('b'), 'b');
|
||||
assert.deepEqual(registry.getLanguageName('a'), 'a');
|
||||
assert.deepEqual(registry.getLanguageName('b'), null);
|
||||
});
|
||||
|
||||
test('extensions', () => {
|
||||
let registry = new LanguagesRegistry(false);
|
||||
|
||||
registry._registerLanguages([{
|
||||
id: 'a',
|
||||
aliases: ['aName'],
|
||||
extensions: ['aExt']
|
||||
}]);
|
||||
|
||||
assert.deepEqual(registry.getExtensions('a'), []);
|
||||
assert.deepEqual(registry.getExtensions('aname'), []);
|
||||
assert.deepEqual(registry.getExtensions('aName'), ['aExt']);
|
||||
|
||||
registry._registerLanguages([{
|
||||
id: 'a',
|
||||
extensions: ['aExt2']
|
||||
}]);
|
||||
|
||||
assert.deepEqual(registry.getExtensions('a'), []);
|
||||
assert.deepEqual(registry.getExtensions('aname'), []);
|
||||
assert.deepEqual(registry.getExtensions('aName'), ['aExt', 'aExt2']);
|
||||
});
|
||||
|
||||
test('filenames', () => {
|
||||
let registry = new LanguagesRegistry(false);
|
||||
|
||||
registry._registerLanguages([{
|
||||
id: 'a',
|
||||
aliases: ['aName'],
|
||||
filenames: ['aFilename']
|
||||
}]);
|
||||
|
||||
assert.deepEqual(registry.getFilenames('a'), []);
|
||||
assert.deepEqual(registry.getFilenames('aname'), []);
|
||||
assert.deepEqual(registry.getFilenames('aName'), ['aFilename']);
|
||||
|
||||
registry._registerLanguages([{
|
||||
id: 'a',
|
||||
filenames: ['aFilename2']
|
||||
}]);
|
||||
|
||||
assert.deepEqual(registry.getFilenames('a'), []);
|
||||
assert.deepEqual(registry.getFilenames('aname'), []);
|
||||
assert.deepEqual(registry.getFilenames('aName'), ['aFilename', 'aFilename2']);
|
||||
});
|
||||
|
||||
test('configuration', () => {
|
||||
let registry = new LanguagesRegistry(false);
|
||||
|
||||
registry._registerLanguages([{
|
||||
id: 'a',
|
||||
aliases: ['aName'],
|
||||
configuration: 'aFilename'
|
||||
}]);
|
||||
|
||||
assert.deepEqual(registry.getConfigurationFiles('a'), ['aFilename']);
|
||||
assert.deepEqual(registry.getConfigurationFiles('aname'), []);
|
||||
assert.deepEqual(registry.getConfigurationFiles('aName'), []);
|
||||
|
||||
registry._registerLanguages([{
|
||||
id: 'a',
|
||||
configuration: 'aFilename2'
|
||||
}]);
|
||||
|
||||
assert.deepEqual(registry.getConfigurationFiles('a'), ['aFilename', 'aFilename2']);
|
||||
assert.deepEqual(registry.getConfigurationFiles('aname'), []);
|
||||
assert.deepEqual(registry.getConfigurationFiles('aName'), []);
|
||||
});
|
||||
});
|
||||
333
src/vs/editor/test/common/services/modelService.test.ts
Normal file
333
src/vs/editor/test/common/services/modelService.test.ts
Normal file
@@ -0,0 +1,333 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
|
||||
import { ModelServiceImpl } from 'vs/editor/common/services/modelServiceImpl';
|
||||
import URI from 'vs/base/common/uri';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import { DefaultEndOfLine } from 'vs/editor/common/editorCommon';
|
||||
import { Model } from 'vs/editor/common/model/model';
|
||||
import { TextSource } from 'vs/editor/common/model/textSource';
|
||||
import { EditOperation } from 'vs/editor/common/core/editOperation';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { CharCode } from 'vs/base/common/charCode';
|
||||
import { createStringBuilder } from 'vs/editor/common/core/stringBuilder';
|
||||
|
||||
const GENERATE_TESTS = false;
|
||||
|
||||
suite('ModelService', () => {
|
||||
let modelService: ModelServiceImpl;
|
||||
|
||||
setup(() => {
|
||||
const configService = new TestConfigurationService();
|
||||
configService.setUserConfiguration('files', { 'eol': '\n' });
|
||||
configService.setUserConfiguration('files', { 'eol': '\r\n' }, URI.file(platform.isWindows ? 'c:\\myroot' : '/myroot'));
|
||||
|
||||
modelService = new ModelServiceImpl(null, configService);
|
||||
});
|
||||
|
||||
teardown(() => {
|
||||
modelService.dispose();
|
||||
});
|
||||
|
||||
test('EOL setting respected depending on root', () => {
|
||||
const model1 = modelService.createModel('farboo', null, null);
|
||||
const model2 = modelService.createModel('farboo', null, URI.file(platform.isWindows ? 'c:\\myroot\\myfile.txt' : '/myroot/myfile.txt'));
|
||||
const model3 = modelService.createModel('farboo', null, URI.file(platform.isWindows ? 'c:\\other\\myfile.txt' : '/other/myfile.txt'));
|
||||
|
||||
assert.equal(model1.getOptions().defaultEOL, DefaultEndOfLine.LF);
|
||||
assert.equal(model2.getOptions().defaultEOL, DefaultEndOfLine.CRLF);
|
||||
assert.equal(model3.getOptions().defaultEOL, DefaultEndOfLine.LF);
|
||||
});
|
||||
|
||||
test('_computeEdits first line changed', function () {
|
||||
|
||||
const model = Model.createFromString(
|
||||
[
|
||||
'This is line one', //16
|
||||
'and this is line number two', //27
|
||||
'it is followed by #3', //20
|
||||
'and finished with the fourth.', //29
|
||||
].join('\n')
|
||||
);
|
||||
|
||||
const textSource = TextSource.fromString(
|
||||
[
|
||||
'This is line One', //16
|
||||
'and this is line number two', //27
|
||||
'it is followed by #3', //20
|
||||
'and finished with the fourth.', //29
|
||||
].join('\n'),
|
||||
DefaultEndOfLine.LF
|
||||
);
|
||||
|
||||
const actual = ModelServiceImpl._computeEdits(model, textSource);
|
||||
|
||||
assert.deepEqual(actual, [
|
||||
EditOperation.replace(new Range(1, 1, 1, 17), 'This is line One')
|
||||
]);
|
||||
});
|
||||
|
||||
test('_computeEdits EOL changed', function () {
|
||||
|
||||
const model = Model.createFromString(
|
||||
[
|
||||
'This is line one', //16
|
||||
'and this is line number two', //27
|
||||
'it is followed by #3', //20
|
||||
'and finished with the fourth.', //29
|
||||
].join('\n')
|
||||
);
|
||||
|
||||
const textSource = TextSource.fromString(
|
||||
[
|
||||
'This is line one', //16
|
||||
'and this is line number two', //27
|
||||
'it is followed by #3', //20
|
||||
'and finished with the fourth.', //29
|
||||
].join('\r\n'),
|
||||
DefaultEndOfLine.LF
|
||||
);
|
||||
|
||||
const actual = ModelServiceImpl._computeEdits(model, textSource);
|
||||
|
||||
assert.deepEqual(actual, []);
|
||||
});
|
||||
|
||||
test('_computeEdits EOL and other change 1', function () {
|
||||
|
||||
const model = Model.createFromString(
|
||||
[
|
||||
'This is line one', //16
|
||||
'and this is line number two', //27
|
||||
'it is followed by #3', //20
|
||||
'and finished with the fourth.', //29
|
||||
].join('\n')
|
||||
);
|
||||
|
||||
const textSource = TextSource.fromString(
|
||||
[
|
||||
'This is line One', //16
|
||||
'and this is line number two', //27
|
||||
'It is followed by #3', //20
|
||||
'and finished with the fourth.', //29
|
||||
].join('\r\n'),
|
||||
DefaultEndOfLine.LF
|
||||
);
|
||||
|
||||
const actual = ModelServiceImpl._computeEdits(model, textSource);
|
||||
|
||||
assert.deepEqual(actual, [
|
||||
EditOperation.replace(new Range(1, 1, 1, 17), 'This is line One'),
|
||||
EditOperation.replace(new Range(3, 1, 3, 21), 'It is followed by #3')
|
||||
]);
|
||||
});
|
||||
|
||||
test('_computeEdits EOL and other change 2', function () {
|
||||
|
||||
const model = Model.createFromString(
|
||||
[
|
||||
'package main', // 1
|
||||
'func foo() {', // 2
|
||||
'}' // 3
|
||||
].join('\n')
|
||||
);
|
||||
|
||||
const textSource = TextSource.fromString(
|
||||
[
|
||||
'package main', // 1
|
||||
'func foo() {', // 2
|
||||
'}', // 3
|
||||
''
|
||||
].join('\r\n'),
|
||||
DefaultEndOfLine.LF
|
||||
);
|
||||
|
||||
const actual = ModelServiceImpl._computeEdits(model, textSource);
|
||||
|
||||
assert.deepEqual(actual, [
|
||||
EditOperation.replace(new Range(3, 2, 3, 2), '\n')
|
||||
]);
|
||||
});
|
||||
|
||||
test('generated1', () => {
|
||||
const file1 = ['pram', 'okctibad', 'pjuwtemued', 'knnnm', 'u', ''];
|
||||
const file2 = ['tcnr', 'rxwlicro', 'vnzy', '', '', 'pjzcogzur', 'ptmxyp', 'dfyshia', 'pee', 'ygg'];
|
||||
assertComputeEdits(file1, file2);
|
||||
});
|
||||
|
||||
test('generated2', () => {
|
||||
const file1 = ['', 'itls', 'hrilyhesv', ''];
|
||||
const file2 = ['vdl', '', 'tchgz', 'bhx', 'nyl'];
|
||||
assertComputeEdits(file1, file2);
|
||||
});
|
||||
|
||||
test('generated3', () => {
|
||||
const file1 = ['ubrbrcv', 'wv', 'xodspybszt', 's', 'wednjxm', 'fklajt', 'fyfc', 'lvejgge', 'rtpjlodmmk', 'arivtgmjdm'];
|
||||
const file2 = ['s', 'qj', 'tu', 'ur', 'qerhjjhyvx', 't'];
|
||||
assertComputeEdits(file1, file2);
|
||||
});
|
||||
|
||||
test('generated4', () => {
|
||||
const file1 = ['ig', 'kh', 'hxegci', 'smvker', 'pkdmjjdqnv', 'vgkkqqx', '', 'jrzeb'];
|
||||
const file2 = ['yk', ''];
|
||||
assertComputeEdits(file1, file2);
|
||||
});
|
||||
|
||||
test('does insertions in the middle of the document', () => {
|
||||
const file1 = [
|
||||
'line 1',
|
||||
'line 2',
|
||||
'line 3'
|
||||
];
|
||||
const file2 = [
|
||||
'line 1',
|
||||
'line 2',
|
||||
'line 5',
|
||||
'line 3'
|
||||
];
|
||||
assertComputeEdits(file1, file2);
|
||||
});
|
||||
|
||||
test('does insertions at the end of the document', () => {
|
||||
const file1 = [
|
||||
'line 1',
|
||||
'line 2',
|
||||
'line 3'
|
||||
];
|
||||
const file2 = [
|
||||
'line 1',
|
||||
'line 2',
|
||||
'line 3',
|
||||
'line 4'
|
||||
];
|
||||
assertComputeEdits(file1, file2);
|
||||
});
|
||||
|
||||
test('does insertions at the beginning of the document', () => {
|
||||
const file1 = [
|
||||
'line 1',
|
||||
'line 2',
|
||||
'line 3'
|
||||
];
|
||||
const file2 = [
|
||||
'line 0',
|
||||
'line 1',
|
||||
'line 2',
|
||||
'line 3'
|
||||
];
|
||||
assertComputeEdits(file1, file2);
|
||||
});
|
||||
|
||||
test('does replacements', () => {
|
||||
const file1 = [
|
||||
'line 1',
|
||||
'line 2',
|
||||
'line 3'
|
||||
];
|
||||
const file2 = [
|
||||
'line 1',
|
||||
'line 7',
|
||||
'line 3'
|
||||
];
|
||||
assertComputeEdits(file1, file2);
|
||||
});
|
||||
|
||||
test('does deletions', () => {
|
||||
const file1 = [
|
||||
'line 1',
|
||||
'line 2',
|
||||
'line 3'
|
||||
];
|
||||
const file2 = [
|
||||
'line 1',
|
||||
'line 3'
|
||||
];
|
||||
assertComputeEdits(file1, file2);
|
||||
});
|
||||
|
||||
test('does insert, replace, and delete', () => {
|
||||
const file1 = [
|
||||
'line 1',
|
||||
'line 2',
|
||||
'line 3',
|
||||
'line 4',
|
||||
'line 5',
|
||||
];
|
||||
const file2 = [
|
||||
'line 0', // insert line 0
|
||||
'line 1',
|
||||
'replace line 2', // replace line 2
|
||||
'line 3',
|
||||
// delete line 4
|
||||
'line 5',
|
||||
];
|
||||
assertComputeEdits(file1, file2);
|
||||
});
|
||||
});
|
||||
|
||||
function assertComputeEdits(lines1: string[], lines2: string[]): void {
|
||||
const model = Model.createFromString(lines1.join('\n'));
|
||||
const textSource = TextSource.fromString(lines2.join('\n'), DefaultEndOfLine.LF);
|
||||
|
||||
// compute required edits
|
||||
// let start = Date.now();
|
||||
const edits = ModelServiceImpl._computeEdits(model, textSource);
|
||||
// console.log(`took ${Date.now() - start} ms.`);
|
||||
|
||||
// apply edits
|
||||
model.pushEditOperations(null, edits, null);
|
||||
|
||||
assert.equal(model.getValue(), lines2.join('\n'));
|
||||
}
|
||||
|
||||
function getRandomInt(min: number, max: number): number {
|
||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||
}
|
||||
|
||||
function getRandomString(minLength: number, maxLength: number): string {
|
||||
let length = getRandomInt(minLength, maxLength);
|
||||
let t = createStringBuilder(length);
|
||||
for (let i = 0; i < length; i++) {
|
||||
t.appendASCII(getRandomInt(CharCode.a, CharCode.z));
|
||||
}
|
||||
return t.build();
|
||||
}
|
||||
|
||||
function generateFile(small: boolean): string[] {
|
||||
let lineCount = getRandomInt(1, small ? 3 : 10000);
|
||||
let lines: string[] = [];
|
||||
for (let i = 0; i < lineCount; i++) {
|
||||
lines.push(getRandomString(0, small ? 3 : 10000));
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
|
||||
if (GENERATE_TESTS) {
|
||||
let number = 1;
|
||||
while (true) {
|
||||
|
||||
console.log('------TEST: ' + number++);
|
||||
|
||||
const file1 = generateFile(true);
|
||||
const file2 = generateFile(true);
|
||||
|
||||
console.log('------TEST GENERATED');
|
||||
|
||||
try {
|
||||
assertComputeEdits(file1, file2);
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
console.log(`
|
||||
const file1 = ${JSON.stringify(file1).replace(/"/g, '\'')};
|
||||
const file2 = ${JSON.stringify(file2).replace(/"/g, '\'')};
|
||||
assertComputeEdits(file1, file2);
|
||||
`);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
142
src/vs/editor/test/common/standalone/standaloneBase.test.ts
Normal file
142
src/vs/editor/test/common/standalone/standaloneBase.test.ts
Normal file
@@ -0,0 +1,142 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { KeyCode as StandaloneKeyCode, Severity as StandaloneSeverity } from 'vs/editor/common/standalone/standaloneBase';
|
||||
import { KeyCode as RuntimeKeyCode } from 'vs/base/common/keyCodes';
|
||||
import RuntimeSeverity from 'vs/base/common/severity';
|
||||
|
||||
suite('StandaloneBase', () => {
|
||||
test('exports enums correctly', () => {
|
||||
assert.equal(StandaloneSeverity.Ignore, RuntimeSeverity.Ignore);
|
||||
assert.equal(StandaloneSeverity.Info, RuntimeSeverity.Info);
|
||||
assert.equal(StandaloneSeverity.Warning, RuntimeSeverity.Warning);
|
||||
assert.equal(StandaloneSeverity.Error, RuntimeSeverity.Error);
|
||||
});
|
||||
});
|
||||
|
||||
suite('KeyCode', () => {
|
||||
test('is exported correctly in standalone editor', () => {
|
||||
|
||||
function assertKeyCode(standalone: StandaloneKeyCode, runtime: RuntimeKeyCode): void {
|
||||
assert.equal(standalone, runtime);
|
||||
}
|
||||
|
||||
assertKeyCode(StandaloneKeyCode.Unknown, RuntimeKeyCode.Unknown);
|
||||
assertKeyCode(StandaloneKeyCode.Backspace, RuntimeKeyCode.Backspace);
|
||||
assertKeyCode(StandaloneKeyCode.Tab, RuntimeKeyCode.Tab);
|
||||
assertKeyCode(StandaloneKeyCode.Enter, RuntimeKeyCode.Enter);
|
||||
assertKeyCode(StandaloneKeyCode.Shift, RuntimeKeyCode.Shift);
|
||||
assertKeyCode(StandaloneKeyCode.Ctrl, RuntimeKeyCode.Ctrl);
|
||||
assertKeyCode(StandaloneKeyCode.Alt, RuntimeKeyCode.Alt);
|
||||
assertKeyCode(StandaloneKeyCode.PauseBreak, RuntimeKeyCode.PauseBreak);
|
||||
assertKeyCode(StandaloneKeyCode.CapsLock, RuntimeKeyCode.CapsLock);
|
||||
assertKeyCode(StandaloneKeyCode.Escape, RuntimeKeyCode.Escape);
|
||||
assertKeyCode(StandaloneKeyCode.Space, RuntimeKeyCode.Space);
|
||||
assertKeyCode(StandaloneKeyCode.PageUp, RuntimeKeyCode.PageUp);
|
||||
assertKeyCode(StandaloneKeyCode.PageDown, RuntimeKeyCode.PageDown);
|
||||
assertKeyCode(StandaloneKeyCode.End, RuntimeKeyCode.End);
|
||||
assertKeyCode(StandaloneKeyCode.Home, RuntimeKeyCode.Home);
|
||||
assertKeyCode(StandaloneKeyCode.LeftArrow, RuntimeKeyCode.LeftArrow);
|
||||
assertKeyCode(StandaloneKeyCode.UpArrow, RuntimeKeyCode.UpArrow);
|
||||
assertKeyCode(StandaloneKeyCode.RightArrow, RuntimeKeyCode.RightArrow);
|
||||
assertKeyCode(StandaloneKeyCode.DownArrow, RuntimeKeyCode.DownArrow);
|
||||
assertKeyCode(StandaloneKeyCode.Insert, RuntimeKeyCode.Insert);
|
||||
assertKeyCode(StandaloneKeyCode.Delete, RuntimeKeyCode.Delete);
|
||||
assertKeyCode(StandaloneKeyCode.KEY_0, RuntimeKeyCode.KEY_0);
|
||||
assertKeyCode(StandaloneKeyCode.KEY_1, RuntimeKeyCode.KEY_1);
|
||||
assertKeyCode(StandaloneKeyCode.KEY_2, RuntimeKeyCode.KEY_2);
|
||||
assertKeyCode(StandaloneKeyCode.KEY_3, RuntimeKeyCode.KEY_3);
|
||||
assertKeyCode(StandaloneKeyCode.KEY_4, RuntimeKeyCode.KEY_4);
|
||||
assertKeyCode(StandaloneKeyCode.KEY_5, RuntimeKeyCode.KEY_5);
|
||||
assertKeyCode(StandaloneKeyCode.KEY_6, RuntimeKeyCode.KEY_6);
|
||||
assertKeyCode(StandaloneKeyCode.KEY_7, RuntimeKeyCode.KEY_7);
|
||||
assertKeyCode(StandaloneKeyCode.KEY_8, RuntimeKeyCode.KEY_8);
|
||||
assertKeyCode(StandaloneKeyCode.KEY_9, RuntimeKeyCode.KEY_9);
|
||||
assertKeyCode(StandaloneKeyCode.KEY_A, RuntimeKeyCode.KEY_A);
|
||||
assertKeyCode(StandaloneKeyCode.KEY_B, RuntimeKeyCode.KEY_B);
|
||||
assertKeyCode(StandaloneKeyCode.KEY_C, RuntimeKeyCode.KEY_C);
|
||||
assertKeyCode(StandaloneKeyCode.KEY_D, RuntimeKeyCode.KEY_D);
|
||||
assertKeyCode(StandaloneKeyCode.KEY_E, RuntimeKeyCode.KEY_E);
|
||||
assertKeyCode(StandaloneKeyCode.KEY_F, RuntimeKeyCode.KEY_F);
|
||||
assertKeyCode(StandaloneKeyCode.KEY_G, RuntimeKeyCode.KEY_G);
|
||||
assertKeyCode(StandaloneKeyCode.KEY_H, RuntimeKeyCode.KEY_H);
|
||||
assertKeyCode(StandaloneKeyCode.KEY_I, RuntimeKeyCode.KEY_I);
|
||||
assertKeyCode(StandaloneKeyCode.KEY_J, RuntimeKeyCode.KEY_J);
|
||||
assertKeyCode(StandaloneKeyCode.KEY_K, RuntimeKeyCode.KEY_K);
|
||||
assertKeyCode(StandaloneKeyCode.KEY_L, RuntimeKeyCode.KEY_L);
|
||||
assertKeyCode(StandaloneKeyCode.KEY_M, RuntimeKeyCode.KEY_M);
|
||||
assertKeyCode(StandaloneKeyCode.KEY_N, RuntimeKeyCode.KEY_N);
|
||||
assertKeyCode(StandaloneKeyCode.KEY_O, RuntimeKeyCode.KEY_O);
|
||||
assertKeyCode(StandaloneKeyCode.KEY_P, RuntimeKeyCode.KEY_P);
|
||||
assertKeyCode(StandaloneKeyCode.KEY_Q, RuntimeKeyCode.KEY_Q);
|
||||
assertKeyCode(StandaloneKeyCode.KEY_R, RuntimeKeyCode.KEY_R);
|
||||
assertKeyCode(StandaloneKeyCode.KEY_S, RuntimeKeyCode.KEY_S);
|
||||
assertKeyCode(StandaloneKeyCode.KEY_T, RuntimeKeyCode.KEY_T);
|
||||
assertKeyCode(StandaloneKeyCode.KEY_U, RuntimeKeyCode.KEY_U);
|
||||
assertKeyCode(StandaloneKeyCode.KEY_V, RuntimeKeyCode.KEY_V);
|
||||
assertKeyCode(StandaloneKeyCode.KEY_W, RuntimeKeyCode.KEY_W);
|
||||
assertKeyCode(StandaloneKeyCode.KEY_X, RuntimeKeyCode.KEY_X);
|
||||
assertKeyCode(StandaloneKeyCode.KEY_Y, RuntimeKeyCode.KEY_Y);
|
||||
assertKeyCode(StandaloneKeyCode.KEY_Z, RuntimeKeyCode.KEY_Z);
|
||||
assertKeyCode(StandaloneKeyCode.Meta, RuntimeKeyCode.Meta);
|
||||
assertKeyCode(StandaloneKeyCode.ContextMenu, RuntimeKeyCode.ContextMenu);
|
||||
assertKeyCode(StandaloneKeyCode.F1, RuntimeKeyCode.F1);
|
||||
assertKeyCode(StandaloneKeyCode.F2, RuntimeKeyCode.F2);
|
||||
assertKeyCode(StandaloneKeyCode.F3, RuntimeKeyCode.F3);
|
||||
assertKeyCode(StandaloneKeyCode.F4, RuntimeKeyCode.F4);
|
||||
assertKeyCode(StandaloneKeyCode.F5, RuntimeKeyCode.F5);
|
||||
assertKeyCode(StandaloneKeyCode.F6, RuntimeKeyCode.F6);
|
||||
assertKeyCode(StandaloneKeyCode.F7, RuntimeKeyCode.F7);
|
||||
assertKeyCode(StandaloneKeyCode.F8, RuntimeKeyCode.F8);
|
||||
assertKeyCode(StandaloneKeyCode.F9, RuntimeKeyCode.F9);
|
||||
assertKeyCode(StandaloneKeyCode.F10, RuntimeKeyCode.F10);
|
||||
assertKeyCode(StandaloneKeyCode.F11, RuntimeKeyCode.F11);
|
||||
assertKeyCode(StandaloneKeyCode.F12, RuntimeKeyCode.F12);
|
||||
assertKeyCode(StandaloneKeyCode.F13, RuntimeKeyCode.F13);
|
||||
assertKeyCode(StandaloneKeyCode.F14, RuntimeKeyCode.F14);
|
||||
assertKeyCode(StandaloneKeyCode.F15, RuntimeKeyCode.F15);
|
||||
assertKeyCode(StandaloneKeyCode.F16, RuntimeKeyCode.F16);
|
||||
assertKeyCode(StandaloneKeyCode.F17, RuntimeKeyCode.F17);
|
||||
assertKeyCode(StandaloneKeyCode.F18, RuntimeKeyCode.F18);
|
||||
assertKeyCode(StandaloneKeyCode.F19, RuntimeKeyCode.F19);
|
||||
assertKeyCode(StandaloneKeyCode.NumLock, RuntimeKeyCode.NumLock);
|
||||
assertKeyCode(StandaloneKeyCode.ScrollLock, RuntimeKeyCode.ScrollLock);
|
||||
assertKeyCode(StandaloneKeyCode.US_SEMICOLON, RuntimeKeyCode.US_SEMICOLON);
|
||||
assertKeyCode(StandaloneKeyCode.US_EQUAL, RuntimeKeyCode.US_EQUAL);
|
||||
assertKeyCode(StandaloneKeyCode.US_COMMA, RuntimeKeyCode.US_COMMA);
|
||||
assertKeyCode(StandaloneKeyCode.US_MINUS, RuntimeKeyCode.US_MINUS);
|
||||
assertKeyCode(StandaloneKeyCode.US_DOT, RuntimeKeyCode.US_DOT);
|
||||
assertKeyCode(StandaloneKeyCode.US_SLASH, RuntimeKeyCode.US_SLASH);
|
||||
assertKeyCode(StandaloneKeyCode.US_BACKTICK, RuntimeKeyCode.US_BACKTICK);
|
||||
assertKeyCode(StandaloneKeyCode.US_OPEN_SQUARE_BRACKET, RuntimeKeyCode.US_OPEN_SQUARE_BRACKET);
|
||||
assertKeyCode(StandaloneKeyCode.US_BACKSLASH, RuntimeKeyCode.US_BACKSLASH);
|
||||
assertKeyCode(StandaloneKeyCode.US_CLOSE_SQUARE_BRACKET, RuntimeKeyCode.US_CLOSE_SQUARE_BRACKET);
|
||||
assertKeyCode(StandaloneKeyCode.US_QUOTE, RuntimeKeyCode.US_QUOTE);
|
||||
assertKeyCode(StandaloneKeyCode.OEM_8, RuntimeKeyCode.OEM_8);
|
||||
assertKeyCode(StandaloneKeyCode.OEM_102, RuntimeKeyCode.OEM_102);
|
||||
assertKeyCode(StandaloneKeyCode.NUMPAD_0, RuntimeKeyCode.NUMPAD_0);
|
||||
assertKeyCode(StandaloneKeyCode.NUMPAD_1, RuntimeKeyCode.NUMPAD_1);
|
||||
assertKeyCode(StandaloneKeyCode.NUMPAD_2, RuntimeKeyCode.NUMPAD_2);
|
||||
assertKeyCode(StandaloneKeyCode.NUMPAD_3, RuntimeKeyCode.NUMPAD_3);
|
||||
assertKeyCode(StandaloneKeyCode.NUMPAD_4, RuntimeKeyCode.NUMPAD_4);
|
||||
assertKeyCode(StandaloneKeyCode.NUMPAD_5, RuntimeKeyCode.NUMPAD_5);
|
||||
assertKeyCode(StandaloneKeyCode.NUMPAD_6, RuntimeKeyCode.NUMPAD_6);
|
||||
assertKeyCode(StandaloneKeyCode.NUMPAD_7, RuntimeKeyCode.NUMPAD_7);
|
||||
assertKeyCode(StandaloneKeyCode.NUMPAD_8, RuntimeKeyCode.NUMPAD_8);
|
||||
assertKeyCode(StandaloneKeyCode.NUMPAD_9, RuntimeKeyCode.NUMPAD_9);
|
||||
assertKeyCode(StandaloneKeyCode.NUMPAD_MULTIPLY, RuntimeKeyCode.NUMPAD_MULTIPLY);
|
||||
assertKeyCode(StandaloneKeyCode.NUMPAD_ADD, RuntimeKeyCode.NUMPAD_ADD);
|
||||
assertKeyCode(StandaloneKeyCode.NUMPAD_SEPARATOR, RuntimeKeyCode.NUMPAD_SEPARATOR);
|
||||
assertKeyCode(StandaloneKeyCode.NUMPAD_SUBTRACT, RuntimeKeyCode.NUMPAD_SUBTRACT);
|
||||
assertKeyCode(StandaloneKeyCode.NUMPAD_DECIMAL, RuntimeKeyCode.NUMPAD_DECIMAL);
|
||||
assertKeyCode(StandaloneKeyCode.NUMPAD_DIVIDE, RuntimeKeyCode.NUMPAD_DIVIDE);
|
||||
assertKeyCode(StandaloneKeyCode.KEY_IN_COMPOSITION, RuntimeKeyCode.KEY_IN_COMPOSITION);
|
||||
assertKeyCode(StandaloneKeyCode.ABNT_C1, RuntimeKeyCode.ABNT_C1);
|
||||
assertKeyCode(StandaloneKeyCode.ABNT_C2, RuntimeKeyCode.ABNT_C2);
|
||||
assertKeyCode(StandaloneKeyCode.MAX_VALUE, RuntimeKeyCode.MAX_VALUE);
|
||||
});
|
||||
});
|
||||
187
src/vs/editor/test/common/view/minimapCharRenderer.test.ts
Normal file
187
src/vs/editor/test/common/view/minimapCharRenderer.test.ts
Normal file
@@ -0,0 +1,187 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { Constants } from 'vs/editor/common/view/minimapCharRenderer';
|
||||
import { MinimapCharRendererFactory } from 'vs/editor/test/common/view/minimapCharRendererFactory';
|
||||
import { getOrCreateMinimapCharRenderer } from 'vs/editor/common/view/runtimeMinimapCharRenderer';
|
||||
import { RGBA8 } from 'vs/editor/common/core/rgba';
|
||||
|
||||
suite('MinimapCharRenderer', () => {
|
||||
|
||||
let sampleData: Uint8ClampedArray = null;
|
||||
|
||||
suiteSetup(() => {
|
||||
sampleData = new Uint8ClampedArray(Constants.SAMPLED_CHAR_HEIGHT * Constants.SAMPLED_CHAR_WIDTH * Constants.RGBA_CHANNELS_CNT * Constants.CHAR_COUNT);
|
||||
});
|
||||
|
||||
suiteTeardown(() => {
|
||||
sampleData = null;
|
||||
});
|
||||
|
||||
setup(() => {
|
||||
for (let i = 0; i < sampleData.length; i++) {
|
||||
sampleData[i] = 0;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
const sampleD = [
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xd0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xd0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xd0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0d, 0xff, 0xff, 0xff, 0xa3, 0xff, 0xff, 0xff, 0xf3, 0xff, 0xff, 0xff, 0xe5, 0xff, 0xff, 0xff, 0x5e, 0xff, 0xff, 0xff, 0xd0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xa4, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x00, 0x00, 0x00, 0x00,
|
||||
0xff, 0xff, 0xff, 0x10, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x94, 0xff, 0xff, 0xff, 0x02, 0xff, 0xff, 0xff, 0x6a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x00, 0x00, 0x00, 0x00,
|
||||
0xff, 0xff, 0xff, 0x3b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x22, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x03, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x00, 0x00, 0x00, 0x00,
|
||||
0xff, 0xff, 0xff, 0x47, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xd6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x00, 0x00, 0x00, 0x00,
|
||||
0xff, 0xff, 0xff, 0x31, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x00, 0x00, 0x00, 0x00,
|
||||
0xff, 0xff, 0xff, 0x0e, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x69, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x9b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xb9, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0e, 0xff, 0xff, 0xff, 0xa7, 0xff, 0xff, 0xff, 0xf5, 0xff, 0xff, 0xff, 0xe8, 0xff, 0xff, 0xff, 0x71, 0xff, 0xff, 0xff, 0xd0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
];
|
||||
|
||||
function setSampleData(charCode: number, data: number[]) {
|
||||
const rowWidth = Constants.SAMPLED_CHAR_WIDTH * Constants.RGBA_CHANNELS_CNT * Constants.CHAR_COUNT;
|
||||
let chIndex = charCode - Constants.START_CH_CODE;
|
||||
|
||||
let globalOutputOffset = chIndex * Constants.SAMPLED_CHAR_WIDTH * Constants.RGBA_CHANNELS_CNT;
|
||||
let inputOffset = 0;
|
||||
for (let i = 0; i < Constants.SAMPLED_CHAR_HEIGHT; i++) {
|
||||
let outputOffset = globalOutputOffset;
|
||||
for (let j = 0; j < Constants.SAMPLED_CHAR_WIDTH; j++) {
|
||||
for (let channel = 0; channel < Constants.RGBA_CHANNELS_CNT; channel++) {
|
||||
sampleData[outputOffset] = data[inputOffset];
|
||||
inputOffset++;
|
||||
outputOffset++;
|
||||
}
|
||||
}
|
||||
globalOutputOffset += rowWidth;
|
||||
}
|
||||
}
|
||||
|
||||
function createFakeImageData(width: number, height: number): ImageData {
|
||||
return {
|
||||
width: width,
|
||||
height: height,
|
||||
data: new Uint8ClampedArray(width * height * Constants.RGBA_CHANNELS_CNT)
|
||||
};
|
||||
}
|
||||
|
||||
test('letter d @ 2x', () => {
|
||||
setSampleData('d'.charCodeAt(0), sampleD);
|
||||
let renderer = MinimapCharRendererFactory.create(sampleData);
|
||||
|
||||
let background = new RGBA8(0, 0, 0, 255);
|
||||
let color = new RGBA8(255, 255, 255, 255);
|
||||
let imageData = createFakeImageData(Constants.x2_CHAR_WIDTH, Constants.x2_CHAR_HEIGHT);
|
||||
// set the background color
|
||||
for (let i = 0, len = imageData.data.length / 4; i < len; i++) {
|
||||
imageData.data[4 * i + 0] = background.r;
|
||||
imageData.data[4 * i + 1] = background.g;
|
||||
imageData.data[4 * i + 2] = background.b;
|
||||
imageData.data[4 * i + 3] = 255;
|
||||
}
|
||||
renderer.x2RenderChar(imageData, 0, 0, 'd'.charCodeAt(0), color, background, false);
|
||||
|
||||
let actual: number[] = [];
|
||||
for (let i = 0; i < imageData.data.length; i++) {
|
||||
actual[i] = imageData.data[i];
|
||||
}
|
||||
assert.deepEqual(actual, [
|
||||
0x00, 0x00, 0x00, 0xff, 0x6d, 0x6d, 0x6d, 0xff,
|
||||
0xbb, 0xbb, 0xbb, 0xff, 0xbe, 0xbe, 0xbe, 0xff,
|
||||
0x94, 0x94, 0x94, 0xff, 0x7e, 0x7e, 0x7e, 0xff,
|
||||
0xb1, 0xb1, 0xb1, 0xff, 0xbb, 0xbb, 0xbb, 0xff,
|
||||
]);
|
||||
});
|
||||
|
||||
test('letter d @ 2x at runtime', () => {
|
||||
let renderer = getOrCreateMinimapCharRenderer();
|
||||
|
||||
let background = new RGBA8(0, 0, 0, 255);
|
||||
let color = new RGBA8(255, 255, 255, 255);
|
||||
let imageData = createFakeImageData(Constants.x2_CHAR_WIDTH, Constants.x2_CHAR_HEIGHT);
|
||||
// set the background color
|
||||
for (let i = 0, len = imageData.data.length / 4; i < len; i++) {
|
||||
imageData.data[4 * i + 0] = background.r;
|
||||
imageData.data[4 * i + 1] = background.g;
|
||||
imageData.data[4 * i + 2] = background.b;
|
||||
imageData.data[4 * i + 3] = 255;
|
||||
}
|
||||
|
||||
renderer.x2RenderChar(imageData, 0, 0, 'd'.charCodeAt(0), color, background, false);
|
||||
|
||||
let actual: number[] = [];
|
||||
for (let i = 0; i < imageData.data.length; i++) {
|
||||
actual[i] = imageData.data[i];
|
||||
}
|
||||
assert.deepEqual(actual, [
|
||||
0x00, 0x00, 0x00, 0xff, 0x6d, 0x6d, 0x6d, 0xff,
|
||||
0xbb, 0xbb, 0xbb, 0xff, 0xbe, 0xbe, 0xbe, 0xff,
|
||||
0x94, 0x94, 0x94, 0xff, 0x7e, 0x7e, 0x7e, 0xff,
|
||||
0xb1, 0xb1, 0xb1, 0xff, 0xbb, 0xbb, 0xbb, 0xff,
|
||||
]);
|
||||
});
|
||||
|
||||
test('letter d @ 1x', () => {
|
||||
setSampleData('d'.charCodeAt(0), sampleD);
|
||||
let renderer = MinimapCharRendererFactory.create(sampleData);
|
||||
|
||||
let background = new RGBA8(0, 0, 0, 255);
|
||||
let color = new RGBA8(255, 255, 255, 255);
|
||||
let imageData = createFakeImageData(Constants.x1_CHAR_WIDTH, Constants.x1_CHAR_HEIGHT);
|
||||
// set the background color
|
||||
for (let i = 0, len = imageData.data.length / 4; i < len; i++) {
|
||||
imageData.data[4 * i + 0] = background.r;
|
||||
imageData.data[4 * i + 1] = background.g;
|
||||
imageData.data[4 * i + 2] = background.b;
|
||||
imageData.data[4 * i + 3] = 255;
|
||||
}
|
||||
|
||||
renderer.x1RenderChar(imageData, 0, 0, 'd'.charCodeAt(0), color, background, false);
|
||||
|
||||
let actual: number[] = [];
|
||||
for (let i = 0; i < imageData.data.length; i++) {
|
||||
actual[i] = imageData.data[i];
|
||||
}
|
||||
assert.deepEqual(actual, [
|
||||
0x55, 0x55, 0x55, 0xff,
|
||||
0x93, 0x93, 0x93, 0xff,
|
||||
]);
|
||||
});
|
||||
|
||||
test('letter d @ 1x at runtime', () => {
|
||||
let renderer = getOrCreateMinimapCharRenderer();
|
||||
|
||||
let background = new RGBA8(0, 0, 0, 255);
|
||||
let color = new RGBA8(255, 255, 255, 255);
|
||||
let imageData = createFakeImageData(Constants.x1_CHAR_WIDTH, Constants.x1_CHAR_HEIGHT);
|
||||
// set the background color
|
||||
for (let i = 0, len = imageData.data.length / 4; i < len; i++) {
|
||||
imageData.data[4 * i + 0] = background.r;
|
||||
imageData.data[4 * i + 1] = background.g;
|
||||
imageData.data[4 * i + 2] = background.b;
|
||||
imageData.data[4 * i + 3] = 255;
|
||||
}
|
||||
|
||||
renderer.x1RenderChar(imageData, 0, 0, 'd'.charCodeAt(0), color, background, false);
|
||||
|
||||
let actual: number[] = [];
|
||||
for (let i = 0; i < imageData.data.length; i++) {
|
||||
actual[i] = imageData.data[i];
|
||||
}
|
||||
assert.deepEqual(actual, [
|
||||
0x55, 0x55, 0x55, 0xff,
|
||||
0x93, 0x93, 0x93, 0xff,
|
||||
]);
|
||||
});
|
||||
|
||||
});
|
||||
173
src/vs/editor/test/common/view/minimapCharRendererFactory.ts
Normal file
173
src/vs/editor/test/common/view/minimapCharRendererFactory.ts
Normal file
@@ -0,0 +1,173 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { Constants, MinimapCharRenderer } from 'vs/editor/common/view/minimapCharRenderer';
|
||||
|
||||
const enum InternalConstants {
|
||||
CA_CHANNELS_CNT = 2,
|
||||
}
|
||||
|
||||
export class MinimapCharRendererFactory {
|
||||
|
||||
public static create(source: Uint8ClampedArray): MinimapCharRenderer {
|
||||
const expectedLength = (Constants.SAMPLED_CHAR_HEIGHT * Constants.SAMPLED_CHAR_WIDTH * Constants.RGBA_CHANNELS_CNT * Constants.CHAR_COUNT);
|
||||
if (source.length !== expectedLength) {
|
||||
throw new Error('Unexpected source in MinimapCharRenderer');
|
||||
}
|
||||
|
||||
let x2CharData = this.toGrayscale(MinimapCharRendererFactory._downsample2x(source));
|
||||
let x1CharData = this.toGrayscale(MinimapCharRendererFactory._downsample1x(source));
|
||||
return new MinimapCharRenderer(x2CharData, x1CharData);
|
||||
}
|
||||
|
||||
private static toGrayscale(charData: Uint8ClampedArray): Uint8ClampedArray {
|
||||
let newLength = charData.length / 2;
|
||||
let result = new Uint8ClampedArray(newLength);
|
||||
let sourceOffset = 0;
|
||||
for (var i = 0; i < newLength; i++) {
|
||||
let color = charData[sourceOffset];
|
||||
let alpha = charData[sourceOffset + 1];
|
||||
let newColor = Math.round((color * alpha) / 255);
|
||||
result[i] = newColor;
|
||||
sourceOffset += 2;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static _extractSampledChar(source: Uint8ClampedArray, charIndex: number, dest: Uint8ClampedArray) {
|
||||
let destOffset = 0;
|
||||
for (let i = 0; i < Constants.SAMPLED_CHAR_HEIGHT; i++) {
|
||||
let sourceOffset = (
|
||||
Constants.SAMPLED_CHAR_WIDTH * Constants.RGBA_CHANNELS_CNT * Constants.CHAR_COUNT * i
|
||||
+ Constants.SAMPLED_CHAR_WIDTH * Constants.RGBA_CHANNELS_CNT * charIndex
|
||||
);
|
||||
for (let j = 0; j < Constants.SAMPLED_CHAR_WIDTH; j++) {
|
||||
for (let c = 0; c < Constants.RGBA_CHANNELS_CNT; c++) {
|
||||
dest[destOffset] = source[sourceOffset];
|
||||
sourceOffset++;
|
||||
destOffset++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static _downsample2xChar(source: Uint8ClampedArray, dest: Uint8ClampedArray): void {
|
||||
// chars are 2 x 4px (width x height)
|
||||
const resultLen = Constants.x2_CHAR_HEIGHT * Constants.x2_CHAR_WIDTH * InternalConstants.CA_CHANNELS_CNT;
|
||||
const result = new Uint16Array(resultLen);
|
||||
for (let i = 0; i < resultLen; i++) {
|
||||
result[i] = 0;
|
||||
}
|
||||
|
||||
let inputOffset = 0, globalOutputOffset = 0;
|
||||
for (let i = 0; i < Constants.SAMPLED_CHAR_HEIGHT; i++) {
|
||||
|
||||
let outputOffset = globalOutputOffset;
|
||||
|
||||
let color = 0;
|
||||
let alpha = 0;
|
||||
for (let j = 0; j < Constants.SAMPLED_HALF_CHAR_WIDTH; j++) {
|
||||
color += source[inputOffset]; // R
|
||||
alpha += source[inputOffset + 3]; // A
|
||||
inputOffset += Constants.RGBA_CHANNELS_CNT;
|
||||
}
|
||||
result[outputOffset] += color;
|
||||
result[outputOffset + 1] += alpha;
|
||||
outputOffset += InternalConstants.CA_CHANNELS_CNT;
|
||||
|
||||
color = 0;
|
||||
alpha = 0;
|
||||
for (let j = 0; j < Constants.SAMPLED_HALF_CHAR_WIDTH; j++) {
|
||||
color += source[inputOffset]; // R
|
||||
alpha += source[inputOffset + 3]; // A
|
||||
inputOffset += Constants.RGBA_CHANNELS_CNT;
|
||||
}
|
||||
result[outputOffset] += color;
|
||||
result[outputOffset + 1] += alpha;
|
||||
outputOffset += InternalConstants.CA_CHANNELS_CNT;
|
||||
|
||||
if (i === 2 || i === 5 || i === 8) {
|
||||
globalOutputOffset = outputOffset;
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < resultLen; i++) {
|
||||
dest[i] = result[i] / 12; // 15 it should be
|
||||
}
|
||||
}
|
||||
|
||||
private static _downsample2x(data: Uint8ClampedArray): Uint8ClampedArray {
|
||||
const resultLen = Constants.x2_CHAR_HEIGHT * Constants.x2_CHAR_WIDTH * InternalConstants.CA_CHANNELS_CNT * Constants.CHAR_COUNT;
|
||||
const result = new Uint8ClampedArray(resultLen);
|
||||
|
||||
const sampledChar = new Uint8ClampedArray(Constants.SAMPLED_CHAR_HEIGHT * Constants.SAMPLED_CHAR_WIDTH * Constants.RGBA_CHANNELS_CNT);
|
||||
const downsampledChar = new Uint8ClampedArray(Constants.x2_CHAR_HEIGHT * Constants.x2_CHAR_WIDTH * InternalConstants.CA_CHANNELS_CNT);
|
||||
|
||||
for (let charIndex = 0; charIndex < Constants.CHAR_COUNT; charIndex++) {
|
||||
this._extractSampledChar(data, charIndex, sampledChar);
|
||||
this._downsample2xChar(sampledChar, downsampledChar);
|
||||
let resultOffset = (Constants.x2_CHAR_HEIGHT * Constants.x2_CHAR_WIDTH * InternalConstants.CA_CHANNELS_CNT * charIndex);
|
||||
for (let i = 0; i < downsampledChar.length; i++) {
|
||||
result[resultOffset + i] = downsampledChar[i];
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static _downsample1xChar(source: Uint8ClampedArray, dest: Uint8ClampedArray): void {
|
||||
// chars are 1 x 2px (width x height)
|
||||
const resultLen = Constants.x1_CHAR_HEIGHT * Constants.x1_CHAR_WIDTH * InternalConstants.CA_CHANNELS_CNT;
|
||||
const result = new Uint16Array(resultLen);
|
||||
for (let i = 0; i < resultLen; i++) {
|
||||
result[i] = 0;
|
||||
}
|
||||
|
||||
let inputOffset = 0, globalOutputOffset = 0;
|
||||
for (let i = 0; i < Constants.SAMPLED_CHAR_HEIGHT; i++) {
|
||||
|
||||
let outputOffset = globalOutputOffset;
|
||||
|
||||
let color = 0;
|
||||
let alpha = 0;
|
||||
for (let j = 0; j < Constants.SAMPLED_CHAR_WIDTH; j++) {
|
||||
color += source[inputOffset]; // R
|
||||
alpha += source[inputOffset + 3]; // A
|
||||
inputOffset += Constants.RGBA_CHANNELS_CNT;
|
||||
}
|
||||
result[outputOffset] += color;
|
||||
result[outputOffset + 1] += alpha;
|
||||
outputOffset += InternalConstants.CA_CHANNELS_CNT;
|
||||
|
||||
if (i === 5) {
|
||||
globalOutputOffset = outputOffset;
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < resultLen; i++) {
|
||||
dest[i] = result[i] / 50; // 60 it should be
|
||||
}
|
||||
}
|
||||
|
||||
private static _downsample1x(data: Uint8ClampedArray): Uint8ClampedArray {
|
||||
const resultLen = Constants.x1_CHAR_HEIGHT * Constants.x1_CHAR_WIDTH * InternalConstants.CA_CHANNELS_CNT * Constants.CHAR_COUNT;
|
||||
const result = new Uint8ClampedArray(resultLen);
|
||||
|
||||
const sampledChar = new Uint8ClampedArray(Constants.SAMPLED_CHAR_HEIGHT * Constants.SAMPLED_CHAR_WIDTH * Constants.RGBA_CHANNELS_CNT);
|
||||
const downsampledChar = new Uint8ClampedArray(Constants.x1_CHAR_HEIGHT * Constants.x1_CHAR_WIDTH * InternalConstants.CA_CHANNELS_CNT);
|
||||
|
||||
for (let charIndex = 0; charIndex < Constants.CHAR_COUNT; charIndex++) {
|
||||
this._extractSampledChar(data, charIndex, sampledChar);
|
||||
this._downsample1xChar(sampledChar, downsampledChar);
|
||||
let resultOffset = (Constants.x1_CHAR_HEIGHT * Constants.x1_CHAR_WIDTH * InternalConstants.CA_CHANNELS_CNT * charIndex);
|
||||
for (let i = 0; i < downsampledChar.length; i++) {
|
||||
result[resultOffset + i] = downsampledChar[i];
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
101
src/vs/editor/test/common/view/overviewZoneManager.test.ts
Normal file
101
src/vs/editor/test/common/view/overviewZoneManager.test.ts
Normal file
@@ -0,0 +1,101 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { OverviewRulerLane } from 'vs/editor/common/editorCommon';
|
||||
import { OverviewZoneManager, ColorZone, OverviewRulerZone } from 'vs/editor/common/view/overviewZoneManager';
|
||||
import { LIGHT } from 'vs/platform/theme/common/themeService';
|
||||
|
||||
suite('Editor View - OverviewZoneManager', () => {
|
||||
|
||||
test('pixel ratio 1, dom height 600', () => {
|
||||
const LINE_COUNT = 50;
|
||||
const LINE_HEIGHT = 20;
|
||||
let manager = new OverviewZoneManager((lineNumber) => LINE_HEIGHT * lineNumber);
|
||||
manager.setMinimumHeight(6);
|
||||
manager.setMaximumHeight(6);
|
||||
manager.setThemeType(LIGHT);
|
||||
manager.setDOMWidth(30);
|
||||
manager.setDOMHeight(600);
|
||||
manager.setOuterHeight(LINE_COUNT * LINE_HEIGHT);
|
||||
manager.setLineHeight(LINE_HEIGHT);
|
||||
manager.setPixelRatio(1);
|
||||
|
||||
manager.setZones([
|
||||
new OverviewRulerZone(1, 1, OverviewRulerLane.Full, 10, '1', '1', '1'),
|
||||
new OverviewRulerZone(10, 10, OverviewRulerLane.Full, 0, '2', '2', '2'),
|
||||
new OverviewRulerZone(30, 31, OverviewRulerLane.Full, 0, '3', '3', '3'),
|
||||
new OverviewRulerZone(50, 50, OverviewRulerLane.Full, 0, '4', '4', '4'),
|
||||
]);
|
||||
|
||||
// one line = 12, but cap is at 6
|
||||
assert.deepEqual(manager.resolveColorZones(), [
|
||||
new ColorZone(12, 22, 1, OverviewRulerLane.Full), // forced height of 10
|
||||
new ColorZone(123, 129, 2, OverviewRulerLane.Full), // 120 -> 132
|
||||
new ColorZone(363, 369, 3, OverviewRulerLane.Full), // 360 -> 372 [360 -> 384]
|
||||
new ColorZone(375, 381, 3, OverviewRulerLane.Full), // 372 -> 384 [360 -> 384]
|
||||
new ColorZone(594, 600, 4, OverviewRulerLane.Full), // 588 -> 600
|
||||
]);
|
||||
});
|
||||
|
||||
test('pixel ratio 1, dom height 300', () => {
|
||||
const LINE_COUNT = 50;
|
||||
const LINE_HEIGHT = 20;
|
||||
let manager = new OverviewZoneManager((lineNumber) => LINE_HEIGHT * lineNumber);
|
||||
manager.setMinimumHeight(6);
|
||||
manager.setMaximumHeight(6);
|
||||
manager.setThemeType(LIGHT);
|
||||
manager.setDOMWidth(30);
|
||||
manager.setDOMHeight(300);
|
||||
manager.setOuterHeight(LINE_COUNT * LINE_HEIGHT);
|
||||
manager.setLineHeight(LINE_HEIGHT);
|
||||
manager.setPixelRatio(1);
|
||||
|
||||
manager.setZones([
|
||||
new OverviewRulerZone(1, 1, OverviewRulerLane.Full, 10, '1', '1', '1'),
|
||||
new OverviewRulerZone(10, 10, OverviewRulerLane.Full, 0, '2', '2', '2'),
|
||||
new OverviewRulerZone(30, 31, OverviewRulerLane.Full, 0, '3', '3', '3'),
|
||||
new OverviewRulerZone(50, 50, OverviewRulerLane.Full, 0, '4', '4', '4'),
|
||||
]);
|
||||
|
||||
// one line = 6, cap is at 6
|
||||
assert.deepEqual(manager.resolveColorZones(), [
|
||||
new ColorZone(6, 16, 1, OverviewRulerLane.Full), // forced height of 10
|
||||
new ColorZone(60, 66, 2, OverviewRulerLane.Full), // 60 -> 66
|
||||
new ColorZone(180, 192, 3, OverviewRulerLane.Full), // 180 -> 192
|
||||
new ColorZone(294, 300, 4, OverviewRulerLane.Full), // 294 -> 300
|
||||
]);
|
||||
});
|
||||
|
||||
test('pixel ratio 2, dom height 300', () => {
|
||||
const LINE_COUNT = 50;
|
||||
const LINE_HEIGHT = 20;
|
||||
let manager = new OverviewZoneManager((lineNumber) => LINE_HEIGHT * lineNumber);
|
||||
manager.setMinimumHeight(6);
|
||||
manager.setMaximumHeight(6);
|
||||
manager.setThemeType(LIGHT);
|
||||
manager.setDOMWidth(30);
|
||||
manager.setDOMHeight(300);
|
||||
manager.setOuterHeight(LINE_COUNT * LINE_HEIGHT);
|
||||
manager.setLineHeight(LINE_HEIGHT);
|
||||
manager.setPixelRatio(2);
|
||||
|
||||
manager.setZones([
|
||||
new OverviewRulerZone(1, 1, OverviewRulerLane.Full, 10, '1', '1', '1'),
|
||||
new OverviewRulerZone(10, 10, OverviewRulerLane.Full, 0, '2', '2', '2'),
|
||||
new OverviewRulerZone(30, 31, OverviewRulerLane.Full, 0, '3', '3', '3'),
|
||||
new OverviewRulerZone(50, 50, OverviewRulerLane.Full, 0, '4', '4', '4'),
|
||||
]);
|
||||
|
||||
// one line = 6, cap is at 12
|
||||
assert.deepEqual(manager.resolveColorZones(), [
|
||||
new ColorZone(12, 32, 1, OverviewRulerLane.Full), // forced height of 10 => forced height of 20
|
||||
new ColorZone(120, 132, 2, OverviewRulerLane.Full), // 120 -> 132
|
||||
new ColorZone(360, 384, 3, OverviewRulerLane.Full), // 360 -> 384
|
||||
new ColorZone(588, 600, 4, OverviewRulerLane.Full), // 588 -> 600
|
||||
]);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,744 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { RenderMinimap, EditorLayoutInfo, EditorLayoutProvider, IEditorLayoutProviderOpts } from 'vs/editor/common/config/editorOptions';
|
||||
|
||||
suite('Editor ViewLayout - EditorLayoutProvider', () => {
|
||||
|
||||
function doTest(input: IEditorLayoutProviderOpts, expected: EditorLayoutInfo): void {
|
||||
let actual = EditorLayoutProvider.compute(input);
|
||||
assert.deepEqual(actual, expected);
|
||||
}
|
||||
|
||||
test('EditorLayoutProvider 1', () => {
|
||||
doTest({
|
||||
outerWidth: 1000,
|
||||
outerHeight: 800,
|
||||
showGlyphMargin: false,
|
||||
lineHeight: 16,
|
||||
showLineNumbers: false,
|
||||
lineNumbersMinChars: 0,
|
||||
lineNumbersDigitCount: 1,
|
||||
lineDecorationsWidth: 10,
|
||||
typicalHalfwidthCharacterWidth: 10,
|
||||
maxDigitWidth: 10,
|
||||
verticalScrollbarWidth: 0,
|
||||
horizontalScrollbarHeight: 0,
|
||||
scrollbarArrowSize: 0,
|
||||
verticalScrollbarHasArrows: false,
|
||||
minimap: false,
|
||||
minimapRenderCharacters: true,
|
||||
minimapMaxColumn: 150,
|
||||
pixelRatio: 1,
|
||||
}, {
|
||||
width: 1000,
|
||||
height: 800,
|
||||
|
||||
glyphMarginLeft: 0,
|
||||
glyphMarginWidth: 0,
|
||||
glyphMarginHeight: 800,
|
||||
|
||||
lineNumbersLeft: 0,
|
||||
lineNumbersWidth: 0,
|
||||
lineNumbersHeight: 800,
|
||||
|
||||
decorationsLeft: 0,
|
||||
decorationsWidth: 10,
|
||||
decorationsHeight: 800,
|
||||
|
||||
contentLeft: 10,
|
||||
contentWidth: 990,
|
||||
contentHeight: 800,
|
||||
|
||||
renderMinimap: RenderMinimap.None,
|
||||
minimapWidth: 0,
|
||||
viewportColumn: 99,
|
||||
|
||||
verticalScrollbarWidth: 0,
|
||||
horizontalScrollbarHeight: 0,
|
||||
|
||||
overviewRuler: {
|
||||
top: 0,
|
||||
width: 0,
|
||||
height: 800,
|
||||
right: 0
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test('EditorLayoutProvider 1.1', () => {
|
||||
doTest({
|
||||
outerWidth: 1000,
|
||||
outerHeight: 800,
|
||||
showGlyphMargin: false,
|
||||
lineHeight: 16,
|
||||
showLineNumbers: false,
|
||||
lineNumbersMinChars: 0,
|
||||
lineNumbersDigitCount: 1,
|
||||
lineDecorationsWidth: 10,
|
||||
typicalHalfwidthCharacterWidth: 10,
|
||||
maxDigitWidth: 10,
|
||||
verticalScrollbarWidth: 11,
|
||||
horizontalScrollbarHeight: 12,
|
||||
scrollbarArrowSize: 13,
|
||||
verticalScrollbarHasArrows: true,
|
||||
minimap: false,
|
||||
minimapRenderCharacters: true,
|
||||
minimapMaxColumn: 150,
|
||||
pixelRatio: 1,
|
||||
}, {
|
||||
width: 1000,
|
||||
height: 800,
|
||||
|
||||
glyphMarginLeft: 0,
|
||||
glyphMarginWidth: 0,
|
||||
glyphMarginHeight: 800,
|
||||
|
||||
lineNumbersLeft: 0,
|
||||
lineNumbersWidth: 0,
|
||||
lineNumbersHeight: 800,
|
||||
|
||||
decorationsLeft: 0,
|
||||
decorationsWidth: 10,
|
||||
decorationsHeight: 800,
|
||||
|
||||
contentLeft: 10,
|
||||
contentWidth: 990,
|
||||
contentHeight: 800,
|
||||
|
||||
renderMinimap: RenderMinimap.None,
|
||||
minimapWidth: 0,
|
||||
viewportColumn: 97,
|
||||
|
||||
verticalScrollbarWidth: 11,
|
||||
horizontalScrollbarHeight: 12,
|
||||
|
||||
overviewRuler: {
|
||||
top: 13,
|
||||
width: 11,
|
||||
height: (800 - 2 * 13),
|
||||
right: 0
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test('EditorLayoutProvider 2', () => {
|
||||
doTest({
|
||||
outerWidth: 900,
|
||||
outerHeight: 800,
|
||||
showGlyphMargin: false,
|
||||
lineHeight: 16,
|
||||
showLineNumbers: false,
|
||||
lineNumbersMinChars: 0,
|
||||
lineNumbersDigitCount: 1,
|
||||
lineDecorationsWidth: 10,
|
||||
typicalHalfwidthCharacterWidth: 10,
|
||||
maxDigitWidth: 10,
|
||||
verticalScrollbarWidth: 0,
|
||||
horizontalScrollbarHeight: 0,
|
||||
scrollbarArrowSize: 0,
|
||||
verticalScrollbarHasArrows: false,
|
||||
minimap: false,
|
||||
minimapRenderCharacters: true,
|
||||
minimapMaxColumn: 150,
|
||||
pixelRatio: 1,
|
||||
}, {
|
||||
width: 900,
|
||||
height: 800,
|
||||
|
||||
glyphMarginLeft: 0,
|
||||
glyphMarginWidth: 0,
|
||||
glyphMarginHeight: 800,
|
||||
|
||||
lineNumbersLeft: 0,
|
||||
lineNumbersWidth: 0,
|
||||
lineNumbersHeight: 800,
|
||||
|
||||
decorationsLeft: 0,
|
||||
decorationsWidth: 10,
|
||||
decorationsHeight: 800,
|
||||
|
||||
contentLeft: 10,
|
||||
contentWidth: 890,
|
||||
contentHeight: 800,
|
||||
|
||||
renderMinimap: RenderMinimap.None,
|
||||
minimapWidth: 0,
|
||||
viewportColumn: 89,
|
||||
|
||||
verticalScrollbarWidth: 0,
|
||||
horizontalScrollbarHeight: 0,
|
||||
|
||||
overviewRuler: {
|
||||
top: 0,
|
||||
width: 0,
|
||||
height: 800,
|
||||
right: 0
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test('EditorLayoutProvider 3', () => {
|
||||
doTest({
|
||||
outerWidth: 900,
|
||||
outerHeight: 900,
|
||||
showGlyphMargin: false,
|
||||
lineHeight: 16,
|
||||
showLineNumbers: false,
|
||||
lineNumbersMinChars: 0,
|
||||
lineNumbersDigitCount: 1,
|
||||
lineDecorationsWidth: 10,
|
||||
typicalHalfwidthCharacterWidth: 10,
|
||||
maxDigitWidth: 10,
|
||||
verticalScrollbarWidth: 0,
|
||||
horizontalScrollbarHeight: 0,
|
||||
scrollbarArrowSize: 0,
|
||||
verticalScrollbarHasArrows: false,
|
||||
minimap: false,
|
||||
minimapRenderCharacters: true,
|
||||
minimapMaxColumn: 150,
|
||||
pixelRatio: 1,
|
||||
}, {
|
||||
width: 900,
|
||||
height: 900,
|
||||
|
||||
glyphMarginLeft: 0,
|
||||
glyphMarginWidth: 0,
|
||||
glyphMarginHeight: 900,
|
||||
|
||||
lineNumbersLeft: 0,
|
||||
lineNumbersWidth: 0,
|
||||
lineNumbersHeight: 900,
|
||||
|
||||
decorationsLeft: 0,
|
||||
decorationsWidth: 10,
|
||||
decorationsHeight: 900,
|
||||
|
||||
contentLeft: 10,
|
||||
contentWidth: 890,
|
||||
contentHeight: 900,
|
||||
|
||||
renderMinimap: RenderMinimap.None,
|
||||
minimapWidth: 0,
|
||||
viewportColumn: 89,
|
||||
|
||||
verticalScrollbarWidth: 0,
|
||||
horizontalScrollbarHeight: 0,
|
||||
|
||||
overviewRuler: {
|
||||
top: 0,
|
||||
width: 0,
|
||||
height: 900,
|
||||
right: 0
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test('EditorLayoutProvider 4', () => {
|
||||
doTest({
|
||||
outerWidth: 900,
|
||||
outerHeight: 900,
|
||||
showGlyphMargin: false,
|
||||
lineHeight: 16,
|
||||
showLineNumbers: false,
|
||||
lineNumbersMinChars: 5,
|
||||
lineNumbersDigitCount: 1,
|
||||
lineDecorationsWidth: 10,
|
||||
typicalHalfwidthCharacterWidth: 10,
|
||||
maxDigitWidth: 10,
|
||||
verticalScrollbarWidth: 0,
|
||||
horizontalScrollbarHeight: 0,
|
||||
scrollbarArrowSize: 0,
|
||||
verticalScrollbarHasArrows: false,
|
||||
minimap: false,
|
||||
minimapRenderCharacters: true,
|
||||
minimapMaxColumn: 150,
|
||||
pixelRatio: 1,
|
||||
}, {
|
||||
width: 900,
|
||||
height: 900,
|
||||
|
||||
glyphMarginLeft: 0,
|
||||
glyphMarginWidth: 0,
|
||||
glyphMarginHeight: 900,
|
||||
|
||||
lineNumbersLeft: 0,
|
||||
lineNumbersWidth: 0,
|
||||
lineNumbersHeight: 900,
|
||||
|
||||
decorationsLeft: 0,
|
||||
decorationsWidth: 10,
|
||||
decorationsHeight: 900,
|
||||
|
||||
contentLeft: 10,
|
||||
contentWidth: 890,
|
||||
contentHeight: 900,
|
||||
|
||||
renderMinimap: RenderMinimap.None,
|
||||
minimapWidth: 0,
|
||||
viewportColumn: 89,
|
||||
|
||||
verticalScrollbarWidth: 0,
|
||||
horizontalScrollbarHeight: 0,
|
||||
|
||||
overviewRuler: {
|
||||
top: 0,
|
||||
width: 0,
|
||||
height: 900,
|
||||
right: 0
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test('EditorLayoutProvider 5', () => {
|
||||
doTest({
|
||||
outerWidth: 900,
|
||||
outerHeight: 900,
|
||||
showGlyphMargin: false,
|
||||
lineHeight: 16,
|
||||
showLineNumbers: true,
|
||||
lineNumbersMinChars: 5,
|
||||
lineNumbersDigitCount: 1,
|
||||
lineDecorationsWidth: 10,
|
||||
typicalHalfwidthCharacterWidth: 10,
|
||||
maxDigitWidth: 10,
|
||||
verticalScrollbarWidth: 0,
|
||||
horizontalScrollbarHeight: 0,
|
||||
scrollbarArrowSize: 0,
|
||||
verticalScrollbarHasArrows: false,
|
||||
minimap: false,
|
||||
minimapRenderCharacters: true,
|
||||
minimapMaxColumn: 150,
|
||||
pixelRatio: 1,
|
||||
}, {
|
||||
width: 900,
|
||||
height: 900,
|
||||
|
||||
glyphMarginLeft: 0,
|
||||
glyphMarginWidth: 0,
|
||||
glyphMarginHeight: 900,
|
||||
|
||||
lineNumbersLeft: 0,
|
||||
lineNumbersWidth: 50,
|
||||
lineNumbersHeight: 900,
|
||||
|
||||
decorationsLeft: 50,
|
||||
decorationsWidth: 10,
|
||||
decorationsHeight: 900,
|
||||
|
||||
contentLeft: 60,
|
||||
contentWidth: 840,
|
||||
contentHeight: 900,
|
||||
|
||||
renderMinimap: RenderMinimap.None,
|
||||
minimapWidth: 0,
|
||||
viewportColumn: 84,
|
||||
|
||||
verticalScrollbarWidth: 0,
|
||||
horizontalScrollbarHeight: 0,
|
||||
|
||||
overviewRuler: {
|
||||
top: 0,
|
||||
width: 0,
|
||||
height: 900,
|
||||
right: 0
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test('EditorLayoutProvider 6', () => {
|
||||
doTest({
|
||||
outerWidth: 900,
|
||||
outerHeight: 900,
|
||||
showGlyphMargin: false,
|
||||
lineHeight: 16,
|
||||
showLineNumbers: true,
|
||||
lineNumbersMinChars: 5,
|
||||
lineNumbersDigitCount: 5,
|
||||
lineDecorationsWidth: 10,
|
||||
typicalHalfwidthCharacterWidth: 10,
|
||||
maxDigitWidth: 10,
|
||||
verticalScrollbarWidth: 0,
|
||||
horizontalScrollbarHeight: 0,
|
||||
scrollbarArrowSize: 0,
|
||||
verticalScrollbarHasArrows: false,
|
||||
minimap: false,
|
||||
minimapRenderCharacters: true,
|
||||
minimapMaxColumn: 150,
|
||||
pixelRatio: 1,
|
||||
}, {
|
||||
width: 900,
|
||||
height: 900,
|
||||
|
||||
glyphMarginLeft: 0,
|
||||
glyphMarginWidth: 0,
|
||||
glyphMarginHeight: 900,
|
||||
|
||||
lineNumbersLeft: 0,
|
||||
lineNumbersWidth: 50,
|
||||
lineNumbersHeight: 900,
|
||||
|
||||
decorationsLeft: 50,
|
||||
decorationsWidth: 10,
|
||||
decorationsHeight: 900,
|
||||
|
||||
contentLeft: 60,
|
||||
contentWidth: 840,
|
||||
contentHeight: 900,
|
||||
|
||||
renderMinimap: RenderMinimap.None,
|
||||
minimapWidth: 0,
|
||||
viewportColumn: 84,
|
||||
|
||||
verticalScrollbarWidth: 0,
|
||||
horizontalScrollbarHeight: 0,
|
||||
|
||||
overviewRuler: {
|
||||
top: 0,
|
||||
width: 0,
|
||||
height: 900,
|
||||
right: 0
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test('EditorLayoutProvider 7', () => {
|
||||
doTest({
|
||||
outerWidth: 900,
|
||||
outerHeight: 900,
|
||||
showGlyphMargin: false,
|
||||
lineHeight: 16,
|
||||
showLineNumbers: true,
|
||||
lineNumbersMinChars: 5,
|
||||
lineNumbersDigitCount: 6,
|
||||
lineDecorationsWidth: 10,
|
||||
typicalHalfwidthCharacterWidth: 10,
|
||||
maxDigitWidth: 10,
|
||||
verticalScrollbarWidth: 0,
|
||||
horizontalScrollbarHeight: 0,
|
||||
scrollbarArrowSize: 0,
|
||||
verticalScrollbarHasArrows: false,
|
||||
minimap: false,
|
||||
minimapRenderCharacters: true,
|
||||
minimapMaxColumn: 150,
|
||||
pixelRatio: 1,
|
||||
}, {
|
||||
width: 900,
|
||||
height: 900,
|
||||
|
||||
glyphMarginLeft: 0,
|
||||
glyphMarginWidth: 0,
|
||||
glyphMarginHeight: 900,
|
||||
|
||||
lineNumbersLeft: 0,
|
||||
lineNumbersWidth: 60,
|
||||
lineNumbersHeight: 900,
|
||||
|
||||
decorationsLeft: 60,
|
||||
decorationsWidth: 10,
|
||||
decorationsHeight: 900,
|
||||
|
||||
contentLeft: 70,
|
||||
contentWidth: 830,
|
||||
contentHeight: 900,
|
||||
|
||||
renderMinimap: RenderMinimap.None,
|
||||
minimapWidth: 0,
|
||||
viewportColumn: 83,
|
||||
|
||||
verticalScrollbarWidth: 0,
|
||||
horizontalScrollbarHeight: 0,
|
||||
|
||||
overviewRuler: {
|
||||
top: 0,
|
||||
width: 0,
|
||||
height: 900,
|
||||
right: 0
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test('EditorLayoutProvider 8', () => {
|
||||
doTest({
|
||||
outerWidth: 900,
|
||||
outerHeight: 900,
|
||||
showGlyphMargin: false,
|
||||
lineHeight: 16,
|
||||
showLineNumbers: true,
|
||||
lineNumbersMinChars: 5,
|
||||
lineNumbersDigitCount: 6,
|
||||
lineDecorationsWidth: 10,
|
||||
typicalHalfwidthCharacterWidth: 5,
|
||||
maxDigitWidth: 5,
|
||||
verticalScrollbarWidth: 0,
|
||||
horizontalScrollbarHeight: 0,
|
||||
scrollbarArrowSize: 0,
|
||||
verticalScrollbarHasArrows: false,
|
||||
minimap: false,
|
||||
minimapRenderCharacters: true,
|
||||
minimapMaxColumn: 150,
|
||||
pixelRatio: 1,
|
||||
}, {
|
||||
width: 900,
|
||||
height: 900,
|
||||
|
||||
glyphMarginLeft: 0,
|
||||
glyphMarginWidth: 0,
|
||||
glyphMarginHeight: 900,
|
||||
|
||||
lineNumbersLeft: 0,
|
||||
lineNumbersWidth: 30,
|
||||
lineNumbersHeight: 900,
|
||||
|
||||
decorationsLeft: 30,
|
||||
decorationsWidth: 10,
|
||||
decorationsHeight: 900,
|
||||
|
||||
contentLeft: 40,
|
||||
contentWidth: 860,
|
||||
contentHeight: 900,
|
||||
|
||||
renderMinimap: RenderMinimap.None,
|
||||
minimapWidth: 0,
|
||||
viewportColumn: 172,
|
||||
|
||||
verticalScrollbarWidth: 0,
|
||||
horizontalScrollbarHeight: 0,
|
||||
|
||||
overviewRuler: {
|
||||
top: 0,
|
||||
width: 0,
|
||||
height: 900,
|
||||
right: 0
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test('EditorLayoutProvider 8 - rounds floats', () => {
|
||||
doTest({
|
||||
outerWidth: 900,
|
||||
outerHeight: 900,
|
||||
showGlyphMargin: false,
|
||||
lineHeight: 16,
|
||||
showLineNumbers: true,
|
||||
lineNumbersMinChars: 5,
|
||||
lineNumbersDigitCount: 6,
|
||||
lineDecorationsWidth: 10,
|
||||
typicalHalfwidthCharacterWidth: 5.05,
|
||||
maxDigitWidth: 5.05,
|
||||
verticalScrollbarWidth: 0,
|
||||
horizontalScrollbarHeight: 0,
|
||||
scrollbarArrowSize: 0,
|
||||
verticalScrollbarHasArrows: false,
|
||||
minimap: false,
|
||||
minimapRenderCharacters: true,
|
||||
minimapMaxColumn: 150,
|
||||
pixelRatio: 1,
|
||||
}, {
|
||||
width: 900,
|
||||
height: 900,
|
||||
|
||||
glyphMarginLeft: 0,
|
||||
glyphMarginWidth: 0,
|
||||
glyphMarginHeight: 900,
|
||||
|
||||
lineNumbersLeft: 0,
|
||||
lineNumbersWidth: 30,
|
||||
lineNumbersHeight: 900,
|
||||
|
||||
decorationsLeft: 30,
|
||||
decorationsWidth: 10,
|
||||
decorationsHeight: 900,
|
||||
|
||||
contentLeft: 40,
|
||||
contentWidth: 860,
|
||||
contentHeight: 900,
|
||||
|
||||
renderMinimap: RenderMinimap.None,
|
||||
minimapWidth: 0,
|
||||
viewportColumn: 170,
|
||||
|
||||
verticalScrollbarWidth: 0,
|
||||
horizontalScrollbarHeight: 0,
|
||||
|
||||
overviewRuler: {
|
||||
top: 0,
|
||||
width: 0,
|
||||
height: 900,
|
||||
right: 0
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test('EditorLayoutProvider 9 - render minimap', () => {
|
||||
doTest({
|
||||
outerWidth: 1000,
|
||||
outerHeight: 800,
|
||||
showGlyphMargin: false,
|
||||
lineHeight: 16,
|
||||
showLineNumbers: false,
|
||||
lineNumbersMinChars: 0,
|
||||
lineNumbersDigitCount: 1,
|
||||
lineDecorationsWidth: 10,
|
||||
typicalHalfwidthCharacterWidth: 10,
|
||||
maxDigitWidth: 10,
|
||||
verticalScrollbarWidth: 0,
|
||||
horizontalScrollbarHeight: 0,
|
||||
scrollbarArrowSize: 0,
|
||||
verticalScrollbarHasArrows: false,
|
||||
minimap: true,
|
||||
minimapRenderCharacters: true,
|
||||
minimapMaxColumn: 150,
|
||||
pixelRatio: 1,
|
||||
}, {
|
||||
width: 1000,
|
||||
height: 800,
|
||||
|
||||
glyphMarginLeft: 0,
|
||||
glyphMarginWidth: 0,
|
||||
glyphMarginHeight: 800,
|
||||
|
||||
lineNumbersLeft: 0,
|
||||
lineNumbersWidth: 0,
|
||||
lineNumbersHeight: 800,
|
||||
|
||||
decorationsLeft: 0,
|
||||
decorationsWidth: 10,
|
||||
decorationsHeight: 800,
|
||||
|
||||
contentLeft: 10,
|
||||
contentWidth: 900,
|
||||
contentHeight: 800,
|
||||
|
||||
renderMinimap: RenderMinimap.Small,
|
||||
minimapWidth: 90,
|
||||
viewportColumn: 90,
|
||||
|
||||
verticalScrollbarWidth: 0,
|
||||
horizontalScrollbarHeight: 0,
|
||||
|
||||
overviewRuler: {
|
||||
top: 0,
|
||||
width: 0,
|
||||
height: 800,
|
||||
right: 0
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test('EditorLayoutProvider 9 - render minimap with pixelRatio = 2', () => {
|
||||
doTest({
|
||||
outerWidth: 1000,
|
||||
outerHeight: 800,
|
||||
showGlyphMargin: false,
|
||||
lineHeight: 16,
|
||||
showLineNumbers: false,
|
||||
lineNumbersMinChars: 0,
|
||||
lineNumbersDigitCount: 1,
|
||||
lineDecorationsWidth: 10,
|
||||
typicalHalfwidthCharacterWidth: 10,
|
||||
maxDigitWidth: 10,
|
||||
verticalScrollbarWidth: 0,
|
||||
horizontalScrollbarHeight: 0,
|
||||
scrollbarArrowSize: 0,
|
||||
verticalScrollbarHasArrows: false,
|
||||
minimap: true,
|
||||
minimapRenderCharacters: true,
|
||||
minimapMaxColumn: 150,
|
||||
pixelRatio: 2,
|
||||
}, {
|
||||
width: 1000,
|
||||
height: 800,
|
||||
|
||||
glyphMarginLeft: 0,
|
||||
glyphMarginWidth: 0,
|
||||
glyphMarginHeight: 800,
|
||||
|
||||
lineNumbersLeft: 0,
|
||||
lineNumbersWidth: 0,
|
||||
lineNumbersHeight: 800,
|
||||
|
||||
decorationsLeft: 0,
|
||||
decorationsWidth: 10,
|
||||
decorationsHeight: 800,
|
||||
|
||||
contentLeft: 10,
|
||||
contentWidth: 900,
|
||||
contentHeight: 800,
|
||||
|
||||
renderMinimap: RenderMinimap.Large,
|
||||
minimapWidth: 90,
|
||||
viewportColumn: 90,
|
||||
|
||||
verticalScrollbarWidth: 0,
|
||||
horizontalScrollbarHeight: 0,
|
||||
|
||||
overviewRuler: {
|
||||
top: 0,
|
||||
width: 0,
|
||||
height: 800,
|
||||
right: 0
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test('EditorLayoutProvider 9 - render minimap with pixelRatio = 4', () => {
|
||||
doTest({
|
||||
outerWidth: 1000,
|
||||
outerHeight: 800,
|
||||
showGlyphMargin: false,
|
||||
lineHeight: 16,
|
||||
showLineNumbers: false,
|
||||
lineNumbersMinChars: 0,
|
||||
lineNumbersDigitCount: 1,
|
||||
lineDecorationsWidth: 10,
|
||||
typicalHalfwidthCharacterWidth: 10,
|
||||
maxDigitWidth: 10,
|
||||
verticalScrollbarWidth: 0,
|
||||
horizontalScrollbarHeight: 0,
|
||||
scrollbarArrowSize: 0,
|
||||
verticalScrollbarHasArrows: false,
|
||||
minimap: true,
|
||||
minimapRenderCharacters: true,
|
||||
minimapMaxColumn: 150,
|
||||
pixelRatio: 4,
|
||||
}, {
|
||||
width: 1000,
|
||||
height: 800,
|
||||
|
||||
glyphMarginLeft: 0,
|
||||
glyphMarginWidth: 0,
|
||||
glyphMarginHeight: 800,
|
||||
|
||||
lineNumbersLeft: 0,
|
||||
lineNumbersWidth: 0,
|
||||
lineNumbersHeight: 800,
|
||||
|
||||
decorationsLeft: 0,
|
||||
decorationsWidth: 10,
|
||||
decorationsHeight: 800,
|
||||
|
||||
contentLeft: 10,
|
||||
contentWidth: 943,
|
||||
contentHeight: 800,
|
||||
|
||||
renderMinimap: RenderMinimap.Large,
|
||||
minimapWidth: 47,
|
||||
viewportColumn: 94,
|
||||
|
||||
verticalScrollbarWidth: 0,
|
||||
horizontalScrollbarHeight: 0,
|
||||
|
||||
overviewRuler: {
|
||||
top: 0,
|
||||
width: 0,
|
||||
height: 800,
|
||||
right: 0
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
124
src/vs/editor/test/common/viewLayout/lineDecorations.test.ts
Normal file
124
src/vs/editor/test/common/viewLayout/lineDecorations.test.ts
Normal file
@@ -0,0 +1,124 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { DecorationSegment, LineDecorationsNormalizer, LineDecoration } from 'vs/editor/common/viewLayout/lineDecorations';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { InlineDecoration } from 'vs/editor/common/viewModel/viewModel';
|
||||
|
||||
suite('Editor ViewLayout - ViewLineParts', () => {
|
||||
|
||||
function newDecoration(startLineNumber: number, startColumn: number, endLineNumber: number, endColumn: number, inlineClassName: string): InlineDecoration {
|
||||
return new InlineDecoration(new Range(startLineNumber, startColumn, endLineNumber, endColumn), inlineClassName, false);
|
||||
}
|
||||
|
||||
test('Bug 9827:Overlapping inline decorations can cause wrong inline class to be applied', () => {
|
||||
|
||||
var result = LineDecorationsNormalizer.normalize([
|
||||
new LineDecoration(1, 11, 'c1', false),
|
||||
new LineDecoration(3, 4, 'c2', false)
|
||||
]);
|
||||
|
||||
assert.deepEqual(result, [
|
||||
new DecorationSegment(0, 1, 'c1'),
|
||||
new DecorationSegment(2, 2, 'c2 c1'),
|
||||
new DecorationSegment(3, 9, 'c1'),
|
||||
]);
|
||||
});
|
||||
|
||||
test('issue #3462: no whitespace shown at the end of a decorated line', () => {
|
||||
|
||||
var result = LineDecorationsNormalizer.normalize([
|
||||
new LineDecoration(15, 21, 'vs-whitespace', false),
|
||||
new LineDecoration(20, 21, 'inline-folded', false),
|
||||
]);
|
||||
|
||||
assert.deepEqual(result, [
|
||||
new DecorationSegment(14, 18, 'vs-whitespace'),
|
||||
new DecorationSegment(19, 19, 'vs-whitespace inline-folded')
|
||||
]);
|
||||
});
|
||||
|
||||
test('issue #3661: Link decoration bleeds to next line when wrapping', () => {
|
||||
|
||||
let result = LineDecoration.filter([
|
||||
newDecoration(2, 12, 3, 30, 'detected-link')
|
||||
], 3, 12, 500);
|
||||
|
||||
assert.deepEqual(result, [
|
||||
new LineDecoration(12, 30, 'detected-link', false),
|
||||
]);
|
||||
});
|
||||
|
||||
test('ViewLineParts', () => {
|
||||
|
||||
assert.deepEqual(LineDecorationsNormalizer.normalize([
|
||||
new LineDecoration(1, 2, 'c1', false),
|
||||
new LineDecoration(3, 4, 'c2', false)
|
||||
]), [
|
||||
new DecorationSegment(0, 0, 'c1'),
|
||||
new DecorationSegment(2, 2, 'c2')
|
||||
]);
|
||||
|
||||
assert.deepEqual(LineDecorationsNormalizer.normalize([
|
||||
new LineDecoration(1, 3, 'c1', false),
|
||||
new LineDecoration(3, 4, 'c2', false)
|
||||
]), [
|
||||
new DecorationSegment(0, 1, 'c1'),
|
||||
new DecorationSegment(2, 2, 'c2')
|
||||
]);
|
||||
|
||||
assert.deepEqual(LineDecorationsNormalizer.normalize([
|
||||
new LineDecoration(1, 4, 'c1', false),
|
||||
new LineDecoration(3, 4, 'c2', false)
|
||||
]), [
|
||||
new DecorationSegment(0, 1, 'c1'),
|
||||
new DecorationSegment(2, 2, 'c1 c2')
|
||||
]);
|
||||
|
||||
assert.deepEqual(LineDecorationsNormalizer.normalize([
|
||||
new LineDecoration(1, 4, 'c1', false),
|
||||
new LineDecoration(1, 4, 'c1*', false),
|
||||
new LineDecoration(3, 4, 'c2', false)
|
||||
]), [
|
||||
new DecorationSegment(0, 1, 'c1 c1*'),
|
||||
new DecorationSegment(2, 2, 'c1 c1* c2')
|
||||
]);
|
||||
|
||||
assert.deepEqual(LineDecorationsNormalizer.normalize([
|
||||
new LineDecoration(1, 4, 'c1', false),
|
||||
new LineDecoration(1, 4, 'c1*', false),
|
||||
new LineDecoration(1, 4, 'c1**', false),
|
||||
new LineDecoration(3, 4, 'c2', false)
|
||||
]), [
|
||||
new DecorationSegment(0, 1, 'c1 c1* c1**'),
|
||||
new DecorationSegment(2, 2, 'c1 c1* c1** c2')
|
||||
]);
|
||||
|
||||
assert.deepEqual(LineDecorationsNormalizer.normalize([
|
||||
new LineDecoration(1, 4, 'c1', false),
|
||||
new LineDecoration(1, 4, 'c1*', false),
|
||||
new LineDecoration(1, 4, 'c1**', false),
|
||||
new LineDecoration(3, 4, 'c2', false),
|
||||
new LineDecoration(3, 4, 'c2*', false)
|
||||
]), [
|
||||
new DecorationSegment(0, 1, 'c1 c1* c1**'),
|
||||
new DecorationSegment(2, 2, 'c1 c1* c1** c2 c2*')
|
||||
]);
|
||||
|
||||
assert.deepEqual(LineDecorationsNormalizer.normalize([
|
||||
new LineDecoration(1, 4, 'c1', false),
|
||||
new LineDecoration(1, 4, 'c1*', false),
|
||||
new LineDecoration(1, 4, 'c1**', false),
|
||||
new LineDecoration(3, 4, 'c2', false),
|
||||
new LineDecoration(3, 5, 'c2*', false)
|
||||
]), [
|
||||
new DecorationSegment(0, 1, 'c1 c1* c1**'),
|
||||
new DecorationSegment(2, 2, 'c1 c1* c1** c2 c2*'),
|
||||
new DecorationSegment(3, 3, 'c2*')
|
||||
]);
|
||||
});
|
||||
});
|
||||
597
src/vs/editor/test/common/viewLayout/linesLayout.test.ts
Normal file
597
src/vs/editor/test/common/viewLayout/linesLayout.test.ts
Normal file
@@ -0,0 +1,597 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { LinesLayout } from 'vs/editor/common/viewLayout/linesLayout';
|
||||
|
||||
suite('Editor ViewLayout - LinesLayout', () => {
|
||||
|
||||
test('LinesLayout 1', () => {
|
||||
|
||||
// Start off with 10 lines
|
||||
var linesLayout = new LinesLayout(10, 10);
|
||||
|
||||
// lines: [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
|
||||
// whitespace: -
|
||||
assert.equal(linesLayout.getLinesTotalHeight(), 100);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(1), 0);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(2), 10);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(3), 20);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(4), 30);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(5), 40);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(6), 50);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(7), 60);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(8), 70);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(9), 80);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(10), 90);
|
||||
|
||||
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(0), 1);
|
||||
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(1), 1);
|
||||
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(5), 1);
|
||||
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(9), 1);
|
||||
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(10), 2);
|
||||
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(11), 2);
|
||||
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(15), 2);
|
||||
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(19), 2);
|
||||
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(20), 3);
|
||||
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(21), 3);
|
||||
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(29), 3);
|
||||
|
||||
// Add whitespace of height 5px after 2nd line
|
||||
linesLayout.insertWhitespace(2, 0, 5);
|
||||
// lines: [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
|
||||
// whitespace: a(2,5)
|
||||
assert.equal(linesLayout.getLinesTotalHeight(), 105);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(1), 0);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(2), 10);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(3), 25);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(4), 35);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(5), 45);
|
||||
|
||||
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(0), 1);
|
||||
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(1), 1);
|
||||
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(9), 1);
|
||||
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(10), 2);
|
||||
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(20), 3);
|
||||
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(21), 3);
|
||||
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(24), 3);
|
||||
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(25), 3);
|
||||
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(35), 4);
|
||||
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(45), 5);
|
||||
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(104), 10);
|
||||
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(105), 10);
|
||||
|
||||
// Add two more whitespaces of height 5px
|
||||
linesLayout.insertWhitespace(3, 0, 5);
|
||||
linesLayout.insertWhitespace(4, 0, 5);
|
||||
// lines: [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
|
||||
// whitespace: a(2,5), b(3, 5), c(4, 5)
|
||||
assert.equal(linesLayout.getLinesTotalHeight(), 115);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(1), 0);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(2), 10);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(3), 25);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(4), 40);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(5), 55);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(6), 65);
|
||||
|
||||
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(0), 1);
|
||||
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(1), 1);
|
||||
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(9), 1);
|
||||
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(10), 2);
|
||||
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(19), 2);
|
||||
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(20), 3);
|
||||
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(34), 3);
|
||||
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(35), 4);
|
||||
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(49), 4);
|
||||
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(50), 5);
|
||||
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(64), 5);
|
||||
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(65), 6);
|
||||
|
||||
assert.equal(linesLayout.getVerticalOffsetForWhitespaceIndex(0), 20); // 20 -> 25
|
||||
assert.equal(linesLayout.getVerticalOffsetForWhitespaceIndex(1), 35); // 35 -> 40
|
||||
assert.equal(linesLayout.getVerticalOffsetForWhitespaceIndex(2), 50);
|
||||
|
||||
assert.equal(linesLayout.getWhitespaceIndexAtOrAfterVerticallOffset(0), 0);
|
||||
assert.equal(linesLayout.getWhitespaceIndexAtOrAfterVerticallOffset(19), 0);
|
||||
assert.equal(linesLayout.getWhitespaceIndexAtOrAfterVerticallOffset(20), 0);
|
||||
assert.equal(linesLayout.getWhitespaceIndexAtOrAfterVerticallOffset(21), 0);
|
||||
assert.equal(linesLayout.getWhitespaceIndexAtOrAfterVerticallOffset(22), 0);
|
||||
assert.equal(linesLayout.getWhitespaceIndexAtOrAfterVerticallOffset(23), 0);
|
||||
assert.equal(linesLayout.getWhitespaceIndexAtOrAfterVerticallOffset(24), 0);
|
||||
assert.equal(linesLayout.getWhitespaceIndexAtOrAfterVerticallOffset(25), 1);
|
||||
assert.equal(linesLayout.getWhitespaceIndexAtOrAfterVerticallOffset(26), 1);
|
||||
assert.equal(linesLayout.getWhitespaceIndexAtOrAfterVerticallOffset(34), 1);
|
||||
assert.equal(linesLayout.getWhitespaceIndexAtOrAfterVerticallOffset(35), 1);
|
||||
assert.equal(linesLayout.getWhitespaceIndexAtOrAfterVerticallOffset(36), 1);
|
||||
assert.equal(linesLayout.getWhitespaceIndexAtOrAfterVerticallOffset(39), 1);
|
||||
assert.equal(linesLayout.getWhitespaceIndexAtOrAfterVerticallOffset(40), 2);
|
||||
assert.equal(linesLayout.getWhitespaceIndexAtOrAfterVerticallOffset(41), 2);
|
||||
assert.equal(linesLayout.getWhitespaceIndexAtOrAfterVerticallOffset(49), 2);
|
||||
assert.equal(linesLayout.getWhitespaceIndexAtOrAfterVerticallOffset(50), 2);
|
||||
assert.equal(linesLayout.getWhitespaceIndexAtOrAfterVerticallOffset(51), 2);
|
||||
assert.equal(linesLayout.getWhitespaceIndexAtOrAfterVerticallOffset(54), 2);
|
||||
assert.equal(linesLayout.getWhitespaceIndexAtOrAfterVerticallOffset(55), -1);
|
||||
assert.equal(linesLayout.getWhitespaceIndexAtOrAfterVerticallOffset(1000), -1);
|
||||
|
||||
});
|
||||
|
||||
test('LinesLayout 2', () => {
|
||||
|
||||
// Start off with 10 lines and one whitespace after line 2, of height 5
|
||||
var linesLayout = new LinesLayout(10, 1);
|
||||
var a = linesLayout.insertWhitespace(2, 0, 5);
|
||||
|
||||
// 10 lines
|
||||
// whitespace: - a(2,5)
|
||||
assert.equal(linesLayout.getLinesTotalHeight(), 15);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(1), 0);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(2), 1);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(3), 7);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(4), 8);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(5), 9);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(6), 10);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(7), 11);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(8), 12);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(9), 13);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(10), 14);
|
||||
|
||||
// Change whitespace height
|
||||
// 10 lines
|
||||
// whitespace: - a(2,10)
|
||||
linesLayout.changeWhitespace(a, 2, 10);
|
||||
assert.equal(linesLayout.getLinesTotalHeight(), 20);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(1), 0);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(2), 1);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(3), 12);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(4), 13);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(5), 14);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(6), 15);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(7), 16);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(8), 17);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(9), 18);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(10), 19);
|
||||
|
||||
// Change whitespace position
|
||||
// 10 lines
|
||||
// whitespace: - a(5,10)
|
||||
linesLayout.changeWhitespace(a, 5, 10);
|
||||
assert.equal(linesLayout.getLinesTotalHeight(), 20);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(1), 0);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(2), 1);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(3), 2);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(4), 3);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(5), 4);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(6), 15);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(7), 16);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(8), 17);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(9), 18);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(10), 19);
|
||||
|
||||
// Pretend that lines 5 and 6 were deleted
|
||||
// 8 lines
|
||||
// whitespace: - a(4,10)
|
||||
linesLayout.onLinesDeleted(5, 6);
|
||||
assert.equal(linesLayout.getLinesTotalHeight(), 18);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(1), 0);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(2), 1);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(3), 2);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(4), 3);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(5), 14);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(6), 15);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(7), 16);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(8), 17);
|
||||
|
||||
// Insert two lines at the beginning
|
||||
// 10 lines
|
||||
// whitespace: - a(6,10)
|
||||
linesLayout.onLinesInserted(1, 2);
|
||||
assert.equal(linesLayout.getLinesTotalHeight(), 20);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(1), 0);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(2), 1);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(3), 2);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(4), 3);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(5), 4);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(6), 5);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(7), 16);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(8), 17);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(9), 18);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(10), 19);
|
||||
|
||||
// Remove whitespace
|
||||
// 10 lines
|
||||
linesLayout.removeWhitespace(a);
|
||||
assert.equal(linesLayout.getLinesTotalHeight(), 10);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(1), 0);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(2), 1);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(3), 2);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(4), 3);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(5), 4);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(6), 5);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(7), 6);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(8), 7);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(9), 8);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(10), 9);
|
||||
});
|
||||
|
||||
test('LinesLayout getLineNumberAtOrAfterVerticalOffset', () => {
|
||||
var linesLayout = new LinesLayout(10, 1);
|
||||
linesLayout.insertWhitespace(6, 0, 10);
|
||||
|
||||
// 10 lines
|
||||
// whitespace: - a(6,10)
|
||||
assert.equal(linesLayout.getLinesTotalHeight(), 20);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(1), 0);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(2), 1);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(3), 2);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(4), 3);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(5), 4);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(6), 5);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(7), 16);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(8), 17);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(9), 18);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(10), 19);
|
||||
|
||||
// Do some hit testing
|
||||
// line [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
||||
// vertical: [0, 1, 2, 3, 4, 5, 16, 17, 18, 19]
|
||||
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(-100), 1);
|
||||
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(-1), 1);
|
||||
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(0), 1);
|
||||
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(1), 2);
|
||||
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(2), 3);
|
||||
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(3), 4);
|
||||
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(4), 5);
|
||||
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(5), 6);
|
||||
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(6), 7);
|
||||
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(7), 7);
|
||||
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(8), 7);
|
||||
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(9), 7);
|
||||
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(10), 7);
|
||||
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(11), 7);
|
||||
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(12), 7);
|
||||
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(13), 7);
|
||||
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(14), 7);
|
||||
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(15), 7);
|
||||
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(16), 7);
|
||||
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(17), 8);
|
||||
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(18), 9);
|
||||
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(19), 10);
|
||||
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(20), 10);
|
||||
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(21), 10);
|
||||
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(22), 10);
|
||||
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(23), 10);
|
||||
});
|
||||
|
||||
test('LinesLayout getCenteredLineInViewport', () => {
|
||||
var linesLayout = new LinesLayout(10, 1);
|
||||
linesLayout.insertWhitespace(6, 0, 10);
|
||||
|
||||
// 10 lines
|
||||
// whitespace: - a(6,10)
|
||||
assert.equal(linesLayout.getLinesTotalHeight(), 20);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(1), 0);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(2), 1);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(3), 2);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(4), 3);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(5), 4);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(6), 5);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(7), 16);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(8), 17);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(9), 18);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(10), 19);
|
||||
|
||||
// Find centered line in viewport 1
|
||||
// line [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
||||
// vertical: [0, 1, 2, 3, 4, 5, 16, 17, 18, 19]
|
||||
assert.equal(linesLayout.getLinesViewportData(0, 1).centeredLineNumber, 1);
|
||||
assert.equal(linesLayout.getLinesViewportData(0, 2).centeredLineNumber, 2);
|
||||
assert.equal(linesLayout.getLinesViewportData(0, 3).centeredLineNumber, 2);
|
||||
assert.equal(linesLayout.getLinesViewportData(0, 4).centeredLineNumber, 3);
|
||||
assert.equal(linesLayout.getLinesViewportData(0, 5).centeredLineNumber, 3);
|
||||
assert.equal(linesLayout.getLinesViewportData(0, 6).centeredLineNumber, 4);
|
||||
assert.equal(linesLayout.getLinesViewportData(0, 7).centeredLineNumber, 4);
|
||||
assert.equal(linesLayout.getLinesViewportData(0, 8).centeredLineNumber, 5);
|
||||
assert.equal(linesLayout.getLinesViewportData(0, 9).centeredLineNumber, 5);
|
||||
assert.equal(linesLayout.getLinesViewportData(0, 10).centeredLineNumber, 6);
|
||||
assert.equal(linesLayout.getLinesViewportData(0, 11).centeredLineNumber, 6);
|
||||
assert.equal(linesLayout.getLinesViewportData(0, 12).centeredLineNumber, 6);
|
||||
assert.equal(linesLayout.getLinesViewportData(0, 13).centeredLineNumber, 6);
|
||||
assert.equal(linesLayout.getLinesViewportData(0, 14).centeredLineNumber, 6);
|
||||
assert.equal(linesLayout.getLinesViewportData(0, 15).centeredLineNumber, 6);
|
||||
assert.equal(linesLayout.getLinesViewportData(0, 16).centeredLineNumber, 6);
|
||||
assert.equal(linesLayout.getLinesViewportData(0, 17).centeredLineNumber, 7);
|
||||
assert.equal(linesLayout.getLinesViewportData(0, 18).centeredLineNumber, 7);
|
||||
assert.equal(linesLayout.getLinesViewportData(0, 19).centeredLineNumber, 7);
|
||||
assert.equal(linesLayout.getLinesViewportData(0, 20).centeredLineNumber, 7);
|
||||
assert.equal(linesLayout.getLinesViewportData(0, 21).centeredLineNumber, 7);
|
||||
assert.equal(linesLayout.getLinesViewportData(0, 22).centeredLineNumber, 7);
|
||||
assert.equal(linesLayout.getLinesViewportData(0, 23).centeredLineNumber, 7);
|
||||
assert.equal(linesLayout.getLinesViewportData(0, 24).centeredLineNumber, 7);
|
||||
assert.equal(linesLayout.getLinesViewportData(0, 25).centeredLineNumber, 7);
|
||||
assert.equal(linesLayout.getLinesViewportData(0, 26).centeredLineNumber, 7);
|
||||
assert.equal(linesLayout.getLinesViewportData(0, 27).centeredLineNumber, 7);
|
||||
assert.equal(linesLayout.getLinesViewportData(0, 28).centeredLineNumber, 7);
|
||||
assert.equal(linesLayout.getLinesViewportData(0, 29).centeredLineNumber, 7);
|
||||
assert.equal(linesLayout.getLinesViewportData(0, 30).centeredLineNumber, 7);
|
||||
assert.equal(linesLayout.getLinesViewportData(0, 31).centeredLineNumber, 7);
|
||||
assert.equal(linesLayout.getLinesViewportData(0, 32).centeredLineNumber, 7);
|
||||
assert.equal(linesLayout.getLinesViewportData(0, 33).centeredLineNumber, 7);
|
||||
|
||||
// Find centered line in viewport 2
|
||||
// line [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
||||
// vertical: [0, 1, 2, 3, 4, 5, 16, 17, 18, 19]
|
||||
assert.equal(linesLayout.getLinesViewportData(0, 20).centeredLineNumber, 7);
|
||||
assert.equal(linesLayout.getLinesViewportData(1, 20).centeredLineNumber, 7);
|
||||
assert.equal(linesLayout.getLinesViewportData(2, 20).centeredLineNumber, 7);
|
||||
assert.equal(linesLayout.getLinesViewportData(3, 20).centeredLineNumber, 7);
|
||||
assert.equal(linesLayout.getLinesViewportData(4, 20).centeredLineNumber, 7);
|
||||
assert.equal(linesLayout.getLinesViewportData(5, 20).centeredLineNumber, 7);
|
||||
assert.equal(linesLayout.getLinesViewportData(6, 20).centeredLineNumber, 7);
|
||||
assert.equal(linesLayout.getLinesViewportData(7, 20).centeredLineNumber, 7);
|
||||
assert.equal(linesLayout.getLinesViewportData(8, 20).centeredLineNumber, 7);
|
||||
assert.equal(linesLayout.getLinesViewportData(9, 20).centeredLineNumber, 7);
|
||||
assert.equal(linesLayout.getLinesViewportData(10, 20).centeredLineNumber, 7);
|
||||
assert.equal(linesLayout.getLinesViewportData(11, 20).centeredLineNumber, 7);
|
||||
assert.equal(linesLayout.getLinesViewportData(12, 20).centeredLineNumber, 7);
|
||||
assert.equal(linesLayout.getLinesViewportData(13, 20).centeredLineNumber, 7);
|
||||
assert.equal(linesLayout.getLinesViewportData(14, 20).centeredLineNumber, 8);
|
||||
assert.equal(linesLayout.getLinesViewportData(15, 20).centeredLineNumber, 8);
|
||||
assert.equal(linesLayout.getLinesViewportData(16, 20).centeredLineNumber, 9);
|
||||
assert.equal(linesLayout.getLinesViewportData(17, 20).centeredLineNumber, 9);
|
||||
assert.equal(linesLayout.getLinesViewportData(18, 20).centeredLineNumber, 10);
|
||||
assert.equal(linesLayout.getLinesViewportData(19, 20).centeredLineNumber, 10);
|
||||
assert.equal(linesLayout.getLinesViewportData(20, 23).centeredLineNumber, 10);
|
||||
assert.equal(linesLayout.getLinesViewportData(21, 23).centeredLineNumber, 10);
|
||||
assert.equal(linesLayout.getLinesViewportData(22, 23).centeredLineNumber, 10);
|
||||
});
|
||||
|
||||
test('LinesLayout getLinesViewportData 1', () => {
|
||||
var linesLayout = new LinesLayout(10, 10);
|
||||
linesLayout.insertWhitespace(6, 0, 100);
|
||||
|
||||
// 10 lines
|
||||
// whitespace: - a(6,100)
|
||||
assert.equal(linesLayout.getLinesTotalHeight(), 200);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(1), 0);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(2), 10);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(3), 20);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(4), 30);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(5), 40);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(6), 50);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(7), 160);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(8), 170);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(9), 180);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(10), 190);
|
||||
|
||||
// viewport 0->50
|
||||
var viewportData = linesLayout.getLinesViewportData(0, 50);
|
||||
assert.equal(viewportData.startLineNumber, 1);
|
||||
assert.equal(viewportData.endLineNumber, 5);
|
||||
assert.equal(viewportData.completelyVisibleStartLineNumber, 1);
|
||||
assert.equal(viewportData.completelyVisibleEndLineNumber, 5);
|
||||
assert.deepEqual(viewportData.relativeVerticalOffset, [0, 10, 20, 30, 40]);
|
||||
|
||||
// viewport 1->51
|
||||
viewportData = linesLayout.getLinesViewportData(1, 51);
|
||||
assert.equal(viewportData.startLineNumber, 1);
|
||||
assert.equal(viewportData.endLineNumber, 6);
|
||||
assert.equal(viewportData.completelyVisibleStartLineNumber, 2);
|
||||
assert.equal(viewportData.completelyVisibleEndLineNumber, 5);
|
||||
assert.deepEqual(viewportData.relativeVerticalOffset, [0, 10, 20, 30, 40, 50]);
|
||||
|
||||
// viewport 5->55
|
||||
viewportData = linesLayout.getLinesViewportData(5, 55);
|
||||
assert.equal(viewportData.startLineNumber, 1);
|
||||
assert.equal(viewportData.endLineNumber, 6);
|
||||
assert.equal(viewportData.completelyVisibleStartLineNumber, 2);
|
||||
assert.equal(viewportData.completelyVisibleEndLineNumber, 5);
|
||||
assert.deepEqual(viewportData.relativeVerticalOffset, [0, 10, 20, 30, 40, 50]);
|
||||
|
||||
// viewport 10->60
|
||||
viewportData = linesLayout.getLinesViewportData(10, 60);
|
||||
assert.equal(viewportData.startLineNumber, 2);
|
||||
assert.equal(viewportData.endLineNumber, 6);
|
||||
assert.equal(viewportData.completelyVisibleStartLineNumber, 2);
|
||||
assert.equal(viewportData.completelyVisibleEndLineNumber, 6);
|
||||
assert.deepEqual(viewportData.relativeVerticalOffset, [10, 20, 30, 40, 50]);
|
||||
|
||||
// viewport 50->100
|
||||
viewportData = linesLayout.getLinesViewportData(50, 100);
|
||||
assert.equal(viewportData.startLineNumber, 6);
|
||||
assert.equal(viewportData.endLineNumber, 6);
|
||||
assert.equal(viewportData.completelyVisibleStartLineNumber, 6);
|
||||
assert.equal(viewportData.completelyVisibleEndLineNumber, 6);
|
||||
assert.deepEqual(viewportData.relativeVerticalOffset, [50]);
|
||||
|
||||
// viewport 60->110
|
||||
viewportData = linesLayout.getLinesViewportData(60, 110);
|
||||
assert.equal(viewportData.startLineNumber, 7);
|
||||
assert.equal(viewportData.endLineNumber, 7);
|
||||
assert.equal(viewportData.completelyVisibleStartLineNumber, 7);
|
||||
assert.equal(viewportData.completelyVisibleEndLineNumber, 7);
|
||||
assert.deepEqual(viewportData.relativeVerticalOffset, [160]);
|
||||
|
||||
// viewport 65->115
|
||||
viewportData = linesLayout.getLinesViewportData(65, 115);
|
||||
assert.equal(viewportData.startLineNumber, 7);
|
||||
assert.equal(viewportData.endLineNumber, 7);
|
||||
assert.equal(viewportData.completelyVisibleStartLineNumber, 7);
|
||||
assert.equal(viewportData.completelyVisibleEndLineNumber, 7);
|
||||
assert.deepEqual(viewportData.relativeVerticalOffset, [160]);
|
||||
|
||||
// viewport 50->159
|
||||
viewportData = linesLayout.getLinesViewportData(50, 159);
|
||||
assert.equal(viewportData.startLineNumber, 6);
|
||||
assert.equal(viewportData.endLineNumber, 6);
|
||||
assert.equal(viewportData.completelyVisibleStartLineNumber, 6);
|
||||
assert.equal(viewportData.completelyVisibleEndLineNumber, 6);
|
||||
assert.deepEqual(viewportData.relativeVerticalOffset, [50]);
|
||||
|
||||
// viewport 50->160
|
||||
viewportData = linesLayout.getLinesViewportData(50, 160);
|
||||
assert.equal(viewportData.startLineNumber, 6);
|
||||
assert.equal(viewportData.endLineNumber, 6);
|
||||
assert.equal(viewportData.completelyVisibleStartLineNumber, 6);
|
||||
assert.equal(viewportData.completelyVisibleEndLineNumber, 6);
|
||||
assert.deepEqual(viewportData.relativeVerticalOffset, [50]);
|
||||
|
||||
// viewport 51->161
|
||||
viewportData = linesLayout.getLinesViewportData(51, 161);
|
||||
assert.equal(viewportData.startLineNumber, 6);
|
||||
assert.equal(viewportData.endLineNumber, 7);
|
||||
assert.equal(viewportData.completelyVisibleStartLineNumber, 7);
|
||||
assert.equal(viewportData.completelyVisibleEndLineNumber, 7);
|
||||
assert.deepEqual(viewportData.relativeVerticalOffset, [50, 160]);
|
||||
|
||||
|
||||
// viewport 150->169
|
||||
viewportData = linesLayout.getLinesViewportData(150, 169);
|
||||
assert.equal(viewportData.startLineNumber, 7);
|
||||
assert.equal(viewportData.endLineNumber, 7);
|
||||
assert.equal(viewportData.completelyVisibleStartLineNumber, 7);
|
||||
assert.equal(viewportData.completelyVisibleEndLineNumber, 7);
|
||||
assert.deepEqual(viewportData.relativeVerticalOffset, [160]);
|
||||
|
||||
// viewport 159->169
|
||||
viewportData = linesLayout.getLinesViewportData(159, 169);
|
||||
assert.equal(viewportData.startLineNumber, 7);
|
||||
assert.equal(viewportData.endLineNumber, 7);
|
||||
assert.equal(viewportData.completelyVisibleStartLineNumber, 7);
|
||||
assert.equal(viewportData.completelyVisibleEndLineNumber, 7);
|
||||
assert.deepEqual(viewportData.relativeVerticalOffset, [160]);
|
||||
|
||||
// viewport 160->169
|
||||
viewportData = linesLayout.getLinesViewportData(160, 169);
|
||||
assert.equal(viewportData.startLineNumber, 7);
|
||||
assert.equal(viewportData.endLineNumber, 7);
|
||||
assert.equal(viewportData.completelyVisibleStartLineNumber, 7);
|
||||
assert.equal(viewportData.completelyVisibleEndLineNumber, 7);
|
||||
assert.deepEqual(viewportData.relativeVerticalOffset, [160]);
|
||||
|
||||
|
||||
// viewport 160->1000
|
||||
viewportData = linesLayout.getLinesViewportData(160, 1000);
|
||||
assert.equal(viewportData.startLineNumber, 7);
|
||||
assert.equal(viewportData.endLineNumber, 10);
|
||||
assert.equal(viewportData.completelyVisibleStartLineNumber, 7);
|
||||
assert.equal(viewportData.completelyVisibleEndLineNumber, 10);
|
||||
assert.deepEqual(viewportData.relativeVerticalOffset, [160, 170, 180, 190]);
|
||||
});
|
||||
|
||||
|
||||
test('LinesLayout getLinesViewportData 2 & getWhitespaceViewportData', () => {
|
||||
var linesLayout = new LinesLayout(10, 10);
|
||||
var a = linesLayout.insertWhitespace(6, 0, 100);
|
||||
var b = linesLayout.insertWhitespace(7, 0, 50);
|
||||
|
||||
// 10 lines
|
||||
// whitespace: - a(6,100), b(7, 50)
|
||||
assert.equal(linesLayout.getLinesTotalHeight(), 250);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(1), 0);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(2), 10);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(3), 20);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(4), 30);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(5), 40);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(6), 50);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(7), 160);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(8), 220);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(9), 230);
|
||||
assert.equal(linesLayout.getVerticalOffsetForLineNumber(10), 240);
|
||||
|
||||
// viewport 50->160
|
||||
var viewportData = linesLayout.getLinesViewportData(50, 160);
|
||||
assert.equal(viewportData.startLineNumber, 6);
|
||||
assert.equal(viewportData.endLineNumber, 6);
|
||||
assert.equal(viewportData.completelyVisibleStartLineNumber, 6);
|
||||
assert.equal(viewportData.completelyVisibleEndLineNumber, 6);
|
||||
assert.deepEqual(viewportData.relativeVerticalOffset, [50]);
|
||||
var whitespaceData = linesLayout.getWhitespaceViewportData(50, 160);
|
||||
assert.deepEqual(whitespaceData, [{
|
||||
id: a,
|
||||
afterLineNumber: 6,
|
||||
verticalOffset: 60,
|
||||
height: 100
|
||||
}]);
|
||||
|
||||
// viewport 50->219
|
||||
viewportData = linesLayout.getLinesViewportData(50, 219);
|
||||
assert.equal(viewportData.startLineNumber, 6);
|
||||
assert.equal(viewportData.endLineNumber, 7);
|
||||
assert.equal(viewportData.completelyVisibleStartLineNumber, 6);
|
||||
assert.equal(viewportData.completelyVisibleEndLineNumber, 7);
|
||||
assert.deepEqual(viewportData.relativeVerticalOffset, [50, 160]);
|
||||
whitespaceData = linesLayout.getWhitespaceViewportData(50, 219);
|
||||
assert.deepEqual(whitespaceData, [{
|
||||
id: a,
|
||||
afterLineNumber: 6,
|
||||
verticalOffset: 60,
|
||||
height: 100
|
||||
}, {
|
||||
id: b,
|
||||
afterLineNumber: 7,
|
||||
verticalOffset: 170,
|
||||
height: 50
|
||||
}]);
|
||||
|
||||
// viewport 50->220
|
||||
viewportData = linesLayout.getLinesViewportData(50, 220);
|
||||
assert.equal(viewportData.startLineNumber, 6);
|
||||
assert.equal(viewportData.endLineNumber, 7);
|
||||
assert.equal(viewportData.completelyVisibleStartLineNumber, 6);
|
||||
assert.equal(viewportData.completelyVisibleEndLineNumber, 7);
|
||||
assert.deepEqual(viewportData.relativeVerticalOffset, [50, 160]);
|
||||
|
||||
// viewport 50->250
|
||||
viewportData = linesLayout.getLinesViewportData(50, 250);
|
||||
assert.equal(viewportData.startLineNumber, 6);
|
||||
assert.equal(viewportData.endLineNumber, 10);
|
||||
assert.equal(viewportData.completelyVisibleStartLineNumber, 6);
|
||||
assert.equal(viewportData.completelyVisibleEndLineNumber, 10);
|
||||
assert.deepEqual(viewportData.relativeVerticalOffset, [50, 160, 220, 230, 240]);
|
||||
});
|
||||
|
||||
test('LinesLayout getWhitespaceAtVerticalOffset', () => {
|
||||
var linesLayout = new LinesLayout(10, 10);
|
||||
var a = linesLayout.insertWhitespace(6, 0, 100);
|
||||
var b = linesLayout.insertWhitespace(7, 0, 50);
|
||||
|
||||
var whitespace = linesLayout.getWhitespaceAtVerticalOffset(0);
|
||||
assert.equal(whitespace, null);
|
||||
|
||||
whitespace = linesLayout.getWhitespaceAtVerticalOffset(59);
|
||||
assert.equal(whitespace, null);
|
||||
|
||||
whitespace = linesLayout.getWhitespaceAtVerticalOffset(60);
|
||||
assert.equal(whitespace.id, a);
|
||||
|
||||
whitespace = linesLayout.getWhitespaceAtVerticalOffset(61);
|
||||
assert.equal(whitespace.id, a);
|
||||
|
||||
whitespace = linesLayout.getWhitespaceAtVerticalOffset(159);
|
||||
assert.equal(whitespace.id, a);
|
||||
|
||||
whitespace = linesLayout.getWhitespaceAtVerticalOffset(160);
|
||||
assert.equal(whitespace, null);
|
||||
|
||||
whitespace = linesLayout.getWhitespaceAtVerticalOffset(161);
|
||||
assert.equal(whitespace, null);
|
||||
|
||||
whitespace = linesLayout.getWhitespaceAtVerticalOffset(169);
|
||||
assert.equal(whitespace, null);
|
||||
|
||||
whitespace = linesLayout.getWhitespaceAtVerticalOffset(170);
|
||||
assert.equal(whitespace.id, b);
|
||||
|
||||
whitespace = linesLayout.getWhitespaceAtVerticalOffset(171);
|
||||
assert.equal(whitespace.id, b);
|
||||
|
||||
whitespace = linesLayout.getWhitespaceAtVerticalOffset(219);
|
||||
assert.equal(whitespace.id, b);
|
||||
|
||||
whitespace = linesLayout.getWhitespaceAtVerticalOffset(220);
|
||||
assert.equal(whitespace, null);
|
||||
});
|
||||
});
|
||||
1234
src/vs/editor/test/common/viewLayout/viewLineRenderer.test.ts
Normal file
1234
src/vs/editor/test/common/viewLayout/viewLineRenderer.test.ts
Normal file
File diff suppressed because it is too large
Load Diff
560
src/vs/editor/test/common/viewLayout/whitespaceComputer.test.ts
Normal file
560
src/vs/editor/test/common/viewLayout/whitespaceComputer.test.ts
Normal file
@@ -0,0 +1,560 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { WhitespaceComputer } from 'vs/editor/common/viewLayout/whitespaceComputer';
|
||||
|
||||
suite('Editor ViewLayout - WhitespaceComputer', () => {
|
||||
|
||||
test('WhitespaceComputer', () => {
|
||||
|
||||
var whitespaceComputer = new WhitespaceComputer();
|
||||
|
||||
// Insert a whitespace after line number 2, of height 10
|
||||
var a = whitespaceComputer.insertWhitespace(2, 0, 10);
|
||||
// whitespaces: a(2, 10)
|
||||
assert.equal(whitespaceComputer.getCount(), 1);
|
||||
assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(0), 2);
|
||||
assert.equal(whitespaceComputer.getHeightForWhitespaceIndex(0), 10);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeight(0), 10);
|
||||
assert.equal(whitespaceComputer.getTotalHeight(), 10);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(1), 0);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(2), 0);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(3), 10);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(4), 10);
|
||||
|
||||
// Insert a whitespace again after line number 2, of height 20
|
||||
var b = whitespaceComputer.insertWhitespace(2, 0, 20);
|
||||
// whitespaces: a(2, 10), b(2, 20)
|
||||
assert.equal(whitespaceComputer.getCount(), 2);
|
||||
assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(0), 2);
|
||||
assert.equal(whitespaceComputer.getHeightForWhitespaceIndex(0), 10);
|
||||
assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(1), 2);
|
||||
assert.equal(whitespaceComputer.getHeightForWhitespaceIndex(1), 20);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeight(0), 10);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeight(1), 30);
|
||||
assert.equal(whitespaceComputer.getTotalHeight(), 30);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(1), 0);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(2), 0);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(3), 30);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(4), 30);
|
||||
|
||||
// Change last inserted whitespace height to 30
|
||||
whitespaceComputer.changeWhitespaceHeight(b, 30);
|
||||
// whitespaces: a(2, 10), b(2, 30)
|
||||
assert.equal(whitespaceComputer.getCount(), 2);
|
||||
assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(0), 2);
|
||||
assert.equal(whitespaceComputer.getHeightForWhitespaceIndex(0), 10);
|
||||
assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(1), 2);
|
||||
assert.equal(whitespaceComputer.getHeightForWhitespaceIndex(1), 30);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeight(0), 10);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeight(1), 40);
|
||||
assert.equal(whitespaceComputer.getTotalHeight(), 40);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(1), 0);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(2), 0);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(3), 40);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(4), 40);
|
||||
|
||||
// Remove last inserted whitespace
|
||||
whitespaceComputer.removeWhitespace(b);
|
||||
// whitespaces: a(2, 10)
|
||||
assert.equal(whitespaceComputer.getCount(), 1);
|
||||
assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(0), 2);
|
||||
assert.equal(whitespaceComputer.getHeightForWhitespaceIndex(0), 10);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeight(0), 10);
|
||||
assert.equal(whitespaceComputer.getTotalHeight(), 10);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(1), 0);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(2), 0);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(3), 10);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(4), 10);
|
||||
|
||||
// Add a whitespace before the first line of height 50
|
||||
b = whitespaceComputer.insertWhitespace(0, 0, 50);
|
||||
// whitespaces: b(0, 50), a(2, 10)
|
||||
assert.equal(whitespaceComputer.getCount(), 2);
|
||||
assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(0), 0);
|
||||
assert.equal(whitespaceComputer.getHeightForWhitespaceIndex(0), 50);
|
||||
assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(1), 2);
|
||||
assert.equal(whitespaceComputer.getHeightForWhitespaceIndex(1), 10);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeight(0), 50);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeight(1), 60);
|
||||
assert.equal(whitespaceComputer.getTotalHeight(), 60);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(1), 50);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(2), 50);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(3), 60);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(4), 60);
|
||||
|
||||
// Add a whitespace after line 4 of height 20
|
||||
whitespaceComputer.insertWhitespace(4, 0, 20);
|
||||
// whitespaces: b(0, 50), a(2, 10), c(4, 20)
|
||||
assert.equal(whitespaceComputer.getCount(), 3);
|
||||
assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(0), 0);
|
||||
assert.equal(whitespaceComputer.getHeightForWhitespaceIndex(0), 50);
|
||||
assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(1), 2);
|
||||
assert.equal(whitespaceComputer.getHeightForWhitespaceIndex(1), 10);
|
||||
assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(2), 4);
|
||||
assert.equal(whitespaceComputer.getHeightForWhitespaceIndex(2), 20);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeight(0), 50);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeight(1), 60);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeight(2), 80);
|
||||
assert.equal(whitespaceComputer.getTotalHeight(), 80);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(1), 50);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(2), 50);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(3), 60);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(4), 60);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(5), 80);
|
||||
|
||||
// Add a whitespace after line 3 of height 30
|
||||
whitespaceComputer.insertWhitespace(3, 0, 30);
|
||||
// whitespaces: b(0, 50), a(2, 10), d(3, 30), c(4, 20)
|
||||
assert.equal(whitespaceComputer.getCount(), 4);
|
||||
assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(0), 0);
|
||||
assert.equal(whitespaceComputer.getHeightForWhitespaceIndex(0), 50);
|
||||
assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(1), 2);
|
||||
assert.equal(whitespaceComputer.getHeightForWhitespaceIndex(1), 10);
|
||||
assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(2), 3);
|
||||
assert.equal(whitespaceComputer.getHeightForWhitespaceIndex(2), 30);
|
||||
assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(3), 4);
|
||||
assert.equal(whitespaceComputer.getHeightForWhitespaceIndex(3), 20);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeight(0), 50);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeight(1), 60);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeight(2), 90);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeight(3), 110);
|
||||
assert.equal(whitespaceComputer.getTotalHeight(), 110);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(1), 50);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(2), 50);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(3), 60);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(4), 90);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(5), 110);
|
||||
|
||||
// Change whitespace after line 2 to height of 100
|
||||
whitespaceComputer.changeWhitespaceHeight(a, 100);
|
||||
// whitespaces: b(0, 50), a(2, 100), d(3, 30), c(4, 20)
|
||||
assert.equal(whitespaceComputer.getCount(), 4);
|
||||
assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(0), 0);
|
||||
assert.equal(whitespaceComputer.getHeightForWhitespaceIndex(0), 50);
|
||||
assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(1), 2);
|
||||
assert.equal(whitespaceComputer.getHeightForWhitespaceIndex(1), 100);
|
||||
assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(2), 3);
|
||||
assert.equal(whitespaceComputer.getHeightForWhitespaceIndex(2), 30);
|
||||
assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(3), 4);
|
||||
assert.equal(whitespaceComputer.getHeightForWhitespaceIndex(3), 20);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeight(0), 50);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeight(1), 150);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeight(2), 180);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeight(3), 200);
|
||||
assert.equal(whitespaceComputer.getTotalHeight(), 200);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(1), 50);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(2), 50);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(3), 150);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(4), 180);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(5), 200);
|
||||
|
||||
// Remove whitespace after line 2
|
||||
whitespaceComputer.removeWhitespace(a);
|
||||
// whitespaces: b(0, 50), d(3, 30), c(4, 20)
|
||||
assert.equal(whitespaceComputer.getCount(), 3);
|
||||
assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(0), 0);
|
||||
assert.equal(whitespaceComputer.getHeightForWhitespaceIndex(0), 50);
|
||||
assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(1), 3);
|
||||
assert.equal(whitespaceComputer.getHeightForWhitespaceIndex(1), 30);
|
||||
assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(2), 4);
|
||||
assert.equal(whitespaceComputer.getHeightForWhitespaceIndex(2), 20);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeight(0), 50);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeight(1), 80);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeight(2), 100);
|
||||
assert.equal(whitespaceComputer.getTotalHeight(), 100);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(1), 50);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(2), 50);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(3), 50);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(4), 80);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(5), 100);
|
||||
|
||||
// Remove whitespace before line 1
|
||||
whitespaceComputer.removeWhitespace(b);
|
||||
// whitespaces: d(3, 30), c(4, 20)
|
||||
assert.equal(whitespaceComputer.getCount(), 2);
|
||||
assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(0), 3);
|
||||
assert.equal(whitespaceComputer.getHeightForWhitespaceIndex(0), 30);
|
||||
assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(1), 4);
|
||||
assert.equal(whitespaceComputer.getHeightForWhitespaceIndex(1), 20);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeight(0), 30);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeight(1), 50);
|
||||
assert.equal(whitespaceComputer.getTotalHeight(), 50);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(1), 0);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(2), 0);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(3), 0);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(4), 30);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(5), 50);
|
||||
|
||||
// Delete line 1
|
||||
whitespaceComputer.onLinesDeleted(1, 1);
|
||||
// whitespaces: d(2, 30), c(3, 20)
|
||||
assert.equal(whitespaceComputer.getCount(), 2);
|
||||
assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(0), 2);
|
||||
assert.equal(whitespaceComputer.getHeightForWhitespaceIndex(0), 30);
|
||||
assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(1), 3);
|
||||
assert.equal(whitespaceComputer.getHeightForWhitespaceIndex(1), 20);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeight(0), 30);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeight(1), 50);
|
||||
assert.equal(whitespaceComputer.getTotalHeight(), 50);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(1), 0);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(2), 0);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(3), 30);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(4), 50);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(5), 50);
|
||||
|
||||
// Insert a line before line 1
|
||||
whitespaceComputer.onLinesInserted(1, 1);
|
||||
// whitespaces: d(3, 30), c(4, 20)
|
||||
assert.equal(whitespaceComputer.getCount(), 2);
|
||||
assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(0), 3);
|
||||
assert.equal(whitespaceComputer.getHeightForWhitespaceIndex(0), 30);
|
||||
assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(1), 4);
|
||||
assert.equal(whitespaceComputer.getHeightForWhitespaceIndex(1), 20);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeight(0), 30);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeight(1), 50);
|
||||
assert.equal(whitespaceComputer.getTotalHeight(), 50);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(1), 0);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(2), 0);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(3), 0);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(4), 30);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(5), 50);
|
||||
|
||||
// Delete line 4
|
||||
whitespaceComputer.onLinesDeleted(4, 4);
|
||||
// whitespaces: d(3, 30), c(3, 20)
|
||||
assert.equal(whitespaceComputer.getCount(), 2);
|
||||
assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(0), 3);
|
||||
assert.equal(whitespaceComputer.getHeightForWhitespaceIndex(0), 30);
|
||||
assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(1), 3);
|
||||
assert.equal(whitespaceComputer.getHeightForWhitespaceIndex(1), 20);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeight(0), 30);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeight(1), 50);
|
||||
assert.equal(whitespaceComputer.getTotalHeight(), 50);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(1), 0);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(2), 0);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(3), 0);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(4), 50);
|
||||
assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(5), 50);
|
||||
});
|
||||
|
||||
test('WhitespaceComputer findInsertionIndex', () => {
|
||||
|
||||
var makeArray = (size: number, fillValue: number) => {
|
||||
var r: number[] = [];
|
||||
for (var i = 0; i < size; i++) {
|
||||
r[i] = fillValue;
|
||||
}
|
||||
return r;
|
||||
};
|
||||
|
||||
var arr: number[];
|
||||
var ordinals: number[];
|
||||
|
||||
arr = [];
|
||||
ordinals = makeArray(arr.length, 0);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 0, ordinals, 0), 0);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 1, ordinals, 0), 0);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 2, ordinals, 0), 0);
|
||||
|
||||
arr = [1];
|
||||
ordinals = makeArray(arr.length, 0);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 0, ordinals, 0), 0);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 1, ordinals, 0), 1);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 2, ordinals, 0), 1);
|
||||
|
||||
arr = [1, 3];
|
||||
ordinals = makeArray(arr.length, 0);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 0, ordinals, 0), 0);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 1, ordinals, 0), 1);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 2, ordinals, 0), 1);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 3, ordinals, 0), 2);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 4, ordinals, 0), 2);
|
||||
|
||||
arr = [1, 3, 5];
|
||||
ordinals = makeArray(arr.length, 0);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 0, ordinals, 0), 0);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 1, ordinals, 0), 1);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 2, ordinals, 0), 1);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 3, ordinals, 0), 2);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 4, ordinals, 0), 2);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 5, ordinals, 0), 3);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 6, ordinals, 0), 3);
|
||||
|
||||
arr = [1, 3, 5];
|
||||
ordinals = makeArray(arr.length, 3);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 0, ordinals, 0), 0);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 1, ordinals, 0), 0);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 2, ordinals, 0), 1);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 3, ordinals, 0), 1);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 4, ordinals, 0), 2);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 5, ordinals, 0), 2);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 6, ordinals, 0), 3);
|
||||
|
||||
arr = [1, 3, 5, 7];
|
||||
ordinals = makeArray(arr.length, 0);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 0, ordinals, 0), 0);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 1, ordinals, 0), 1);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 2, ordinals, 0), 1);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 3, ordinals, 0), 2);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 4, ordinals, 0), 2);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 5, ordinals, 0), 3);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 6, ordinals, 0), 3);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 7, ordinals, 0), 4);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 8, ordinals, 0), 4);
|
||||
|
||||
arr = [1, 3, 5, 7, 9];
|
||||
ordinals = makeArray(arr.length, 0);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 0, ordinals, 0), 0);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 1, ordinals, 0), 1);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 2, ordinals, 0), 1);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 3, ordinals, 0), 2);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 4, ordinals, 0), 2);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 5, ordinals, 0), 3);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 6, ordinals, 0), 3);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 7, ordinals, 0), 4);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 8, ordinals, 0), 4);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 9, ordinals, 0), 5);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 10, ordinals, 0), 5);
|
||||
|
||||
arr = [1, 3, 5, 7, 9, 11];
|
||||
ordinals = makeArray(arr.length, 0);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 0, ordinals, 0), 0);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 1, ordinals, 0), 1);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 2, ordinals, 0), 1);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 3, ordinals, 0), 2);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 4, ordinals, 0), 2);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 5, ordinals, 0), 3);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 6, ordinals, 0), 3);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 7, ordinals, 0), 4);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 8, ordinals, 0), 4);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 9, ordinals, 0), 5);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 10, ordinals, 0), 5);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 11, ordinals, 0), 6);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 12, ordinals, 0), 6);
|
||||
|
||||
arr = [1, 3, 5, 7, 9, 11, 13];
|
||||
ordinals = makeArray(arr.length, 0);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 0, ordinals, 0), 0);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 1, ordinals, 0), 1);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 2, ordinals, 0), 1);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 3, ordinals, 0), 2);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 4, ordinals, 0), 2);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 5, ordinals, 0), 3);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 6, ordinals, 0), 3);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 7, ordinals, 0), 4);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 8, ordinals, 0), 4);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 9, ordinals, 0), 5);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 10, ordinals, 0), 5);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 11, ordinals, 0), 6);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 12, ordinals, 0), 6);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 13, ordinals, 0), 7);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 14, ordinals, 0), 7);
|
||||
|
||||
arr = [1, 3, 5, 7, 9, 11, 13, 15];
|
||||
ordinals = makeArray(arr.length, 0);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 0, ordinals, 0), 0);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 1, ordinals, 0), 1);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 2, ordinals, 0), 1);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 3, ordinals, 0), 2);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 4, ordinals, 0), 2);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 5, ordinals, 0), 3);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 6, ordinals, 0), 3);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 7, ordinals, 0), 4);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 8, ordinals, 0), 4);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 9, ordinals, 0), 5);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 10, ordinals, 0), 5);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 11, ordinals, 0), 6);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 12, ordinals, 0), 6);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 13, ordinals, 0), 7);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 14, ordinals, 0), 7);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 15, ordinals, 0), 8);
|
||||
assert.equal(WhitespaceComputer.findInsertionIndex(arr, 16, ordinals, 0), 8);
|
||||
});
|
||||
|
||||
test('WhitespaceComputer changeWhitespaceAfterLineNumber & getFirstWhitespaceIndexAfterLineNumber', () => {
|
||||
var whitespaceComputer = new WhitespaceComputer();
|
||||
|
||||
var a = whitespaceComputer.insertWhitespace(0, 0, 1);
|
||||
var b = whitespaceComputer.insertWhitespace(7, 0, 1);
|
||||
var c = whitespaceComputer.insertWhitespace(3, 0, 1);
|
||||
|
||||
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(0), a); // 0
|
||||
assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(0), 0);
|
||||
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(1), c); // 3
|
||||
assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(1), 3);
|
||||
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(2), b); // 7
|
||||
assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(2), 7);
|
||||
|
||||
assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(1), 1); // c
|
||||
assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(2), 1); // c
|
||||
assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(3), 1); // c
|
||||
assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(4), 2); // b
|
||||
assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(5), 2); // b
|
||||
assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(6), 2); // b
|
||||
assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(7), 2); // b
|
||||
assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(8), -1); // --
|
||||
|
||||
// Do not really move a
|
||||
whitespaceComputer.changeWhitespaceAfterLineNumber(a, 1);
|
||||
|
||||
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(0), a); // 1
|
||||
assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(0), 1);
|
||||
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(1), c); // 3
|
||||
assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(1), 3);
|
||||
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(2), b); // 7
|
||||
assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(2), 7);
|
||||
|
||||
assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(1), 0); // a
|
||||
assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(2), 1); // c
|
||||
assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(3), 1); // c
|
||||
assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(4), 2); // b
|
||||
assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(5), 2); // b
|
||||
assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(6), 2); // b
|
||||
assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(7), 2); // b
|
||||
assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(8), -1); // --
|
||||
|
||||
|
||||
// Do not really move a
|
||||
whitespaceComputer.changeWhitespaceAfterLineNumber(a, 2);
|
||||
|
||||
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(0), a); // 2
|
||||
assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(0), 2);
|
||||
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(1), c); // 3
|
||||
assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(1), 3);
|
||||
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(2), b); // 7
|
||||
assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(2), 7);
|
||||
|
||||
assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(1), 0); // a
|
||||
assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(2), 0); // a
|
||||
assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(3), 1); // c
|
||||
assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(4), 2); // b
|
||||
assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(5), 2); // b
|
||||
assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(6), 2); // b
|
||||
assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(7), 2); // b
|
||||
assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(8), -1); // --
|
||||
|
||||
|
||||
// Change a to conflict with c => a gets placed after c
|
||||
whitespaceComputer.changeWhitespaceAfterLineNumber(a, 3);
|
||||
|
||||
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(0), c); // 3
|
||||
assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(0), 3);
|
||||
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(1), a); // 3
|
||||
assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(1), 3);
|
||||
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(2), b); // 7
|
||||
assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(2), 7);
|
||||
|
||||
assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(1), 0); // c
|
||||
assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(2), 0); // c
|
||||
assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(3), 0); // c
|
||||
assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(4), 2); // b
|
||||
assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(5), 2); // b
|
||||
assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(6), 2); // b
|
||||
assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(7), 2); // b
|
||||
assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(8), -1); // --
|
||||
|
||||
|
||||
// Make a no-op
|
||||
whitespaceComputer.changeWhitespaceAfterLineNumber(c, 3);
|
||||
|
||||
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(0), c); // 3
|
||||
assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(0), 3);
|
||||
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(1), a); // 3
|
||||
assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(1), 3);
|
||||
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(2), b); // 7
|
||||
assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(2), 7);
|
||||
|
||||
assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(1), 0); // c
|
||||
assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(2), 0); // c
|
||||
assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(3), 0); // c
|
||||
assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(4), 2); // b
|
||||
assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(5), 2); // b
|
||||
assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(6), 2); // b
|
||||
assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(7), 2); // b
|
||||
assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(8), -1); // --
|
||||
|
||||
|
||||
|
||||
// Conflict c with b => c gets placed after b
|
||||
whitespaceComputer.changeWhitespaceAfterLineNumber(c, 7);
|
||||
|
||||
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(0), a); // 3
|
||||
assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(0), 3);
|
||||
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(1), b); // 7
|
||||
assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(1), 7);
|
||||
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(2), c); // 7
|
||||
assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(2), 7);
|
||||
|
||||
assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(1), 0); // a
|
||||
assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(2), 0); // a
|
||||
assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(3), 0); // a
|
||||
assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(4), 1); // b
|
||||
assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(5), 1); // b
|
||||
assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(6), 1); // b
|
||||
assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(7), 1); // b
|
||||
assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(8), -1); // --
|
||||
});
|
||||
|
||||
|
||||
test('WhitespaceComputer Bug', () => {
|
||||
var whitespaceComputer = new WhitespaceComputer();
|
||||
|
||||
var a = whitespaceComputer.insertWhitespace(0, 0, 1);
|
||||
var b = whitespaceComputer.insertWhitespace(7, 0, 1);
|
||||
|
||||
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(0), a); // 0
|
||||
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(1), b); // 7
|
||||
|
||||
var c = whitespaceComputer.insertWhitespace(3, 0, 1);
|
||||
|
||||
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(0), a); // 0
|
||||
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(1), c); // 3
|
||||
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(2), b); // 7
|
||||
|
||||
var d = whitespaceComputer.insertWhitespace(2, 0, 1);
|
||||
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(0), a); // 0
|
||||
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(1), d); // 2
|
||||
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(2), c); // 3
|
||||
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(3), b); // 7
|
||||
|
||||
var e = whitespaceComputer.insertWhitespace(8, 0, 1);
|
||||
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(0), a); // 0
|
||||
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(1), d); // 2
|
||||
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(2), c); // 3
|
||||
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(3), b); // 7
|
||||
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(4), e); // 8
|
||||
|
||||
var f = whitespaceComputer.insertWhitespace(11, 0, 1);
|
||||
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(0), a); // 0
|
||||
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(1), d); // 2
|
||||
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(2), c); // 3
|
||||
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(3), b); // 7
|
||||
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(4), e); // 8
|
||||
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(5), f); // 11
|
||||
|
||||
var g = whitespaceComputer.insertWhitespace(10, 0, 1);
|
||||
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(0), a); // 0
|
||||
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(1), d); // 2
|
||||
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(2), c); // 3
|
||||
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(3), b); // 7
|
||||
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(4), e); // 8
|
||||
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(5), g); // 10
|
||||
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(6), f); // 11
|
||||
|
||||
var h = whitespaceComputer.insertWhitespace(0, 0, 1);
|
||||
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(0), a); // 0
|
||||
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(1), h); // 0
|
||||
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(2), d); // 2
|
||||
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(3), c); // 3
|
||||
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(4), b); // 7
|
||||
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(5), e); // 8
|
||||
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(6), g); // 10
|
||||
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(7), f); // 11
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { WrappingIndent } from 'vs/editor/common/config/editorOptions';
|
||||
import { CharacterHardWrappingLineMapperFactory } from 'vs/editor/common/viewModel/characterHardWrappingLineMapper';
|
||||
import { ILineMapperFactory } from 'vs/editor/common/viewModel/splitLinesCollection';
|
||||
|
||||
function assertLineMapping(factory: ILineMapperFactory, tabSize: number, breakAfter: number, annotatedText: string, wrappingIndent = WrappingIndent.None) {
|
||||
|
||||
let rawText = '';
|
||||
let currentLineIndex = 0;
|
||||
let lineIndices: number[] = [];
|
||||
for (let i = 0, len = annotatedText.length; i < len; i++) {
|
||||
if (annotatedText.charAt(i) === '|') {
|
||||
currentLineIndex++;
|
||||
} else {
|
||||
rawText += annotatedText.charAt(i);
|
||||
lineIndices[rawText.length - 1] = currentLineIndex;
|
||||
}
|
||||
}
|
||||
|
||||
let mapper = factory.createLineMapping(rawText, tabSize, breakAfter, 2, wrappingIndent);
|
||||
|
||||
let actualAnnotatedText = '';
|
||||
if (mapper) {
|
||||
let previousLineIndex = 0;
|
||||
for (let i = 0, len = rawText.length; i < len; i++) {
|
||||
let r = mapper.getOutputPositionOfInputOffset(i);
|
||||
if (previousLineIndex !== r.outputLineIndex) {
|
||||
previousLineIndex = r.outputLineIndex;
|
||||
actualAnnotatedText += '|';
|
||||
}
|
||||
actualAnnotatedText += rawText.charAt(i);
|
||||
}
|
||||
} else {
|
||||
// No wrapping
|
||||
actualAnnotatedText = rawText;
|
||||
}
|
||||
|
||||
assert.equal(actualAnnotatedText, annotatedText);
|
||||
}
|
||||
|
||||
suite('Editor ViewModel - CharacterHardWrappingLineMapper', () => {
|
||||
test('CharacterHardWrappingLineMapper', () => {
|
||||
|
||||
let factory = new CharacterHardWrappingLineMapperFactory('(', ')', '.');
|
||||
|
||||
// Empty string
|
||||
assertLineMapping(factory, 4, 5, '');
|
||||
|
||||
// No wrapping if not necessary
|
||||
assertLineMapping(factory, 4, 5, 'aaa');
|
||||
assertLineMapping(factory, 4, 5, 'aaaaa');
|
||||
assertLineMapping(factory, 4, -1, 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa');
|
||||
|
||||
// Acts like hard wrapping if no char found
|
||||
assertLineMapping(factory, 4, 5, 'aaaaa|a');
|
||||
|
||||
// Honors obtrusive wrapping character
|
||||
assertLineMapping(factory, 4, 5, 'aaaaa|.');
|
||||
assertLineMapping(factory, 4, 5, 'aaaaa|a.|aaa.|aa');
|
||||
assertLineMapping(factory, 4, 5, 'aaaaa|a..|aaa.|aa');
|
||||
assertLineMapping(factory, 4, 5, 'aaaaa|a...|aaa.|aa');
|
||||
assertLineMapping(factory, 4, 5, 'aaaaa|a....|aaa.|aa');
|
||||
|
||||
// Honors tabs when computing wrapping position
|
||||
assertLineMapping(factory, 4, 5, '\t');
|
||||
assertLineMapping(factory, 4, 5, '\ta|aa');
|
||||
assertLineMapping(factory, 4, 5, '\ta|\ta|a');
|
||||
assertLineMapping(factory, 4, 5, 'aa\ta');
|
||||
assertLineMapping(factory, 4, 5, 'aa\ta|a');
|
||||
|
||||
// Honors wrapping before characters (& gives it priority)
|
||||
assertLineMapping(factory, 4, 5, 'aaa.|aa');
|
||||
assertLineMapping(factory, 4, 5, 'aaa|(.aa');
|
||||
|
||||
// Honors wrapping after characters (& gives it priority)
|
||||
assertLineMapping(factory, 4, 5, 'aaa))|).aaa');
|
||||
assertLineMapping(factory, 4, 5, 'aaa))|)|.aaaa');
|
||||
assertLineMapping(factory, 4, 5, 'aaa)|()|.aaa');
|
||||
assertLineMapping(factory, 4, 5, 'aaa(|()|.aaa');
|
||||
assertLineMapping(factory, 4, 5, 'aa.(|()|.aaa');
|
||||
assertLineMapping(factory, 4, 5, 'aa.|(.)|.aaa');
|
||||
});
|
||||
|
||||
test('CharacterHardWrappingLineMapper - CJK and Kinsoku Shori', () => {
|
||||
let factory = new CharacterHardWrappingLineMapperFactory('(', ')', '.');
|
||||
assertLineMapping(factory, 4, 5, 'aa \u5b89|\u5b89');
|
||||
assertLineMapping(factory, 4, 5, '\u3042 \u5b89|\u5b89');
|
||||
assertLineMapping(factory, 4, 5, '\u3042\u3042|\u5b89\u5b89');
|
||||
assertLineMapping(factory, 4, 5, 'aa |\u5b89)\u5b89|\u5b89');
|
||||
assertLineMapping(factory, 4, 5, 'aa \u3042|\u5b89\u3042)|\u5b89');
|
||||
assertLineMapping(factory, 4, 5, 'aa |(\u5b89aa|\u5b89');
|
||||
});
|
||||
|
||||
test('CharacterHardWrappingLineMapper - WrappingIndent.Same', () => {
|
||||
let factory = new CharacterHardWrappingLineMapperFactory('', ' ', '');
|
||||
assertLineMapping(factory, 4, 38, ' *123456789012345678901234567890123456|7890', WrappingIndent.Same);
|
||||
});
|
||||
|
||||
test('issue #16332: Scroll bar overlaying on top of text', () => {
|
||||
let factory = new CharacterHardWrappingLineMapperFactory('', ' ', '');
|
||||
assertLineMapping(factory, 4, 24, 'a/ very/long/line/of/tex|t/that/expands/beyon|d/your/typical/line/|of/code/', WrappingIndent.Indent);
|
||||
});
|
||||
});
|
||||
171
src/vs/editor/test/common/viewModel/prefixSumComputer.test.ts
Normal file
171
src/vs/editor/test/common/viewModel/prefixSumComputer.test.ts
Normal file
@@ -0,0 +1,171 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { PrefixSumComputer, PrefixSumIndexOfResult } from 'vs/editor/common/viewModel/prefixSumComputer';
|
||||
import { toUint32Array } from 'vs/editor/common/core/uint';
|
||||
|
||||
suite('Editor ViewModel - PrefixSumComputer', () => {
|
||||
|
||||
test('PrefixSumComputer', () => {
|
||||
let indexOfResult: PrefixSumIndexOfResult;
|
||||
|
||||
var psc = new PrefixSumComputer(toUint32Array([1, 1, 2, 1, 3]));
|
||||
assert.equal(psc.getTotalValue(), 8);
|
||||
assert.equal(psc.getAccumulatedValue(-1), 0);
|
||||
assert.equal(psc.getAccumulatedValue(0), 1);
|
||||
assert.equal(psc.getAccumulatedValue(1), 2);
|
||||
assert.equal(psc.getAccumulatedValue(2), 4);
|
||||
assert.equal(psc.getAccumulatedValue(3), 5);
|
||||
assert.equal(psc.getAccumulatedValue(4), 8);
|
||||
indexOfResult = psc.getIndexOf(0);
|
||||
assert.equal(indexOfResult.index, 0);
|
||||
assert.equal(indexOfResult.remainder, 0);
|
||||
indexOfResult = psc.getIndexOf(1);
|
||||
assert.equal(indexOfResult.index, 1);
|
||||
assert.equal(indexOfResult.remainder, 0);
|
||||
indexOfResult = psc.getIndexOf(2);
|
||||
assert.equal(indexOfResult.index, 2);
|
||||
assert.equal(indexOfResult.remainder, 0);
|
||||
indexOfResult = psc.getIndexOf(3);
|
||||
assert.equal(indexOfResult.index, 2);
|
||||
assert.equal(indexOfResult.remainder, 1);
|
||||
indexOfResult = psc.getIndexOf(4);
|
||||
assert.equal(indexOfResult.index, 3);
|
||||
assert.equal(indexOfResult.remainder, 0);
|
||||
indexOfResult = psc.getIndexOf(5);
|
||||
assert.equal(indexOfResult.index, 4);
|
||||
assert.equal(indexOfResult.remainder, 0);
|
||||
indexOfResult = psc.getIndexOf(6);
|
||||
assert.equal(indexOfResult.index, 4);
|
||||
assert.equal(indexOfResult.remainder, 1);
|
||||
indexOfResult = psc.getIndexOf(7);
|
||||
assert.equal(indexOfResult.index, 4);
|
||||
assert.equal(indexOfResult.remainder, 2);
|
||||
indexOfResult = psc.getIndexOf(8);
|
||||
assert.equal(indexOfResult.index, 4);
|
||||
assert.equal(indexOfResult.remainder, 3);
|
||||
|
||||
// [1, 2, 2, 1, 3]
|
||||
psc.changeValue(1, 2);
|
||||
assert.equal(psc.getTotalValue(), 9);
|
||||
assert.equal(psc.getAccumulatedValue(0), 1);
|
||||
assert.equal(psc.getAccumulatedValue(1), 3);
|
||||
assert.equal(psc.getAccumulatedValue(2), 5);
|
||||
assert.equal(psc.getAccumulatedValue(3), 6);
|
||||
assert.equal(psc.getAccumulatedValue(4), 9);
|
||||
|
||||
// [1, 0, 2, 1, 3]
|
||||
psc.changeValue(1, 0);
|
||||
assert.equal(psc.getTotalValue(), 7);
|
||||
assert.equal(psc.getAccumulatedValue(0), 1);
|
||||
assert.equal(psc.getAccumulatedValue(1), 1);
|
||||
assert.equal(psc.getAccumulatedValue(2), 3);
|
||||
assert.equal(psc.getAccumulatedValue(3), 4);
|
||||
assert.equal(psc.getAccumulatedValue(4), 7);
|
||||
indexOfResult = psc.getIndexOf(0);
|
||||
assert.equal(indexOfResult.index, 0);
|
||||
assert.equal(indexOfResult.remainder, 0);
|
||||
indexOfResult = psc.getIndexOf(1);
|
||||
assert.equal(indexOfResult.index, 2);
|
||||
assert.equal(indexOfResult.remainder, 0);
|
||||
indexOfResult = psc.getIndexOf(2);
|
||||
assert.equal(indexOfResult.index, 2);
|
||||
assert.equal(indexOfResult.remainder, 1);
|
||||
indexOfResult = psc.getIndexOf(3);
|
||||
assert.equal(indexOfResult.index, 3);
|
||||
assert.equal(indexOfResult.remainder, 0);
|
||||
indexOfResult = psc.getIndexOf(4);
|
||||
assert.equal(indexOfResult.index, 4);
|
||||
assert.equal(indexOfResult.remainder, 0);
|
||||
indexOfResult = psc.getIndexOf(5);
|
||||
assert.equal(indexOfResult.index, 4);
|
||||
assert.equal(indexOfResult.remainder, 1);
|
||||
indexOfResult = psc.getIndexOf(6);
|
||||
assert.equal(indexOfResult.index, 4);
|
||||
assert.equal(indexOfResult.remainder, 2);
|
||||
indexOfResult = psc.getIndexOf(7);
|
||||
assert.equal(indexOfResult.index, 4);
|
||||
assert.equal(indexOfResult.remainder, 3);
|
||||
|
||||
// [1, 0, 0, 1, 3]
|
||||
psc.changeValue(2, 0);
|
||||
assert.equal(psc.getTotalValue(), 5);
|
||||
assert.equal(psc.getAccumulatedValue(0), 1);
|
||||
assert.equal(psc.getAccumulatedValue(1), 1);
|
||||
assert.equal(psc.getAccumulatedValue(2), 1);
|
||||
assert.equal(psc.getAccumulatedValue(3), 2);
|
||||
assert.equal(psc.getAccumulatedValue(4), 5);
|
||||
indexOfResult = psc.getIndexOf(0);
|
||||
assert.equal(indexOfResult.index, 0);
|
||||
assert.equal(indexOfResult.remainder, 0);
|
||||
indexOfResult = psc.getIndexOf(1);
|
||||
assert.equal(indexOfResult.index, 3);
|
||||
assert.equal(indexOfResult.remainder, 0);
|
||||
indexOfResult = psc.getIndexOf(2);
|
||||
assert.equal(indexOfResult.index, 4);
|
||||
assert.equal(indexOfResult.remainder, 0);
|
||||
indexOfResult = psc.getIndexOf(3);
|
||||
assert.equal(indexOfResult.index, 4);
|
||||
assert.equal(indexOfResult.remainder, 1);
|
||||
indexOfResult = psc.getIndexOf(4);
|
||||
assert.equal(indexOfResult.index, 4);
|
||||
assert.equal(indexOfResult.remainder, 2);
|
||||
indexOfResult = psc.getIndexOf(5);
|
||||
assert.equal(indexOfResult.index, 4);
|
||||
assert.equal(indexOfResult.remainder, 3);
|
||||
|
||||
// [1, 0, 0, 0, 3]
|
||||
psc.changeValue(3, 0);
|
||||
assert.equal(psc.getTotalValue(), 4);
|
||||
assert.equal(psc.getAccumulatedValue(0), 1);
|
||||
assert.equal(psc.getAccumulatedValue(1), 1);
|
||||
assert.equal(psc.getAccumulatedValue(2), 1);
|
||||
assert.equal(psc.getAccumulatedValue(3), 1);
|
||||
assert.equal(psc.getAccumulatedValue(4), 4);
|
||||
indexOfResult = psc.getIndexOf(0);
|
||||
assert.equal(indexOfResult.index, 0);
|
||||
assert.equal(indexOfResult.remainder, 0);
|
||||
indexOfResult = psc.getIndexOf(1);
|
||||
assert.equal(indexOfResult.index, 4);
|
||||
assert.equal(indexOfResult.remainder, 0);
|
||||
indexOfResult = psc.getIndexOf(2);
|
||||
assert.equal(indexOfResult.index, 4);
|
||||
assert.equal(indexOfResult.remainder, 1);
|
||||
indexOfResult = psc.getIndexOf(3);
|
||||
assert.equal(indexOfResult.index, 4);
|
||||
assert.equal(indexOfResult.remainder, 2);
|
||||
indexOfResult = psc.getIndexOf(4);
|
||||
assert.equal(indexOfResult.index, 4);
|
||||
assert.equal(indexOfResult.remainder, 3);
|
||||
|
||||
// [1, 1, 0, 1, 1]
|
||||
psc.changeValue(1, 1);
|
||||
psc.changeValue(3, 1);
|
||||
psc.changeValue(4, 1);
|
||||
assert.equal(psc.getTotalValue(), 4);
|
||||
assert.equal(psc.getAccumulatedValue(0), 1);
|
||||
assert.equal(psc.getAccumulatedValue(1), 2);
|
||||
assert.equal(psc.getAccumulatedValue(2), 2);
|
||||
assert.equal(psc.getAccumulatedValue(3), 3);
|
||||
assert.equal(psc.getAccumulatedValue(4), 4);
|
||||
indexOfResult = psc.getIndexOf(0);
|
||||
assert.equal(indexOfResult.index, 0);
|
||||
assert.equal(indexOfResult.remainder, 0);
|
||||
indexOfResult = psc.getIndexOf(1);
|
||||
assert.equal(indexOfResult.index, 1);
|
||||
assert.equal(indexOfResult.remainder, 0);
|
||||
indexOfResult = psc.getIndexOf(2);
|
||||
assert.equal(indexOfResult.index, 3);
|
||||
assert.equal(indexOfResult.remainder, 0);
|
||||
indexOfResult = psc.getIndexOf(3);
|
||||
assert.equal(indexOfResult.index, 4);
|
||||
assert.equal(indexOfResult.remainder, 0);
|
||||
indexOfResult = psc.getIndexOf(4);
|
||||
assert.equal(indexOfResult.index, 4);
|
||||
assert.equal(indexOfResult.remainder, 1);
|
||||
});
|
||||
});
|
||||
786
src/vs/editor/test/common/viewModel/splitLinesCollection.test.ts
Normal file
786
src/vs/editor/test/common/viewModel/splitLinesCollection.test.ts
Normal file
@@ -0,0 +1,786 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { Position } from 'vs/editor/common/core/position';
|
||||
import { CharacterHardWrappingLineMapping, CharacterHardWrappingLineMapperFactory } from 'vs/editor/common/viewModel/characterHardWrappingLineMapper';
|
||||
import { PrefixSumComputer } from 'vs/editor/common/viewModel/prefixSumComputer';
|
||||
import { ILineMapping, IModel, SplitLine, SplitLinesCollection } from 'vs/editor/common/viewModel/splitLinesCollection';
|
||||
import { TestConfiguration } from 'vs/editor/test/common/mocks/testConfiguration';
|
||||
import { Model } from 'vs/editor/common/model/model';
|
||||
import { toUint32Array } from 'vs/editor/common/core/uint';
|
||||
import * as modes from 'vs/editor/common/modes';
|
||||
import { NULL_STATE } from 'vs/editor/common/modes/nullMode';
|
||||
import { TokenizationResult2 } from 'vs/editor/common/core/token';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { ViewLineToken } from 'vs/editor/common/core/viewLineToken';
|
||||
import { ViewLineData } from 'vs/editor/common/viewModel/viewModel';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
|
||||
suite('Editor ViewModel - SplitLinesCollection', () => {
|
||||
test('SplitLine', () => {
|
||||
var model1 = createModel('My First LineMy Second LineAnd another one');
|
||||
var line1 = createSplitLine([13, 14, 15], '');
|
||||
|
||||
assert.equal(line1.getViewLineCount(), 3);
|
||||
assert.equal(line1.getViewLineContent(model1, 1, 0), 'My First Line');
|
||||
assert.equal(line1.getViewLineContent(model1, 1, 1), 'My Second Line');
|
||||
assert.equal(line1.getViewLineContent(model1, 1, 2), 'And another one');
|
||||
assert.equal(line1.getViewLineMaxColumn(model1, 1, 0), 14);
|
||||
assert.equal(line1.getViewLineMaxColumn(model1, 1, 1), 15);
|
||||
assert.equal(line1.getViewLineMaxColumn(model1, 1, 2), 16);
|
||||
for (var col = 1; col <= 14; col++) {
|
||||
assert.equal(line1.getModelColumnOfViewPosition(0, col), col, 'getInputColumnOfOutputPosition(0, ' + col + ')');
|
||||
}
|
||||
for (var col = 1; col <= 15; col++) {
|
||||
assert.equal(line1.getModelColumnOfViewPosition(1, col), 13 + col, 'getInputColumnOfOutputPosition(1, ' + col + ')');
|
||||
}
|
||||
for (var col = 1; col <= 16; col++) {
|
||||
assert.equal(line1.getModelColumnOfViewPosition(2, col), 13 + 14 + col, 'getInputColumnOfOutputPosition(2, ' + col + ')');
|
||||
}
|
||||
for (var col = 1; col <= 13; col++) {
|
||||
assert.deepEqual(line1.getViewPositionOfModelPosition(0, col), pos(0, col), 'getOutputPositionOfInputPosition(' + col + ')');
|
||||
}
|
||||
for (var col = 1 + 13; col <= 14 + 13; col++) {
|
||||
assert.deepEqual(line1.getViewPositionOfModelPosition(0, col), pos(1, col - 13), 'getOutputPositionOfInputPosition(' + col + ')');
|
||||
}
|
||||
for (var col = 1 + 13 + 14; col <= 15 + 14 + 13; col++) {
|
||||
assert.deepEqual(line1.getViewPositionOfModelPosition(0, col), pos(2, col - 13 - 14), 'getOutputPositionOfInputPosition(' + col + ')');
|
||||
}
|
||||
|
||||
model1 = createModel('My First LineMy Second LineAnd another one');
|
||||
line1 = createSplitLine([13, 14, 15], '\t');
|
||||
|
||||
assert.equal(line1.getViewLineCount(), 3);
|
||||
assert.equal(line1.getViewLineContent(model1, 1, 0), 'My First Line');
|
||||
assert.equal(line1.getViewLineContent(model1, 1, 1), '\tMy Second Line');
|
||||
assert.equal(line1.getViewLineContent(model1, 1, 2), '\tAnd another one');
|
||||
assert.equal(line1.getViewLineMaxColumn(model1, 1, 0), 14);
|
||||
assert.equal(line1.getViewLineMaxColumn(model1, 1, 1), 16);
|
||||
assert.equal(line1.getViewLineMaxColumn(model1, 1, 2), 17);
|
||||
for (var col = 1; col <= 14; col++) {
|
||||
assert.equal(line1.getModelColumnOfViewPosition(0, col), col, 'getInputColumnOfOutputPosition(0, ' + col + ')');
|
||||
}
|
||||
for (var col = 1; col <= 1; col++) {
|
||||
assert.equal(line1.getModelColumnOfViewPosition(1, 1), 13 + col, 'getInputColumnOfOutputPosition(1, ' + col + ')');
|
||||
}
|
||||
for (var col = 2; col <= 16; col++) {
|
||||
assert.equal(line1.getModelColumnOfViewPosition(1, col), 13 + col - 1, 'getInputColumnOfOutputPosition(1, ' + col + ')');
|
||||
}
|
||||
for (var col = 1; col <= 1; col++) {
|
||||
assert.equal(line1.getModelColumnOfViewPosition(2, col), 13 + 14 + col, 'getInputColumnOfOutputPosition(2, ' + col + ')');
|
||||
}
|
||||
for (var col = 2; col <= 17; col++) {
|
||||
assert.equal(line1.getModelColumnOfViewPosition(2, col), 13 + 14 + col - 1, 'getInputColumnOfOutputPosition(2, ' + col + ')');
|
||||
}
|
||||
for (var col = 1; col <= 13; col++) {
|
||||
assert.deepEqual(line1.getViewPositionOfModelPosition(0, col), pos(0, col), 'getOutputPositionOfInputPosition(' + col + ')');
|
||||
}
|
||||
for (var col = 1 + 13; col <= 14 + 13; col++) {
|
||||
assert.deepEqual(line1.getViewPositionOfModelPosition(0, col), pos(1, 1 + col - 13), 'getOutputPositionOfInputPosition(' + col + ')');
|
||||
}
|
||||
for (var col = 1 + 13 + 14; col <= 15 + 14 + 13; col++) {
|
||||
assert.deepEqual(line1.getViewPositionOfModelPosition(0, col), pos(2, 1 + col - 13 - 14), 'getOutputPositionOfInputPosition(' + col + ')');
|
||||
}
|
||||
});
|
||||
|
||||
function withSplitLinesCollection(text: string, callback: (model: Model, linesCollection: SplitLinesCollection) => void): void {
|
||||
let config = new TestConfiguration({});
|
||||
|
||||
let hardWrappingLineMapperFactory = new CharacterHardWrappingLineMapperFactory(
|
||||
config.editor.wrappingInfo.wordWrapBreakBeforeCharacters,
|
||||
config.editor.wrappingInfo.wordWrapBreakAfterCharacters,
|
||||
config.editor.wrappingInfo.wordWrapBreakObtrusiveCharacters
|
||||
);
|
||||
|
||||
let model = Model.createFromString([
|
||||
'int main() {',
|
||||
'\tprintf("Hello world!");',
|
||||
'}',
|
||||
'int main() {',
|
||||
'\tprintf("Hello world!");',
|
||||
'}',
|
||||
].join('\n'));
|
||||
|
||||
let linesCollection = new SplitLinesCollection(
|
||||
model,
|
||||
hardWrappingLineMapperFactory,
|
||||
model.getOptions().tabSize,
|
||||
config.editor.wrappingInfo.wrappingColumn,
|
||||
config.editor.fontInfo.typicalFullwidthCharacterWidth / config.editor.fontInfo.typicalHalfwidthCharacterWidth,
|
||||
config.editor.wrappingInfo.wrappingIndent
|
||||
);
|
||||
|
||||
callback(model, linesCollection);
|
||||
|
||||
linesCollection.dispose();
|
||||
model.dispose();
|
||||
config.dispose();
|
||||
}
|
||||
|
||||
test('Invalid line numbers', () => {
|
||||
|
||||
const text = [
|
||||
'int main() {',
|
||||
'\tprintf("Hello world!");',
|
||||
'}',
|
||||
'int main() {',
|
||||
'\tprintf("Hello world!");',
|
||||
'}',
|
||||
].join('\n');
|
||||
|
||||
withSplitLinesCollection(text, (model, linesCollection) => {
|
||||
assert.equal(linesCollection.getViewLineCount(), 6);
|
||||
|
||||
// getOutputIndentGuide
|
||||
assert.equal(linesCollection.getViewLineIndentGuide(-1), 0);
|
||||
assert.equal(linesCollection.getViewLineIndentGuide(0), 0);
|
||||
assert.equal(linesCollection.getViewLineIndentGuide(1), 0);
|
||||
assert.equal(linesCollection.getViewLineIndentGuide(2), 1);
|
||||
assert.equal(linesCollection.getViewLineIndentGuide(3), 0);
|
||||
assert.equal(linesCollection.getViewLineIndentGuide(4), 0);
|
||||
assert.equal(linesCollection.getViewLineIndentGuide(5), 1);
|
||||
assert.equal(linesCollection.getViewLineIndentGuide(6), 0);
|
||||
assert.equal(linesCollection.getViewLineIndentGuide(7), 0);
|
||||
|
||||
// getOutputLineContent
|
||||
assert.equal(linesCollection.getViewLineContent(-1), 'int main() {');
|
||||
assert.equal(linesCollection.getViewLineContent(0), 'int main() {');
|
||||
assert.equal(linesCollection.getViewLineContent(1), 'int main() {');
|
||||
assert.equal(linesCollection.getViewLineContent(2), '\tprintf("Hello world!");');
|
||||
assert.equal(linesCollection.getViewLineContent(3), '}');
|
||||
assert.equal(linesCollection.getViewLineContent(4), 'int main() {');
|
||||
assert.equal(linesCollection.getViewLineContent(5), '\tprintf("Hello world!");');
|
||||
assert.equal(linesCollection.getViewLineContent(6), '}');
|
||||
assert.equal(linesCollection.getViewLineContent(7), '}');
|
||||
|
||||
// getOutputLineMinColumn
|
||||
assert.equal(linesCollection.getViewLineMinColumn(-1), 1);
|
||||
assert.equal(linesCollection.getViewLineMinColumn(0), 1);
|
||||
assert.equal(linesCollection.getViewLineMinColumn(1), 1);
|
||||
assert.equal(linesCollection.getViewLineMinColumn(2), 1);
|
||||
assert.equal(linesCollection.getViewLineMinColumn(3), 1);
|
||||
assert.equal(linesCollection.getViewLineMinColumn(4), 1);
|
||||
assert.equal(linesCollection.getViewLineMinColumn(5), 1);
|
||||
assert.equal(linesCollection.getViewLineMinColumn(6), 1);
|
||||
assert.equal(linesCollection.getViewLineMinColumn(7), 1);
|
||||
|
||||
// getOutputLineMaxColumn
|
||||
assert.equal(linesCollection.getViewLineMaxColumn(-1), 13);
|
||||
assert.equal(linesCollection.getViewLineMaxColumn(0), 13);
|
||||
assert.equal(linesCollection.getViewLineMaxColumn(1), 13);
|
||||
assert.equal(linesCollection.getViewLineMaxColumn(2), 25);
|
||||
assert.equal(linesCollection.getViewLineMaxColumn(3), 2);
|
||||
assert.equal(linesCollection.getViewLineMaxColumn(4), 13);
|
||||
assert.equal(linesCollection.getViewLineMaxColumn(5), 25);
|
||||
assert.equal(linesCollection.getViewLineMaxColumn(6), 2);
|
||||
assert.equal(linesCollection.getViewLineMaxColumn(7), 2);
|
||||
|
||||
// convertOutputPositionToInputPosition
|
||||
assert.deepEqual(linesCollection.convertViewPositionToModelPosition(-1, 1), new Position(1, 1));
|
||||
assert.deepEqual(linesCollection.convertViewPositionToModelPosition(0, 1), new Position(1, 1));
|
||||
assert.deepEqual(linesCollection.convertViewPositionToModelPosition(1, 1), new Position(1, 1));
|
||||
assert.deepEqual(linesCollection.convertViewPositionToModelPosition(2, 1), new Position(2, 1));
|
||||
assert.deepEqual(linesCollection.convertViewPositionToModelPosition(3, 1), new Position(3, 1));
|
||||
assert.deepEqual(linesCollection.convertViewPositionToModelPosition(4, 1), new Position(4, 1));
|
||||
assert.deepEqual(linesCollection.convertViewPositionToModelPosition(5, 1), new Position(5, 1));
|
||||
assert.deepEqual(linesCollection.convertViewPositionToModelPosition(6, 1), new Position(6, 1));
|
||||
assert.deepEqual(linesCollection.convertViewPositionToModelPosition(7, 1), new Position(6, 1));
|
||||
assert.deepEqual(linesCollection.convertViewPositionToModelPosition(8, 1), new Position(6, 1));
|
||||
});
|
||||
});
|
||||
|
||||
test('issue #3662', () => {
|
||||
|
||||
const text = [
|
||||
'int main() {',
|
||||
'\tprintf("Hello world!");',
|
||||
'}',
|
||||
'int main() {',
|
||||
'\tprintf("Hello world!");',
|
||||
'}',
|
||||
].join('\n');
|
||||
|
||||
withSplitLinesCollection(text, (model, linesCollection) => {
|
||||
linesCollection.setHiddenAreas([
|
||||
new Range(1, 1, 3, 1),
|
||||
new Range(5, 1, 6, 1)
|
||||
]);
|
||||
|
||||
let viewLineCount = linesCollection.getViewLineCount();
|
||||
assert.equal(viewLineCount, 1, 'getOutputLineCount()');
|
||||
|
||||
let modelLineCount = model.getLineCount();
|
||||
for (let lineNumber = 0; lineNumber <= modelLineCount + 1; lineNumber++) {
|
||||
let lineMinColumn = (lineNumber >= 1 && lineNumber <= modelLineCount) ? model.getLineMinColumn(lineNumber) : 1;
|
||||
let lineMaxColumn = (lineNumber >= 1 && lineNumber <= modelLineCount) ? model.getLineMaxColumn(lineNumber) : 1;
|
||||
for (let column = lineMinColumn - 1; column <= lineMaxColumn + 1; column++) {
|
||||
let viewPosition = linesCollection.convertModelPositionToViewPosition(lineNumber, column);
|
||||
|
||||
// validate view position
|
||||
let viewLineNumber = viewPosition.lineNumber;
|
||||
let viewColumn = viewPosition.column;
|
||||
if (viewLineNumber < 1) {
|
||||
viewLineNumber = 1;
|
||||
}
|
||||
var lineCount = linesCollection.getViewLineCount();
|
||||
if (viewLineNumber > lineCount) {
|
||||
viewLineNumber = lineCount;
|
||||
}
|
||||
var viewMinColumn = linesCollection.getViewLineMinColumn(viewLineNumber);
|
||||
var viewMaxColumn = linesCollection.getViewLineMaxColumn(viewLineNumber);
|
||||
if (viewColumn < viewMinColumn) {
|
||||
viewColumn = viewMinColumn;
|
||||
}
|
||||
if (viewColumn > viewMaxColumn) {
|
||||
viewColumn = viewMaxColumn;
|
||||
}
|
||||
let validViewPosition = new Position(viewLineNumber, viewColumn);
|
||||
assert.equal(viewPosition.toString(), validViewPosition.toString(), 'model->view for ' + lineNumber + ', ' + column);
|
||||
}
|
||||
}
|
||||
|
||||
for (let lineNumber = 0; lineNumber <= viewLineCount + 1; lineNumber++) {
|
||||
let lineMinColumn = linesCollection.getViewLineMinColumn(lineNumber);
|
||||
let lineMaxColumn = linesCollection.getViewLineMaxColumn(lineNumber);
|
||||
for (let column = lineMinColumn - 1; column <= lineMaxColumn + 1; column++) {
|
||||
let modelPosition = linesCollection.convertViewPositionToModelPosition(lineNumber, column);
|
||||
let validModelPosition = model.validatePosition(modelPosition);
|
||||
assert.equal(modelPosition.toString(), validModelPosition.toString(), 'view->model for ' + lineNumber + ', ' + column);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
suite('SplitLinesCollection', () => {
|
||||
|
||||
const _text = [
|
||||
'class Nice {',
|
||||
' function hi() {',
|
||||
' console.log("Hello world");',
|
||||
' }',
|
||||
' function hello() {',
|
||||
' console.log("Hello world, this is a somewhat longer line");',
|
||||
' }',
|
||||
'}',
|
||||
];
|
||||
|
||||
const _tokens = [
|
||||
[
|
||||
{ startIndex: 0, value: 1 },
|
||||
{ startIndex: 5, value: 2 },
|
||||
{ startIndex: 6, value: 3 },
|
||||
{ startIndex: 10, value: 4 },
|
||||
],
|
||||
[
|
||||
{ startIndex: 0, value: 5 },
|
||||
{ startIndex: 1, value: 6 },
|
||||
{ startIndex: 9, value: 7 },
|
||||
{ startIndex: 10, value: 8 },
|
||||
{ startIndex: 12, value: 9 },
|
||||
],
|
||||
[
|
||||
{ startIndex: 0, value: 10 },
|
||||
{ startIndex: 2, value: 11 },
|
||||
{ startIndex: 9, value: 12 },
|
||||
{ startIndex: 10, value: 13 },
|
||||
{ startIndex: 13, value: 14 },
|
||||
{ startIndex: 14, value: 15 },
|
||||
{ startIndex: 27, value: 16 },
|
||||
],
|
||||
[
|
||||
{ startIndex: 0, value: 17 },
|
||||
],
|
||||
[
|
||||
{ startIndex: 0, value: 18 },
|
||||
{ startIndex: 1, value: 19 },
|
||||
{ startIndex: 9, value: 20 },
|
||||
{ startIndex: 10, value: 21 },
|
||||
{ startIndex: 15, value: 22 },
|
||||
],
|
||||
[
|
||||
{ startIndex: 0, value: 23 },
|
||||
{ startIndex: 2, value: 24 },
|
||||
{ startIndex: 9, value: 25 },
|
||||
{ startIndex: 10, value: 26 },
|
||||
{ startIndex: 13, value: 27 },
|
||||
{ startIndex: 14, value: 28 },
|
||||
{ startIndex: 59, value: 29 },
|
||||
],
|
||||
[
|
||||
{ startIndex: 0, value: 30 },
|
||||
],
|
||||
[
|
||||
{ startIndex: 0, value: 31 },
|
||||
]
|
||||
];
|
||||
|
||||
let model: Model = null;
|
||||
let languageRegistration: IDisposable = null;
|
||||
|
||||
setup(() => {
|
||||
let _lineIndex = 0;
|
||||
const tokenizationSupport: modes.ITokenizationSupport = {
|
||||
getInitialState: () => NULL_STATE,
|
||||
tokenize: undefined,
|
||||
tokenize2: (line: string, state: modes.IState): TokenizationResult2 => {
|
||||
let tokens = _tokens[_lineIndex++];
|
||||
|
||||
let result = new Uint32Array(2 * tokens.length);
|
||||
for (let i = 0; i < tokens.length; i++) {
|
||||
result[2 * i] = tokens[i].startIndex;
|
||||
result[2 * i + 1] = (
|
||||
tokens[i].value << modes.MetadataConsts.FOREGROUND_OFFSET
|
||||
);
|
||||
}
|
||||
return new TokenizationResult2(result, state);
|
||||
}
|
||||
};
|
||||
const LANGUAGE_ID = 'modelModeTest1';
|
||||
languageRegistration = modes.TokenizationRegistry.register(LANGUAGE_ID, tokenizationSupport);
|
||||
model = Model.createFromString(_text.join('\n'), undefined, new modes.LanguageIdentifier(LANGUAGE_ID, 0));
|
||||
// force tokenization
|
||||
model.forceTokenization(model.getLineCount());
|
||||
});
|
||||
|
||||
teardown(() => {
|
||||
model.dispose();
|
||||
model = null;
|
||||
languageRegistration.dispose();
|
||||
languageRegistration = null;
|
||||
});
|
||||
|
||||
|
||||
interface ITestViewLineToken {
|
||||
endIndex: number;
|
||||
value: number;
|
||||
}
|
||||
|
||||
function assertViewLineTokens(actual: ViewLineToken[], expected: ITestViewLineToken[]): void {
|
||||
let _actual = actual.map((token) => {
|
||||
return {
|
||||
endIndex: token.endIndex,
|
||||
value: token.getForeground()
|
||||
};
|
||||
});
|
||||
assert.deepEqual(_actual, expected);
|
||||
}
|
||||
|
||||
interface ITestMinimapLineRenderingData {
|
||||
content: string;
|
||||
minColumn: number;
|
||||
maxColumn: number;
|
||||
tokens: ITestViewLineToken[];
|
||||
}
|
||||
|
||||
function assertMinimapLineRenderingData(actual: ViewLineData, expected: ITestMinimapLineRenderingData): void {
|
||||
if (actual === null && expected === null) {
|
||||
assert.ok(true);
|
||||
return;
|
||||
}
|
||||
assert.equal(actual.content, expected.content);
|
||||
assert.equal(actual.minColumn, expected.minColumn);
|
||||
assert.equal(actual.maxColumn, expected.maxColumn);
|
||||
assertViewLineTokens(actual.tokens, expected.tokens);
|
||||
}
|
||||
|
||||
function assertMinimapLinesRenderingData(actual: ViewLineData[], expected: ITestMinimapLineRenderingData[]): void {
|
||||
assert.equal(actual.length, expected.length);
|
||||
for (let i = 0; i < expected.length; i++) {
|
||||
assertMinimapLineRenderingData(actual[i], expected[i]);
|
||||
}
|
||||
}
|
||||
|
||||
function assertAllMinimapLinesRenderingData(splitLinesCollection: SplitLinesCollection, all: ITestMinimapLineRenderingData[]): void {
|
||||
let lineCount = all.length;
|
||||
for (let start = 1; start <= lineCount; start++) {
|
||||
for (let end = start; end <= lineCount; end++) {
|
||||
let count = end - start + 1;
|
||||
for (let desired = Math.pow(2, count) - 1; desired >= 0; desired--) {
|
||||
let needed: boolean[] = [];
|
||||
let expected: ITestMinimapLineRenderingData[] = [];
|
||||
for (let i = 0; i < count; i++) {
|
||||
needed[i] = (desired & (1 << i)) ? true : false;
|
||||
expected[i] = (needed[i] ? all[start - 1 + i] : null);
|
||||
}
|
||||
let actual = splitLinesCollection.getViewLinesData(start, end, needed);
|
||||
assertMinimapLinesRenderingData(actual, expected);
|
||||
// Comment out next line to test all possible combinations
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test('getViewLinesData - no wrapping', () => {
|
||||
withSplitLinesCollection(model, 'off', 0, (splitLinesCollection) => {
|
||||
assert.equal(splitLinesCollection.getViewLineCount(), 8);
|
||||
assert.equal(splitLinesCollection.modelPositionIsVisible(1, 1), true);
|
||||
assert.equal(splitLinesCollection.modelPositionIsVisible(2, 1), true);
|
||||
assert.equal(splitLinesCollection.modelPositionIsVisible(3, 1), true);
|
||||
assert.equal(splitLinesCollection.modelPositionIsVisible(4, 1), true);
|
||||
assert.equal(splitLinesCollection.modelPositionIsVisible(5, 1), true);
|
||||
assert.equal(splitLinesCollection.modelPositionIsVisible(6, 1), true);
|
||||
assert.equal(splitLinesCollection.modelPositionIsVisible(7, 1), true);
|
||||
assert.equal(splitLinesCollection.modelPositionIsVisible(8, 1), true);
|
||||
|
||||
let _expected: ITestMinimapLineRenderingData[] = [
|
||||
{
|
||||
content: 'class Nice {',
|
||||
minColumn: 1,
|
||||
maxColumn: 13,
|
||||
tokens: [
|
||||
{ endIndex: 5, value: 1 },
|
||||
{ endIndex: 6, value: 2 },
|
||||
{ endIndex: 10, value: 3 },
|
||||
{ endIndex: 12, value: 4 },
|
||||
]
|
||||
},
|
||||
{
|
||||
content: ' function hi() {',
|
||||
minColumn: 1,
|
||||
maxColumn: 17,
|
||||
tokens: [
|
||||
{ endIndex: 1, value: 5 },
|
||||
{ endIndex: 9, value: 6 },
|
||||
{ endIndex: 10, value: 7 },
|
||||
{ endIndex: 12, value: 8 },
|
||||
{ endIndex: 16, value: 9 },
|
||||
]
|
||||
},
|
||||
{
|
||||
content: ' console.log("Hello world");',
|
||||
minColumn: 1,
|
||||
maxColumn: 30,
|
||||
tokens: [
|
||||
{ endIndex: 2, value: 10 },
|
||||
{ endIndex: 9, value: 11 },
|
||||
{ endIndex: 10, value: 12 },
|
||||
{ endIndex: 13, value: 13 },
|
||||
{ endIndex: 14, value: 14 },
|
||||
{ endIndex: 27, value: 15 },
|
||||
{ endIndex: 29, value: 16 },
|
||||
]
|
||||
},
|
||||
{
|
||||
content: ' }',
|
||||
minColumn: 1,
|
||||
maxColumn: 3,
|
||||
tokens: [
|
||||
{ endIndex: 2, value: 17 },
|
||||
]
|
||||
},
|
||||
{
|
||||
content: ' function hello() {',
|
||||
minColumn: 1,
|
||||
maxColumn: 20,
|
||||
tokens: [
|
||||
{ endIndex: 1, value: 18 },
|
||||
{ endIndex: 9, value: 19 },
|
||||
{ endIndex: 10, value: 20 },
|
||||
{ endIndex: 15, value: 21 },
|
||||
{ endIndex: 19, value: 22 },
|
||||
]
|
||||
},
|
||||
{
|
||||
content: ' console.log("Hello world, this is a somewhat longer line");',
|
||||
minColumn: 1,
|
||||
maxColumn: 62,
|
||||
tokens: [
|
||||
{ endIndex: 2, value: 23 },
|
||||
{ endIndex: 9, value: 24 },
|
||||
{ endIndex: 10, value: 25 },
|
||||
{ endIndex: 13, value: 26 },
|
||||
{ endIndex: 14, value: 27 },
|
||||
{ endIndex: 59, value: 28 },
|
||||
{ endIndex: 61, value: 29 },
|
||||
]
|
||||
},
|
||||
{
|
||||
minColumn: 1,
|
||||
maxColumn: 3,
|
||||
content: ' }',
|
||||
tokens: [
|
||||
{ endIndex: 2, value: 30 },
|
||||
]
|
||||
},
|
||||
{
|
||||
minColumn: 1,
|
||||
maxColumn: 2,
|
||||
content: '}',
|
||||
tokens: [
|
||||
{ endIndex: 1, value: 31 },
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
assertAllMinimapLinesRenderingData(splitLinesCollection, [
|
||||
_expected[0],
|
||||
_expected[1],
|
||||
_expected[2],
|
||||
_expected[3],
|
||||
_expected[4],
|
||||
_expected[5],
|
||||
_expected[6],
|
||||
_expected[7],
|
||||
]);
|
||||
|
||||
splitLinesCollection.setHiddenAreas([new Range(2, 1, 4, 1)]);
|
||||
assert.equal(splitLinesCollection.getViewLineCount(), 5);
|
||||
assert.equal(splitLinesCollection.modelPositionIsVisible(1, 1), true);
|
||||
assert.equal(splitLinesCollection.modelPositionIsVisible(2, 1), false);
|
||||
assert.equal(splitLinesCollection.modelPositionIsVisible(3, 1), false);
|
||||
assert.equal(splitLinesCollection.modelPositionIsVisible(4, 1), false);
|
||||
assert.equal(splitLinesCollection.modelPositionIsVisible(5, 1), true);
|
||||
assert.equal(splitLinesCollection.modelPositionIsVisible(6, 1), true);
|
||||
assert.equal(splitLinesCollection.modelPositionIsVisible(7, 1), true);
|
||||
assert.equal(splitLinesCollection.modelPositionIsVisible(8, 1), true);
|
||||
|
||||
assertAllMinimapLinesRenderingData(splitLinesCollection, [
|
||||
_expected[0],
|
||||
_expected[4],
|
||||
_expected[5],
|
||||
_expected[6],
|
||||
_expected[7],
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
test('getViewLinesData - with wrapping', () => {
|
||||
withSplitLinesCollection(model, 'wordWrapColumn', 30, (splitLinesCollection) => {
|
||||
assert.equal(splitLinesCollection.getViewLineCount(), 12);
|
||||
assert.equal(splitLinesCollection.modelPositionIsVisible(1, 1), true);
|
||||
assert.equal(splitLinesCollection.modelPositionIsVisible(2, 1), true);
|
||||
assert.equal(splitLinesCollection.modelPositionIsVisible(3, 1), true);
|
||||
assert.equal(splitLinesCollection.modelPositionIsVisible(4, 1), true);
|
||||
assert.equal(splitLinesCollection.modelPositionIsVisible(5, 1), true);
|
||||
assert.equal(splitLinesCollection.modelPositionIsVisible(6, 1), true);
|
||||
assert.equal(splitLinesCollection.modelPositionIsVisible(7, 1), true);
|
||||
assert.equal(splitLinesCollection.modelPositionIsVisible(8, 1), true);
|
||||
|
||||
let _expected: ITestMinimapLineRenderingData[] = [
|
||||
{
|
||||
content: 'class Nice {',
|
||||
minColumn: 1,
|
||||
maxColumn: 13,
|
||||
tokens: [
|
||||
{ endIndex: 5, value: 1 },
|
||||
{ endIndex: 6, value: 2 },
|
||||
{ endIndex: 10, value: 3 },
|
||||
{ endIndex: 12, value: 4 },
|
||||
]
|
||||
},
|
||||
{
|
||||
content: ' function hi() {',
|
||||
minColumn: 1,
|
||||
maxColumn: 17,
|
||||
tokens: [
|
||||
{ endIndex: 1, value: 5 },
|
||||
{ endIndex: 9, value: 6 },
|
||||
{ endIndex: 10, value: 7 },
|
||||
{ endIndex: 12, value: 8 },
|
||||
{ endIndex: 16, value: 9 },
|
||||
]
|
||||
},
|
||||
{
|
||||
content: ' console.log("Hello ',
|
||||
minColumn: 1,
|
||||
maxColumn: 22,
|
||||
tokens: [
|
||||
{ endIndex: 2, value: 10 },
|
||||
{ endIndex: 9, value: 11 },
|
||||
{ endIndex: 10, value: 12 },
|
||||
{ endIndex: 13, value: 13 },
|
||||
{ endIndex: 14, value: 14 },
|
||||
{ endIndex: 21, value: 15 },
|
||||
]
|
||||
},
|
||||
{
|
||||
content: ' world");',
|
||||
minColumn: 4,
|
||||
maxColumn: 12,
|
||||
tokens: [
|
||||
{ endIndex: 9, value: 15 },
|
||||
{ endIndex: 11, value: 16 },
|
||||
]
|
||||
},
|
||||
{
|
||||
content: ' }',
|
||||
minColumn: 1,
|
||||
maxColumn: 3,
|
||||
tokens: [
|
||||
{ endIndex: 2, value: 17 },
|
||||
]
|
||||
},
|
||||
{
|
||||
content: ' function hello() {',
|
||||
minColumn: 1,
|
||||
maxColumn: 20,
|
||||
tokens: [
|
||||
{ endIndex: 1, value: 18 },
|
||||
{ endIndex: 9, value: 19 },
|
||||
{ endIndex: 10, value: 20 },
|
||||
{ endIndex: 15, value: 21 },
|
||||
{ endIndex: 19, value: 22 },
|
||||
]
|
||||
},
|
||||
{
|
||||
content: ' console.log("Hello ',
|
||||
minColumn: 1,
|
||||
maxColumn: 22,
|
||||
tokens: [
|
||||
{ endIndex: 2, value: 23 },
|
||||
{ endIndex: 9, value: 24 },
|
||||
{ endIndex: 10, value: 25 },
|
||||
{ endIndex: 13, value: 26 },
|
||||
{ endIndex: 14, value: 27 },
|
||||
{ endIndex: 21, value: 28 },
|
||||
]
|
||||
},
|
||||
{
|
||||
content: ' world, this is a ',
|
||||
minColumn: 4,
|
||||
maxColumn: 21,
|
||||
tokens: [
|
||||
{ endIndex: 20, value: 28 },
|
||||
]
|
||||
},
|
||||
{
|
||||
content: ' somewhat longer ',
|
||||
minColumn: 4,
|
||||
maxColumn: 20,
|
||||
tokens: [
|
||||
{ endIndex: 19, value: 28 },
|
||||
]
|
||||
},
|
||||
{
|
||||
content: ' line");',
|
||||
minColumn: 4,
|
||||
maxColumn: 11,
|
||||
tokens: [
|
||||
{ endIndex: 8, value: 28 },
|
||||
{ endIndex: 10, value: 29 },
|
||||
]
|
||||
},
|
||||
{
|
||||
content: ' }',
|
||||
minColumn: 1,
|
||||
maxColumn: 3,
|
||||
tokens: [
|
||||
{ endIndex: 2, value: 30 },
|
||||
]
|
||||
},
|
||||
{
|
||||
content: '}',
|
||||
minColumn: 1,
|
||||
maxColumn: 2,
|
||||
tokens: [
|
||||
{ endIndex: 1, value: 31 },
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
assertAllMinimapLinesRenderingData(splitLinesCollection, [
|
||||
_expected[0],
|
||||
_expected[1],
|
||||
_expected[2],
|
||||
_expected[3],
|
||||
_expected[4],
|
||||
_expected[5],
|
||||
_expected[6],
|
||||
_expected[7],
|
||||
_expected[8],
|
||||
_expected[9],
|
||||
_expected[10],
|
||||
_expected[11],
|
||||
]);
|
||||
|
||||
splitLinesCollection.setHiddenAreas([new Range(2, 1, 4, 1)]);
|
||||
assert.equal(splitLinesCollection.getViewLineCount(), 8);
|
||||
assert.equal(splitLinesCollection.modelPositionIsVisible(1, 1), true);
|
||||
assert.equal(splitLinesCollection.modelPositionIsVisible(2, 1), false);
|
||||
assert.equal(splitLinesCollection.modelPositionIsVisible(3, 1), false);
|
||||
assert.equal(splitLinesCollection.modelPositionIsVisible(4, 1), false);
|
||||
assert.equal(splitLinesCollection.modelPositionIsVisible(5, 1), true);
|
||||
assert.equal(splitLinesCollection.modelPositionIsVisible(6, 1), true);
|
||||
assert.equal(splitLinesCollection.modelPositionIsVisible(7, 1), true);
|
||||
assert.equal(splitLinesCollection.modelPositionIsVisible(8, 1), true);
|
||||
|
||||
assertAllMinimapLinesRenderingData(splitLinesCollection, [
|
||||
_expected[0],
|
||||
_expected[5],
|
||||
_expected[6],
|
||||
_expected[7],
|
||||
_expected[8],
|
||||
_expected[9],
|
||||
_expected[10],
|
||||
_expected[11],
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
function withSplitLinesCollection(model: Model, wordWrap: 'on' | 'off' | 'wordWrapColumn' | 'bounded', wordWrapColumn: number, callback: (splitLinesCollection: SplitLinesCollection) => void): void {
|
||||
let configuration = new TestConfiguration({
|
||||
wordWrap: wordWrap,
|
||||
wordWrapColumn: wordWrapColumn,
|
||||
wrappingIndent: 'indent'
|
||||
});
|
||||
|
||||
let factory = new CharacterHardWrappingLineMapperFactory(
|
||||
configuration.editor.wrappingInfo.wordWrapBreakBeforeCharacters,
|
||||
configuration.editor.wrappingInfo.wordWrapBreakAfterCharacters,
|
||||
configuration.editor.wrappingInfo.wordWrapBreakObtrusiveCharacters
|
||||
);
|
||||
|
||||
let linesCollection = new SplitLinesCollection(
|
||||
model,
|
||||
factory,
|
||||
model.getOptions().tabSize,
|
||||
configuration.editor.wrappingInfo.wrappingColumn,
|
||||
configuration.editor.fontInfo.typicalFullwidthCharacterWidth / configuration.editor.fontInfo.typicalHalfwidthCharacterWidth,
|
||||
configuration.editor.wrappingInfo.wrappingIndent
|
||||
);
|
||||
|
||||
callback(linesCollection);
|
||||
|
||||
configuration.dispose();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
function pos(lineNumber: number, column: number): Position {
|
||||
return new Position(lineNumber, column);
|
||||
}
|
||||
|
||||
function createSplitLine(splitLengths: number[], wrappedLinesPrefix: string, isVisible: boolean = true): SplitLine {
|
||||
return new SplitLine(createLineMapping(splitLengths, wrappedLinesPrefix), isVisible);
|
||||
}
|
||||
|
||||
function createLineMapping(breakingLengths: number[], wrappedLinesPrefix: string): ILineMapping {
|
||||
return new CharacterHardWrappingLineMapping(
|
||||
new PrefixSumComputer(toUint32Array(breakingLengths)),
|
||||
wrappedLinesPrefix
|
||||
);
|
||||
}
|
||||
|
||||
function createModel(text: string): IModel {
|
||||
return {
|
||||
getLineTokens: (lineNumber: number) => {
|
||||
return null;
|
||||
},
|
||||
getLineContent: (lineNumber: number) => {
|
||||
return text;
|
||||
},
|
||||
getLineMinColumn: (lineNumber: number) => {
|
||||
return 1;
|
||||
},
|
||||
getLineMaxColumn: (lineNumber: number) => {
|
||||
return text.length + 1;
|
||||
}
|
||||
};
|
||||
}
|
||||
26
src/vs/editor/test/common/viewModel/testViewModel.ts
Normal file
26
src/vs/editor/test/common/viewModel/testViewModel.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { Model } from 'vs/editor/common/model/model';
|
||||
import { TestConfiguration } from 'vs/editor/test/common/mocks/testConfiguration';
|
||||
import { ViewModel } from 'vs/editor/common/viewModel/viewModelImpl';
|
||||
import { MockCodeEditorCreationOptions } from 'vs/editor/test/common/mocks/mockCodeEditor';
|
||||
|
||||
export function testViewModel(text: string[], options: MockCodeEditorCreationOptions, callback: (viewModel: ViewModel, model: Model) => void): void {
|
||||
const EDITOR_ID = 1;
|
||||
|
||||
let configuration = new TestConfiguration(options);
|
||||
|
||||
let model = Model.createFromString(text.join('\n'));
|
||||
|
||||
let viewModel = new ViewModel(EDITOR_ID, configuration, model, null);
|
||||
|
||||
callback(viewModel, model);
|
||||
|
||||
viewModel.dispose();
|
||||
model.dispose();
|
||||
configuration.dispose();
|
||||
}
|
||||
311
src/vs/editor/test/common/viewModel/viewModelDecorations.test.ts
Normal file
311
src/vs/editor/test/common/viewModel/viewModelDecorations.test.ts
Normal file
@@ -0,0 +1,311 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { testViewModel } from 'vs/editor/test/common/viewModel/testViewModel';
|
||||
import { MockCodeEditorCreationOptions } from 'vs/editor/test/common/mocks/mockCodeEditor';
|
||||
|
||||
suite('ViewModelDecorations', () => {
|
||||
test('getDecorationsViewportData', () => {
|
||||
const text = [
|
||||
'hello world, this is a buffer that will be wrapped'
|
||||
];
|
||||
const opts: MockCodeEditorCreationOptions = {
|
||||
wordWrap: 'wordWrapColumn',
|
||||
wordWrapColumn: 13
|
||||
};
|
||||
testViewModel(text, opts, (viewModel, model) => {
|
||||
assert.equal(viewModel.getLineContent(1), 'hello world, ');
|
||||
assert.equal(viewModel.getLineContent(2), 'this is a ');
|
||||
assert.equal(viewModel.getLineContent(3), 'buffer that ');
|
||||
assert.equal(viewModel.getLineContent(4), 'will be ');
|
||||
assert.equal(viewModel.getLineContent(5), 'wrapped');
|
||||
|
||||
let dec1: string;
|
||||
let dec2: string;
|
||||
let dec3: string;
|
||||
let dec4: string;
|
||||
let dec5: string;
|
||||
let dec6: string;
|
||||
let dec7: string;
|
||||
let dec8: string;
|
||||
let dec9: string;
|
||||
let dec10: string;
|
||||
let dec11: string;
|
||||
let dec12: string;
|
||||
let dec13: string;
|
||||
let dec14: string;
|
||||
let dec15: string;
|
||||
model.changeDecorations((accessor) => {
|
||||
let createOpts = (id: string) => {
|
||||
return {
|
||||
className: id,
|
||||
inlineClassName: 'i-' + id,
|
||||
beforeContentClassName: 'b-' + id,
|
||||
afterContentClassName: 'a-' + id
|
||||
};
|
||||
};
|
||||
|
||||
// VIEWPORT will be (1,14) -> (1,36)
|
||||
|
||||
// completely before viewport
|
||||
dec1 = accessor.addDecoration(new Range(1, 2, 1, 3), createOpts('dec1'));
|
||||
// starts before viewport, ends at viewport start
|
||||
dec2 = accessor.addDecoration(new Range(1, 2, 1, 14), createOpts('dec2'));
|
||||
// starts before viewport, ends inside viewport
|
||||
dec3 = accessor.addDecoration(new Range(1, 2, 1, 15), createOpts('dec3'));
|
||||
// starts before viewport, ends at viewport end
|
||||
dec4 = accessor.addDecoration(new Range(1, 2, 1, 36), createOpts('dec4'));
|
||||
// starts before viewport, ends after viewport
|
||||
dec5 = accessor.addDecoration(new Range(1, 2, 1, 51), createOpts('dec5'));
|
||||
|
||||
// starts at viewport start, ends at viewport start
|
||||
dec6 = accessor.addDecoration(new Range(1, 14, 1, 14), createOpts('dec6'));
|
||||
// starts at viewport start, ends inside viewport
|
||||
dec7 = accessor.addDecoration(new Range(1, 14, 1, 16), createOpts('dec7'));
|
||||
// starts at viewport start, ends at viewport end
|
||||
dec8 = accessor.addDecoration(new Range(1, 14, 1, 36), createOpts('dec8'));
|
||||
// starts at viewport start, ends after viewport
|
||||
dec9 = accessor.addDecoration(new Range(1, 14, 1, 51), createOpts('dec9'));
|
||||
|
||||
// starts inside viewport, ends inside viewport
|
||||
dec10 = accessor.addDecoration(new Range(1, 16, 1, 18), createOpts('dec10'));
|
||||
// starts inside viewport, ends at viewport end
|
||||
dec11 = accessor.addDecoration(new Range(1, 16, 1, 36), createOpts('dec11'));
|
||||
// starts inside viewport, ends after viewport
|
||||
dec12 = accessor.addDecoration(new Range(1, 16, 1, 51), createOpts('dec12'));
|
||||
|
||||
// starts at viewport end, ends at viewport end
|
||||
dec13 = accessor.addDecoration(new Range(1, 36, 1, 36), createOpts('dec13'));
|
||||
// starts at viewport end, ends after viewport
|
||||
dec14 = accessor.addDecoration(new Range(1, 36, 1, 51), createOpts('dec14'));
|
||||
|
||||
// starts after viewport, ends after viewport
|
||||
dec15 = accessor.addDecoration(new Range(1, 40, 1, 51), createOpts('dec15'));
|
||||
});
|
||||
|
||||
let actualDecorations = viewModel.getDecorationsInViewport(
|
||||
new Range(2, viewModel.getLineMinColumn(2), 3, viewModel.getLineMaxColumn(3))
|
||||
).map((dec) => {
|
||||
return dec.source.id;
|
||||
});
|
||||
|
||||
assert.deepEqual(actualDecorations, [
|
||||
dec2,
|
||||
dec3,
|
||||
dec4,
|
||||
dec5,
|
||||
dec6,
|
||||
dec7,
|
||||
dec8,
|
||||
dec9,
|
||||
dec10,
|
||||
dec11,
|
||||
dec12,
|
||||
dec13,
|
||||
dec14,
|
||||
]);
|
||||
|
||||
let inlineDecorations1 = viewModel.getViewLineRenderingData(
|
||||
new Range(2, viewModel.getLineMinColumn(2), 3, viewModel.getLineMaxColumn(3)),
|
||||
2
|
||||
).inlineDecorations;
|
||||
|
||||
// view line 2: (1,14 -> 1,24)
|
||||
assert.deepEqual(inlineDecorations1, [
|
||||
{
|
||||
range: new Range(1, 2, 2, 1),
|
||||
inlineClassName: 'i-dec2',
|
||||
insertsBeforeOrAfter: false
|
||||
},
|
||||
{
|
||||
range: new Range(1, 2, 2, 2),
|
||||
inlineClassName: 'i-dec3',
|
||||
insertsBeforeOrAfter: false
|
||||
},
|
||||
{
|
||||
range: new Range(2, 1, 2, 2),
|
||||
inlineClassName: 'a-dec3',
|
||||
insertsBeforeOrAfter: true
|
||||
},
|
||||
{
|
||||
range: new Range(1, 2, 4, 1),
|
||||
inlineClassName: 'i-dec4',
|
||||
insertsBeforeOrAfter: false
|
||||
},
|
||||
{
|
||||
range: new Range(1, 2, 5, 8),
|
||||
inlineClassName: 'i-dec5',
|
||||
insertsBeforeOrAfter: false
|
||||
},
|
||||
{
|
||||
range: new Range(2, 1, 2, 1),
|
||||
inlineClassName: 'i-dec6',
|
||||
insertsBeforeOrAfter: false
|
||||
},
|
||||
{
|
||||
range: new Range(2, 1, 2, 2),
|
||||
inlineClassName: 'b-dec6',
|
||||
insertsBeforeOrAfter: true
|
||||
},
|
||||
{
|
||||
range: new Range(2, 1, 2, 3),
|
||||
inlineClassName: 'i-dec7',
|
||||
insertsBeforeOrAfter: false
|
||||
},
|
||||
{
|
||||
range: new Range(2, 1, 2, 2),
|
||||
inlineClassName: 'b-dec7',
|
||||
insertsBeforeOrAfter: true
|
||||
},
|
||||
{
|
||||
range: new Range(2, 2, 2, 3),
|
||||
inlineClassName: 'a-dec7',
|
||||
insertsBeforeOrAfter: true
|
||||
},
|
||||
{
|
||||
range: new Range(2, 1, 4, 1),
|
||||
inlineClassName: 'i-dec8',
|
||||
insertsBeforeOrAfter: false
|
||||
},
|
||||
{
|
||||
range: new Range(2, 1, 2, 2),
|
||||
inlineClassName: 'b-dec8',
|
||||
insertsBeforeOrAfter: true
|
||||
},
|
||||
{
|
||||
range: new Range(2, 1, 5, 8),
|
||||
inlineClassName: 'i-dec9',
|
||||
insertsBeforeOrAfter: false
|
||||
},
|
||||
{
|
||||
range: new Range(2, 1, 2, 2),
|
||||
inlineClassName: 'b-dec9',
|
||||
insertsBeforeOrAfter: true
|
||||
},
|
||||
{
|
||||
range: new Range(2, 3, 2, 5),
|
||||
inlineClassName: 'i-dec10',
|
||||
insertsBeforeOrAfter: false
|
||||
},
|
||||
{
|
||||
range: new Range(2, 3, 2, 4),
|
||||
inlineClassName: 'b-dec10',
|
||||
insertsBeforeOrAfter: true
|
||||
},
|
||||
{
|
||||
range: new Range(2, 4, 2, 5),
|
||||
inlineClassName: 'a-dec10',
|
||||
insertsBeforeOrAfter: true
|
||||
},
|
||||
{
|
||||
range: new Range(2, 3, 4, 1),
|
||||
inlineClassName: 'i-dec11',
|
||||
insertsBeforeOrAfter: false
|
||||
},
|
||||
{
|
||||
range: new Range(2, 3, 2, 4),
|
||||
inlineClassName: 'b-dec11',
|
||||
insertsBeforeOrAfter: true
|
||||
},
|
||||
{
|
||||
range: new Range(2, 3, 5, 8),
|
||||
inlineClassName: 'i-dec12',
|
||||
insertsBeforeOrAfter: false
|
||||
},
|
||||
{
|
||||
range: new Range(2, 3, 2, 4),
|
||||
inlineClassName: 'b-dec12',
|
||||
insertsBeforeOrAfter: true
|
||||
},
|
||||
]);
|
||||
|
||||
let inlineDecorations2 = viewModel.getViewLineRenderingData(
|
||||
new Range(2, viewModel.getLineMinColumn(2), 3, viewModel.getLineMaxColumn(3)),
|
||||
3
|
||||
).inlineDecorations;
|
||||
|
||||
// view line 3 (24 -> 36)
|
||||
assert.deepEqual(inlineDecorations2, [
|
||||
{
|
||||
range: new Range(1, 2, 4, 1),
|
||||
inlineClassName: 'i-dec4',
|
||||
insertsBeforeOrAfter: false
|
||||
},
|
||||
{
|
||||
range: new Range(1, 2, 5, 8),
|
||||
inlineClassName: 'i-dec5',
|
||||
insertsBeforeOrAfter: false
|
||||
},
|
||||
{
|
||||
range: new Range(2, 1, 4, 1),
|
||||
inlineClassName: 'i-dec8',
|
||||
insertsBeforeOrAfter: false
|
||||
},
|
||||
{
|
||||
range: new Range(2, 1, 5, 8),
|
||||
inlineClassName: 'i-dec9',
|
||||
insertsBeforeOrAfter: false
|
||||
},
|
||||
{
|
||||
range: new Range(2, 3, 4, 1),
|
||||
inlineClassName: 'i-dec11',
|
||||
insertsBeforeOrAfter: false
|
||||
},
|
||||
{
|
||||
range: new Range(2, 3, 5, 8),
|
||||
inlineClassName: 'i-dec12',
|
||||
insertsBeforeOrAfter: false
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
test('issue #17208: Problem scrolling in 1.8.0', () => {
|
||||
const text = [
|
||||
'hello world, this is a buffer that will be wrapped'
|
||||
];
|
||||
const opts: MockCodeEditorCreationOptions = {
|
||||
wordWrap: 'wordWrapColumn',
|
||||
wordWrapColumn: 13
|
||||
};
|
||||
testViewModel(text, opts, (viewModel, model) => {
|
||||
assert.equal(viewModel.getLineContent(1), 'hello world, ');
|
||||
assert.equal(viewModel.getLineContent(2), 'this is a ');
|
||||
assert.equal(viewModel.getLineContent(3), 'buffer that ');
|
||||
assert.equal(viewModel.getLineContent(4), 'will be ');
|
||||
assert.equal(viewModel.getLineContent(5), 'wrapped');
|
||||
|
||||
let dec1: string;
|
||||
model.changeDecorations((accessor) => {
|
||||
dec1 = accessor.addDecoration(
|
||||
new Range(1, 50, 1, 51),
|
||||
{
|
||||
beforeContentClassName: 'dec1'
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
let decorations = viewModel.getDecorationsInViewport(
|
||||
new Range(2, viewModel.getLineMinColumn(2), 3, viewModel.getLineMaxColumn(3))
|
||||
);
|
||||
assert.deepEqual(decorations, []);
|
||||
|
||||
let inlineDecorations1 = viewModel.getViewLineRenderingData(
|
||||
new Range(2, viewModel.getLineMinColumn(2), 3, viewModel.getLineMaxColumn(3)),
|
||||
2
|
||||
).inlineDecorations;
|
||||
assert.deepEqual(inlineDecorations1, []);
|
||||
|
||||
let inlineDecorations2 = viewModel.getViewLineRenderingData(
|
||||
new Range(2, viewModel.getLineMinColumn(2), 3, viewModel.getLineMaxColumn(3)),
|
||||
3
|
||||
).inlineDecorations;
|
||||
assert.deepEqual(inlineDecorations2, []);
|
||||
});
|
||||
});
|
||||
});
|
||||
44
src/vs/editor/test/common/viewModel/viewModelImpl.test.ts
Normal file
44
src/vs/editor/test/common/viewModel/viewModelImpl.test.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { testViewModel } from 'vs/editor/test/common/viewModel/testViewModel';
|
||||
|
||||
suite('ViewModel', () => {
|
||||
|
||||
test('issue #21073: SplitLinesCollection: attempt to access a \'newer\' model', () => {
|
||||
const text = [''];
|
||||
const opts = {
|
||||
lineNumbersMinChars: 1
|
||||
};
|
||||
testViewModel(text, opts, (viewModel, model) => {
|
||||
assert.equal(viewModel.getLineCount(), 1);
|
||||
|
||||
viewModel.setViewport(1, 1, 1);
|
||||
|
||||
model.applyEdits([{
|
||||
identifier: null,
|
||||
range: new Range(1, 1, 1, 1),
|
||||
text: [
|
||||
'line01',
|
||||
'line02',
|
||||
'line03',
|
||||
'line04',
|
||||
'line05',
|
||||
'line06',
|
||||
'line07',
|
||||
'line08',
|
||||
'line09',
|
||||
'line10',
|
||||
].join('\n'),
|
||||
forceMoveMarkers: false
|
||||
}]);
|
||||
|
||||
assert.equal(viewModel.getLineCount(), 10);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user