Initial VS Code 1.19 source merge (#571)

* Initial 1.19 xcopy

* Fix yarn build

* Fix numerous build breaks

* Next batch of build break fixes

* More build break fixes

* Runtime breaks

* Additional post merge fixes

* Fix windows setup file

* Fix test failures.

* Update license header blocks to refer to source eula
This commit is contained in:
Karl Burtram
2018-01-28 23:37:17 -08:00
committed by GitHub
parent 9a1ac20710
commit 251ae01c3e
8009 changed files with 93378 additions and 35634 deletions

View File

@@ -1,94 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as assert from 'assert';
import { 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
};
}

View File

@@ -1,987 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as assert from 'assert';
import { 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);
});
}
});
});

View File

@@ -1,886 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as assert from 'assert';
import { 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 { withMockCodeEditor } from 'vs/editor/test/common/mocks/mockCodeEditor';
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 { Cursor } from 'vs/editor/common/controller/cursor';
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()));
});
}
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('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)]
);
});
});
suite('SideEditing', () => {
const LINES = [
'My First Line',
'My Second Line',
'Third Line'
];
function _runTest(selection: Selection, editRange: Range, editText: string, editForceMoveMarkers: boolean, expected: Selection, msg: string): void {
const model = Model.createFromString(LINES.join('\n'));
const config = new TestConfiguration(null);
const viewModel = new ViewModel(0, config, model, null);
const cursor = new Cursor(config, model, viewModel);
cursor.setSelections('tests', [selection]);
model.applyEdits([{ range: editRange, text: editText, forceMoveMarkers: editForceMoveMarkers, identifier: null }]);
const actual = cursor.getSelection();
assert.deepEqual(actual.toString(), expected.toString(), msg);
cursor.dispose();
viewModel.dispose();
config.dispose();
model.dispose();
}
function runTest(selection: Range, editRange: Range, editText: string, expected: Selection[][]): void {
const sel1 = new Selection(selection.startLineNumber, selection.startColumn, selection.endLineNumber, selection.endColumn);
_runTest(sel1, editRange, editText, false, expected[0][0], '0-0-regular-no-force');
_runTest(sel1, editRange, editText, true, expected[1][0], '1-0-regular-force');
// RTL selection
const sel2 = new Selection(selection.endLineNumber, selection.endColumn, selection.startLineNumber, selection.startColumn);
_runTest(sel2, editRange, editText, false, expected[0][1], '0-1-inverse-no-force');
_runTest(sel2, editRange, editText, true, expected[1][1], '1-1-inverse-force');
}
suite('insert', () => {
suite('collapsed sel', () => {
test('before', () => {
runTest(
new Range(1, 4, 1, 4),
new Range(1, 3, 1, 3), 'xx',
[
[new Selection(1, 6, 1, 6), new Selection(1, 6, 1, 6)],
[new Selection(1, 6, 1, 6), new Selection(1, 6, 1, 6)],
]
);
});
test('equal', () => {
runTest(
new Range(1, 4, 1, 4),
new Range(1, 4, 1, 4), 'xx',
[
[new Selection(1, 4, 1, 6), new Selection(1, 4, 1, 6)],
[new Selection(1, 6, 1, 6), new Selection(1, 6, 1, 6)],
]
);
});
test('after', () => {
runTest(
new Range(1, 4, 1, 4),
new Range(1, 5, 1, 5), 'xx',
[
[new Selection(1, 4, 1, 4), new Selection(1, 4, 1, 4)],
[new Selection(1, 4, 1, 4), new Selection(1, 4, 1, 4)],
]
);
});
});
suite('non-collapsed dec', () => {
test('before', () => {
runTest(
new Range(1, 4, 1, 9),
new Range(1, 3, 1, 3), 'xx',
[
[new Selection(1, 6, 1, 11), new Selection(1, 11, 1, 6)],
[new Selection(1, 6, 1, 11), new Selection(1, 11, 1, 6)],
]
);
});
test('start', () => {
runTest(
new Range(1, 4, 1, 9),
new Range(1, 4, 1, 4), 'xx',
[
[new Selection(1, 4, 1, 11), new Selection(1, 11, 1, 4)],
[new Selection(1, 6, 1, 11), new Selection(1, 11, 1, 6)],
]
);
});
test('inside', () => {
runTest(
new Range(1, 4, 1, 9),
new Range(1, 5, 1, 5), 'xx',
[
[new Selection(1, 4, 1, 11), new Selection(1, 11, 1, 4)],
[new Selection(1, 4, 1, 11), new Selection(1, 11, 1, 4)],
]
);
});
test('end', () => {
runTest(
new Range(1, 4, 1, 9),
new Range(1, 9, 1, 9), 'xx',
[
[new Selection(1, 4, 1, 11), new Selection(1, 11, 1, 4)],
[new Selection(1, 4, 1, 11), new Selection(1, 11, 1, 4)],
]
);
});
test('after', () => {
runTest(
new Range(1, 4, 1, 9),
new Range(1, 10, 1, 10), 'xx',
[
[new Selection(1, 4, 1, 9), new Selection(1, 9, 1, 4)],
[new Selection(1, 4, 1, 9), new Selection(1, 9, 1, 4)],
]
);
});
});
});
suite('delete', () => {
suite('collapsed dec', () => {
test('edit.end < range.start', () => {
runTest(
new Range(1, 4, 1, 4),
new Range(1, 1, 1, 3), '',
[
[new Selection(1, 2, 1, 2), new Selection(1, 2, 1, 2)],
[new Selection(1, 2, 1, 2), new Selection(1, 2, 1, 2)],
]
);
});
test('edit.end <= range.start', () => {
runTest(
new Range(1, 4, 1, 4),
new Range(1, 2, 1, 4), '',
[
[new Selection(1, 2, 1, 2), new Selection(1, 2, 1, 2)],
[new Selection(1, 2, 1, 2), new Selection(1, 2, 1, 2)],
]
);
});
test('edit.start < range.start && edit.end > range.end', () => {
runTest(
new Range(1, 4, 1, 4),
new Range(1, 3, 1, 5), '',
[
[new Selection(1, 3, 1, 3), new Selection(1, 3, 1, 3)],
[new Selection(1, 3, 1, 3), new Selection(1, 3, 1, 3)],
]
);
});
test('edit.start >= range.end', () => {
runTest(
new Range(1, 4, 1, 4),
new Range(1, 4, 1, 6), '',
[
[new Selection(1, 4, 1, 4), new Selection(1, 4, 1, 4)],
[new Selection(1, 4, 1, 4), new Selection(1, 4, 1, 4)],
]
);
});
test('edit.start > range.end', () => {
runTest(
new Range(1, 4, 1, 4),
new Range(1, 5, 1, 7), '',
[
[new Selection(1, 4, 1, 4), new Selection(1, 4, 1, 4)],
[new Selection(1, 4, 1, 4), new Selection(1, 4, 1, 4)],
]
);
});
});
suite('non-collapsed dec', () => {
test('edit.end < range.start', () => {
runTest(
new Range(1, 4, 1, 9),
new Range(1, 1, 1, 3), '',
[
[new Selection(1, 2, 1, 7), new Selection(1, 7, 1, 2)],
[new Selection(1, 2, 1, 7), new Selection(1, 7, 1, 2)],
]
);
});
test('edit.end <= range.start', () => {
runTest(
new Range(1, 4, 1, 9),
new Range(1, 2, 1, 4), '',
[
[new Selection(1, 2, 1, 7), new Selection(1, 7, 1, 2)],
[new Selection(1, 2, 1, 7), new Selection(1, 7, 1, 2)],
]
);
});
test('edit.start < range.start && edit.end < range.end', () => {
runTest(
new Range(1, 4, 1, 9),
new Range(1, 3, 1, 5), '',
[
[new Selection(1, 3, 1, 7), new Selection(1, 7, 1, 3)],
[new Selection(1, 3, 1, 7), new Selection(1, 7, 1, 3)],
]
);
});
test('edit.start < range.start && edit.end == range.end', () => {
runTest(
new Range(1, 4, 1, 9),
new Range(1, 3, 1, 9), '',
[
[new Selection(1, 3, 1, 3), new Selection(1, 3, 1, 3)],
[new Selection(1, 3, 1, 3), new Selection(1, 3, 1, 3)],
]
);
});
test('edit.start < range.start && edit.end > range.end', () => {
runTest(
new Range(1, 4, 1, 9),
new Range(1, 3, 1, 10), '',
[
[new Selection(1, 3, 1, 3), new Selection(1, 3, 1, 3)],
[new Selection(1, 3, 1, 3), new Selection(1, 3, 1, 3)],
]
);
});
test('edit.start == range.start && edit.end < range.end', () => {
runTest(
new Range(1, 4, 1, 9),
new Range(1, 4, 1, 6), '',
[
[new Selection(1, 4, 1, 7), new Selection(1, 7, 1, 4)],
[new Selection(1, 4, 1, 7), new Selection(1, 7, 1, 4)],
]
);
});
test('edit.start == range.start && edit.end == range.end', () => {
runTest(
new Range(1, 4, 1, 9),
new Range(1, 4, 1, 9), '',
[
[new Selection(1, 4, 1, 4), new Selection(1, 4, 1, 4)],
[new Selection(1, 4, 1, 4), new Selection(1, 4, 1, 4)],
]
);
});
test('edit.start == range.start && edit.end > range.end', () => {
runTest(
new Range(1, 4, 1, 9),
new Range(1, 4, 1, 10), '',
[
[new Selection(1, 4, 1, 4), new Selection(1, 4, 1, 4)],
[new Selection(1, 4, 1, 4), new Selection(1, 4, 1, 4)],
]
);
});
test('edit.start > range.start && edit.start < range.end && edit.end < range.end', () => {
runTest(
new Range(1, 4, 1, 9),
new Range(1, 5, 1, 7), '',
[
[new Selection(1, 4, 1, 7), new Selection(1, 7, 1, 4)],
[new Selection(1, 4, 1, 7), new Selection(1, 7, 1, 4)],
]
);
});
test('edit.start > range.start && edit.start < range.end && edit.end == range.end', () => {
runTest(
new Range(1, 4, 1, 9),
new Range(1, 5, 1, 9), '',
[
[new Selection(1, 4, 1, 5), new Selection(1, 5, 1, 4)],
[new Selection(1, 4, 1, 5), new Selection(1, 5, 1, 4)],
]
);
});
test('edit.start > range.start && edit.start < range.end && edit.end > range.end', () => {
runTest(
new Range(1, 4, 1, 9),
new Range(1, 5, 1, 10), '',
[
[new Selection(1, 4, 1, 5), new Selection(1, 5, 1, 4)],
[new Selection(1, 4, 1, 5), new Selection(1, 5, 1, 4)],
]
);
});
test('edit.start == range.end', () => {
runTest(
new Range(1, 4, 1, 9),
new Range(1, 9, 1, 11), '',
[
[new Selection(1, 4, 1, 9), new Selection(1, 9, 1, 4)],
[new Selection(1, 4, 1, 9), new Selection(1, 9, 1, 4)],
]
);
});
test('edit.start > range.end', () => {
runTest(
new Range(1, 4, 1, 9),
new Range(1, 10, 1, 11), '',
[
[new Selection(1, 4, 1, 9), new Selection(1, 9, 1, 4)],
[new Selection(1, 4, 1, 9), new Selection(1, 9, 1, 4)],
]
);
});
});
});
suite('replace short', () => {
suite('collapsed dec', () => {
test('edit.end < range.start', () => {
runTest(
new Range(1, 4, 1, 4),
new Range(1, 1, 1, 3), 'c',
[
[new Selection(1, 3, 1, 3), new Selection(1, 3, 1, 3)],
[new Selection(1, 3, 1, 3), new Selection(1, 3, 1, 3)],
]
);
});
test('edit.end <= range.start', () => {
runTest(
new Range(1, 4, 1, 4),
new Range(1, 2, 1, 4), 'c',
[
[new Selection(1, 3, 1, 3), new Selection(1, 3, 1, 3)],
[new Selection(1, 3, 1, 3), new Selection(1, 3, 1, 3)],
]
);
});
test('edit.start < range.start && edit.end > range.end', () => {
runTest(
new Range(1, 4, 1, 4),
new Range(1, 3, 1, 5), 'c',
[
[new Selection(1, 4, 1, 4), new Selection(1, 4, 1, 4)],
[new Selection(1, 4, 1, 4), new Selection(1, 4, 1, 4)],
]
);
});
test('edit.start >= range.end', () => {
runTest(
new Range(1, 4, 1, 4),
new Range(1, 4, 1, 6), 'c',
[
[new Selection(1, 4, 1, 4), new Selection(1, 4, 1, 4)],
[new Selection(1, 5, 1, 5), new Selection(1, 5, 1, 5)],
]
);
});
test('edit.start > range.end', () => {
runTest(
new Range(1, 4, 1, 4),
new Range(1, 5, 1, 7), 'c',
[
[new Selection(1, 4, 1, 4), new Selection(1, 4, 1, 4)],
[new Selection(1, 4, 1, 4), new Selection(1, 4, 1, 4)],
]
);
});
});
suite('non-collapsed dec', () => {
test('edit.end < range.start', () => {
runTest(
new Range(1, 4, 1, 9),
new Range(1, 1, 1, 3), 'c',
[
[new Selection(1, 3, 1, 8), new Selection(1, 8, 1, 3)],
[new Selection(1, 3, 1, 8), new Selection(1, 8, 1, 3)],
]
);
});
test('edit.end <= range.start', () => {
runTest(
new Range(1, 4, 1, 9),
new Range(1, 2, 1, 4), 'c',
[
[new Selection(1, 3, 1, 8), new Selection(1, 8, 1, 3)],
[new Selection(1, 3, 1, 8), new Selection(1, 8, 1, 3)],
]
);
});
test('edit.start < range.start && edit.end < range.end', () => {
runTest(
new Range(1, 4, 1, 9),
new Range(1, 3, 1, 5), 'c',
[
[new Selection(1, 4, 1, 8), new Selection(1, 8, 1, 4)],
[new Selection(1, 4, 1, 8), new Selection(1, 8, 1, 4)],
]
);
});
test('edit.start < range.start && edit.end == range.end', () => {
runTest(
new Range(1, 4, 1, 9),
new Range(1, 3, 1, 9), 'c',
[
[new Selection(1, 4, 1, 4), new Selection(1, 4, 1, 4)],
[new Selection(1, 4, 1, 4), new Selection(1, 4, 1, 4)],
]
);
});
test('edit.start < range.start && edit.end > range.end', () => {
runTest(
new Range(1, 4, 1, 9),
new Range(1, 3, 1, 10), 'c',
[
[new Selection(1, 4, 1, 4), new Selection(1, 4, 1, 4)],
[new Selection(1, 4, 1, 4), new Selection(1, 4, 1, 4)],
]
);
});
test('edit.start == range.start && edit.end < range.end', () => {
runTest(
new Range(1, 4, 1, 9),
new Range(1, 4, 1, 6), 'c',
[
[new Selection(1, 4, 1, 8), new Selection(1, 8, 1, 4)],
[new Selection(1, 5, 1, 8), new Selection(1, 8, 1, 5)],
]
);
});
test('edit.start == range.start && edit.end == range.end', () => {
runTest(
new Range(1, 4, 1, 9),
new Range(1, 4, 1, 9), 'c',
[
[new Selection(1, 4, 1, 5), new Selection(1, 5, 1, 4)],
[new Selection(1, 5, 1, 5), new Selection(1, 5, 1, 5)],
]
);
});
test('edit.start == range.start && edit.end > range.end', () => {
runTest(
new Range(1, 4, 1, 9),
new Range(1, 4, 1, 10), 'c',
[
[new Selection(1, 4, 1, 5), new Selection(1, 5, 1, 4)],
[new Selection(1, 5, 1, 5), new Selection(1, 5, 1, 5)],
]
);
});
test('edit.start > range.start && edit.start < range.end && edit.end < range.end', () => {
runTest(
new Range(1, 4, 1, 9),
new Range(1, 5, 1, 7), 'c',
[
[new Selection(1, 4, 1, 8), new Selection(1, 8, 1, 4)],
[new Selection(1, 4, 1, 8), new Selection(1, 8, 1, 4)],
]
);
});
test('edit.start > range.start && edit.start < range.end && edit.end == range.end', () => {
runTest(
new Range(1, 4, 1, 9),
new Range(1, 5, 1, 9), 'c',
[
[new Selection(1, 4, 1, 6), new Selection(1, 6, 1, 4)],
[new Selection(1, 4, 1, 6), new Selection(1, 6, 1, 4)],
]
);
});
test('edit.start > range.start && edit.start < range.end && edit.end > range.end', () => {
runTest(
new Range(1, 4, 1, 9),
new Range(1, 5, 1, 10), 'c',
[
[new Selection(1, 4, 1, 6), new Selection(1, 6, 1, 4)],
[new Selection(1, 4, 1, 6), new Selection(1, 6, 1, 4)],
]
);
});
test('edit.start == range.end', () => {
runTest(
new Range(1, 4, 1, 9),
new Range(1, 9, 1, 11), 'c',
[
[new Selection(1, 4, 1, 9), new Selection(1, 9, 1, 4)],
[new Selection(1, 4, 1, 10), new Selection(1, 10, 1, 4)],
]
);
});
test('edit.start > range.end', () => {
runTest(
new Range(1, 4, 1, 9),
new Range(1, 10, 1, 11), 'c',
[
[new Selection(1, 4, 1, 9), new Selection(1, 9, 1, 4)],
[new Selection(1, 4, 1, 9), new Selection(1, 9, 1, 4)],
]
);
});
});
});
suite('replace long', () => {
suite('collapsed dec', () => {
test('edit.end < range.start', () => {
runTest(
new Range(1, 4, 1, 4),
new Range(1, 1, 1, 3), 'cccc',
[
[new Selection(1, 6, 1, 6), new Selection(1, 6, 1, 6)],
[new Selection(1, 6, 1, 6), new Selection(1, 6, 1, 6)],
]
);
});
test('edit.end <= range.start', () => {
runTest(
new Range(1, 4, 1, 4),
new Range(1, 2, 1, 4), 'cccc',
[
[new Selection(1, 4, 1, 6), new Selection(1, 4, 1, 6)],
[new Selection(1, 6, 1, 6), new Selection(1, 6, 1, 6)],
]
);
});
test('edit.start < range.start && edit.end > range.end', () => {
runTest(
new Range(1, 4, 1, 4),
new Range(1, 3, 1, 5), 'cccc',
[
[new Selection(1, 4, 1, 4), new Selection(1, 4, 1, 4)],
[new Selection(1, 7, 1, 7), new Selection(1, 7, 1, 7)],
]
);
});
test('edit.start >= range.end', () => {
runTest(
new Range(1, 4, 1, 4),
new Range(1, 4, 1, 6), 'cccc',
[
[new Selection(1, 4, 1, 4), new Selection(1, 4, 1, 4)],
[new Selection(1, 8, 1, 8), new Selection(1, 8, 1, 8)],
]
);
});
test('edit.start > range.end', () => {
runTest(
new Range(1, 4, 1, 4),
new Range(1, 5, 1, 7), 'cccc',
[
[new Selection(1, 4, 1, 4), new Selection(1, 4, 1, 4)],
[new Selection(1, 4, 1, 4), new Selection(1, 4, 1, 4)],
]
);
});
});
suite('non-collapsed dec', () => {
test('edit.end < range.start', () => {
runTest(
new Range(1, 4, 1, 9),
new Range(1, 1, 1, 3), 'cccc',
[
[new Selection(1, 6, 1, 11), new Selection(1, 11, 1, 6)],
[new Selection(1, 6, 1, 11), new Selection(1, 11, 1, 6)],
]
);
});
test('edit.end <= range.start', () => {
runTest(
new Range(1, 4, 1, 9),
new Range(1, 2, 1, 4), 'cccc',
[
[new Selection(1, 4, 1, 11), new Selection(1, 11, 1, 4)],
[new Selection(1, 6, 1, 11), new Selection(1, 11, 1, 6)],
]
);
});
test('edit.start < range.start && edit.end < range.end', () => {
runTest(
new Range(1, 4, 1, 9),
new Range(1, 3, 1, 5), 'cccc',
[
[new Selection(1, 4, 1, 11), new Selection(1, 11, 1, 4)],
[new Selection(1, 7, 1, 11), new Selection(1, 11, 1, 7)],
]
);
});
test('edit.start < range.start && edit.end == range.end', () => {
runTest(
new Range(1, 4, 1, 9),
new Range(1, 3, 1, 9), 'cccc',
[
[new Selection(1, 4, 1, 7), new Selection(1, 7, 1, 4)],
[new Selection(1, 7, 1, 7), new Selection(1, 7, 1, 7)],
]
);
});
test('edit.start < range.start && edit.end > range.end', () => {
runTest(
new Range(1, 4, 1, 9),
new Range(1, 3, 1, 10), 'cccc',
[
[new Selection(1, 4, 1, 7), new Selection(1, 7, 1, 4)],
[new Selection(1, 7, 1, 7), new Selection(1, 7, 1, 7)],
]
);
});
test('edit.start == range.start && edit.end < range.end', () => {
runTest(
new Range(1, 4, 1, 9),
new Range(1, 4, 1, 6), 'cccc',
[
[new Selection(1, 4, 1, 11), new Selection(1, 11, 1, 4)],
[new Selection(1, 8, 1, 11), new Selection(1, 11, 1, 8)],
]
);
});
test('edit.start == range.start && edit.end == range.end', () => {
runTest(
new Range(1, 4, 1, 9),
new Range(1, 4, 1, 9), 'cccc',
[
[new Selection(1, 4, 1, 8), new Selection(1, 8, 1, 4)],
[new Selection(1, 8, 1, 8), new Selection(1, 8, 1, 8)],
]
);
});
test('edit.start == range.start && edit.end > range.end', () => {
runTest(
new Range(1, 4, 1, 9),
new Range(1, 4, 1, 10), 'cccc',
[
[new Selection(1, 4, 1, 8), new Selection(1, 8, 1, 4)],
[new Selection(1, 8, 1, 8), new Selection(1, 8, 1, 8)],
]
);
});
test('edit.start > range.start && edit.start < range.end && edit.end < range.end', () => {
runTest(
new Range(1, 4, 1, 9),
new Range(1, 5, 1, 7), 'cccc',
[
[new Selection(1, 4, 1, 11), new Selection(1, 11, 1, 4)],
[new Selection(1, 4, 1, 11), new Selection(1, 11, 1, 4)],
]
);
});
test('edit.start > range.start && edit.start < range.end && edit.end == range.end', () => {
runTest(
new Range(1, 4, 1, 9),
new Range(1, 5, 1, 9), 'cccc',
[
[new Selection(1, 4, 1, 9), new Selection(1, 9, 1, 4)],
[new Selection(1, 4, 1, 9), new Selection(1, 9, 1, 4)],
]
);
});
test('edit.start > range.start && edit.start < range.end && edit.end > range.end', () => {
runTest(
new Range(1, 4, 1, 9),
new Range(1, 5, 1, 10), 'cccc',
[
[new Selection(1, 4, 1, 9), new Selection(1, 9, 1, 4)],
[new Selection(1, 4, 1, 9), new Selection(1, 9, 1, 4)],
]
);
});
test('edit.start == range.end', () => {
runTest(
new Range(1, 4, 1, 9),
new Range(1, 9, 1, 11), 'cccc',
[
[new Selection(1, 4, 1, 9), new Selection(1, 9, 1, 4)],
[new Selection(1, 4, 1, 13), new Selection(1, 13, 1, 4)],
]
);
});
test('edit.start > range.end', () => {
runTest(
new Range(1, 4, 1, 9),
new Range(1, 10, 1, 11), 'cccc',
[
[new Selection(1, 4, 1, 9), new Selection(1, 9, 1, 4)],
[new Selection(1, 4, 1, 9), new Selection(1, 9, 1, 4)],
]
);
});
});
});
});

View File

@@ -1,82 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as assert from 'assert';
import { 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)
]);
});
});

View File

@@ -10,7 +10,7 @@ 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);
private static readonly _id = new LanguageIdentifier('commentMode', 3);
constructor(commentsConfig: CommentRule) {
super(CommentMode._id);

File diff suppressed because it is too large Load Diff

View File

@@ -1,512 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as assert from 'assert';
import { 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, {});
}
}

View File

@@ -1,104 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as assert from 'assert';
import 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
};
}
});

View File

@@ -50,7 +50,7 @@ suite('LineTokens', () => {
const lineTokens = createTestLineTokens();
assert.equal(lineTokens.getLineContent(), 'Hello world, this is a lovely day');
assert.equal(lineTokens.getLineLength(), 33);
assert.equal(lineTokens.getLineContent().length, 33);
assert.equal(lineTokens.getTokenCount(), 7);
assert.equal(lineTokens.getTokenStartOffset(0), 0);

View File

@@ -1,114 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { 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 {
public _isFocused = true;
protected _createConfiguration(options: editorOptions.IEditorOptions): CommonEditorConfiguration {
return new TestConfiguration(options);
}
public layout(dimension?: editorCommon.IDimension): void { }
public focus(): void { }
public isFocused(): boolean { return this._isFocused; }
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;
}

View File

@@ -1,14 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { 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; }
}

View File

@@ -12,6 +12,12 @@ import { EditableTextModel, IValidatedEditOperation } from 'vs/editor/common/mod
import { MirrorModel } from 'vs/editor/common/model/mirrorModel';
import { assertSyncedModels, testApplyEditsWithSyncedModels } from 'vs/editor/test/common/model/editableTextModelTestUtils';
import { IModelContentChangedEvent } from 'vs/editor/common/model/textModelEvents';
import { TextModel } from 'vs/editor/common/model/textModel';
import { RawTextSource } from 'vs/editor/common/model/textSource';
function createEditableTextModelFromString(text: string): EditableTextModel {
return new EditableTextModel(RawTextSource.fromString(text), TextModel.DEFAULT_CREATION_OPTIONS, null);
}
suite('EditorModel - EditableTextModel._getInverseEdits', () => {
@@ -280,7 +286,7 @@ suite('EditorModel - EditableTextModel._toSingleEditOperation', () => {
}
function testSimpleApplyEdits(original: string[], edits: IValidatedEditOperation[], expected: IValidatedEditOperation): void {
let model = EditableTextModel.createFromString(original.join('\n'));
let model = createEditableTextModelFromString(original.join('\n'));
model.setEOL(EndOfLineSequence.LF);
let actual = model._toSingleEditOperation(edits);
@@ -522,7 +528,7 @@ suite('EditorModel - EditableTextModel._toSingleEditOperation', () => {
suite('EditorModel - EditableTextModel.applyEdits updates mightContainRTL', () => {
function testApplyEdits(original: string[], edits: IIdentifiedSingleEditOperation[], before: boolean, after: boolean): void {
let model = EditableTextModel.createFromString(original.join('\n'));
let model = createEditableTextModelFromString(original.join('\n'));
model.setEOL(EndOfLineSequence.LF);
assert.equal(model.mightContainRTL(), before);
@@ -570,7 +576,7 @@ suite('EditorModel - EditableTextModel.applyEdits updates mightContainRTL', () =
suite('EditorModel - EditableTextModel.applyEdits updates mightContainNonBasicASCII', () => {
function testApplyEdits(original: string[], edits: IIdentifiedSingleEditOperation[], before: boolean, after: boolean): void {
let model = EditableTextModel.createFromString(original.join('\n'));
let model = createEditableTextModelFromString(original.join('\n'));
model.setEOL(EndOfLineSequence.LF);
assert.equal(model.mightContainNonBasicASCII(), before);
@@ -1365,7 +1371,7 @@ suite('EditorModel - EditableTextModel.applyEdits', () => {
});
function testApplyEditsFails(original: string[], edits: IIdentifiedSingleEditOperation[]): void {
let model = EditableTextModel.createFromString(original.join('\n'));
let model = createEditableTextModelFromString(original.join('\n'));
let hasThrown = false;
try {
@@ -1506,7 +1512,7 @@ suite('EditorModel - EditableTextModel.applyEdits', () => {
}, (model) => {
var isFirstTime = true;
model.addBulkListener((events) => {
model.onDidChangeRawContent(() => {
if (!isFirstTime) {
return;
}
@@ -1553,7 +1559,7 @@ suite('EditorModel - EditableTextModel.applyEdits', () => {
});
test('issue #1580: Changes in line endings are not correctly reflected in the extension host, leading to invalid offsets sent to external refactoring tools', () => {
let model = EditableTextModel.createFromString('Hello\nWorld!');
let model = createEditableTextModelFromString('Hello\nWorld!');
assert.equal(model.getEOL(), '\n');
let mirrorModel2 = new MirrorModel(null, model.getLinesContent(), model.getEOL(), model.getVersionId());

View File

@@ -1,388 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as assert from 'assert';
import { Model } from 'vs/editor/common/model/model';
import { computeRanges, MAX_FOLDING_REGIONS } from 'vs/editor/common/model/indentRanges';
import { FoldingMarkers } from 'vs/editor/common/modes/languageConfiguration';
export interface ExpectedIndentRange {
startLineNumber: number;
endLineNumber: number;
indent: number;
parentIndex: number;
}
function assertRanges(lines: string[], expected: ExpectedIndentRange[], offside: boolean, markers?: FoldingMarkers): void {
let model = Model.createFromString(lines.join('\n'));
let actual = computeRanges(model, offside, markers);
let actualRanges = [];
for (let i = 0; i < actual.length; i++) {
actualRanges[i] = r(actual.getStartLineNumber(i), actual.getEndLineNumber(i), actual.getIndent(i), actual.getParentIndex(i));
}
assert.deepEqual(actualRanges, expected);
model.dispose();
}
function r(startLineNumber: number, endLineNumber: number, indent: number, parentIndex: number, marker = false): ExpectedIndentRange {
return { startLineNumber, endLineNumber, indent, parentIndex };
}
suite('Indentation Folding', () => {
test('Fold one level', () => {
let range = [
'A',
' A',
' A',
' A'
];
assertRanges(range, [r(1, 4, 0, -1)], true);
assertRanges(range, [r(1, 4, 0, -1)], false);
});
test('Fold two levels', () => {
let range = [
'A',
' A',
' A',
' A',
' A'
];
assertRanges(range, [r(1, 5, 0, -1), r(3, 5, 2, 0)], true);
assertRanges(range, [r(1, 5, 0, -1), r(3, 5, 2, 0)], false);
});
test('Fold three levels', () => {
let range = [
'A',
' A',
' A',
' A',
'A'
];
assertRanges(range, [r(1, 4, 0, -1), r(2, 4, 2, 0), r(3, 4, 4, 1)], true);
assertRanges(range, [r(1, 4, 0, -1), r(2, 4, 2, 0), r(3, 4, 4, 1)], false);
});
test('Fold decreasing indent', () => {
let range = [
' A',
' A',
'A'
];
assertRanges(range, [], true);
assertRanges(range, [], false);
});
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, -1), r(2, 4, 2, 0), r(7, 8, 2, 0), r(11, 12, 0, -1)], false);
});
test('Fold Javadoc', () => {
assertRanges([
/* 1*/ '/**',
/* 2*/ ' * Comment',
/* 3*/ ' */',
/* 4*/ 'class A {',
/* 5*/ ' void foo() {',
/* 6*/ ' }',
/* 7*/ '}',
], [r(1, 3, 0, -1), r(4, 6, 0, -1)], false);
});
test('Fold Whitespace Java', () => {
assertRanges([
/* 1*/ 'class A {',
/* 2*/ '',
/* 3*/ ' void foo() {',
/* 4*/ ' ',
/* 5*/ ' return 0;',
/* 6*/ ' }',
/* 7*/ ' ',
/* 8*/ '}',
], [r(1, 7, 0, -1), r(3, 5, 2, 0)], false);
});
test('Fold Whitespace Python', () => {
assertRanges([
/* 1*/ 'def a:',
/* 2*/ ' pass',
/* 3*/ ' ',
/* 4*/ ' def b:',
/* 5*/ ' pass',
/* 6*/ ' ',
/* 7*/ ' ',
/* 8*/ 'def c: # since there was a deintent here'
], [r(1, 5, 0, -1), r(4, 5, 2, 0)], true);
});
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, -1), r(3, 5, 4, 0)], false);
});
});
let markers: FoldingMarkers = {
start: /^\s*#region\b/,
end: /^\s*#endregion\b/
};
suite('Folding with regions', () => {
test('Inside region, indented', () => {
assertRanges([
/* 1*/ 'class A {',
/* 2*/ ' #region',
/* 3*/ ' void foo() {',
/* 4*/ ' ',
/* 5*/ ' return 0;',
/* 6*/ ' }',
/* 7*/ ' #endregion',
/* 8*/ '}',
], [r(1, 7, 0, -1), r(2, 7, 2, 0, true), r(3, 5, 2, 1)], false, markers);
});
test('Inside region, not indented', () => {
assertRanges([
/* 1*/ 'var x;',
/* 2*/ '#region',
/* 3*/ 'void foo() {',
/* 4*/ ' ',
/* 5*/ ' return 0;',
/* 6*/ ' }',
/* 7*/ '#endregion',
/* 8*/ '',
], [r(2, 7, 0, -1, true), r(3, 6, 0, 0)], false, markers);
});
test('Empty Regions', () => {
assertRanges([
/* 1*/ 'var x;',
/* 2*/ '#region',
/* 3*/ '#endregion',
/* 4*/ '#region',
/* 5*/ '',
/* 6*/ '#endregion',
/* 7*/ 'var y;',
], [r(2, 3, 0, -1, true), r(4, 6, 0, -1, true)], false, markers);
});
test('Nested Regions', () => {
assertRanges([
/* 1*/ 'var x;',
/* 2*/ '#region',
/* 3*/ '#region',
/* 4*/ '',
/* 5*/ '#endregion',
/* 6*/ '#endregion',
/* 7*/ 'var y;',
], [r(2, 6, 0, -1, true), r(3, 5, 0, 0, true)], false, markers);
});
test('Nested Regions 2', () => {
assertRanges([
/* 1*/ 'class A {',
/* 2*/ ' #region',
/* 3*/ '',
/* 4*/ ' #region',
/* 5*/ '',
/* 6*/ ' #endregion',
/* 7*/ ' // comment',
/* 8*/ ' #endregion',
/* 9*/ '}',
], [r(1, 8, 0, -1), r(2, 8, 2, 0, true), r(4, 6, 2, 1, true)], false, markers);
});
test('Incomplete Regions', () => {
assertRanges([
/* 1*/ 'class A {',
/* 2*/ '#region',
/* 3*/ ' // comment',
/* 4*/ '}',
], [r(2, 3, 0, -1)], false, markers);
});
test('Incomplete Regions 2', () => {
assertRanges([
/* 1*/ '',
/* 2*/ '#region',
/* 3*/ '#region',
/* 4*/ '#region',
/* 5*/ ' // comment',
/* 6*/ '#endregion',
/* 7*/ '#endregion',
/* 8*/ ' // hello',
], [r(3, 7, 0, -1, true), r(4, 6, 0, 0, true)], false, markers);
});
test('Indented region before', () => {
assertRanges([
/* 1*/ 'if (x)',
/* 2*/ ' return;',
/* 3*/ '',
/* 4*/ '#region',
/* 5*/ ' // comment',
/* 6*/ '#endregion',
], [r(1, 3, 0, -1), r(4, 6, 0, -1, true)], false, markers);
});
test('Indented region before 2', () => {
assertRanges([
/* 1*/ 'if (x)',
/* 2*/ ' log();',
/* 3*/ '',
/* 4*/ ' #region',
/* 5*/ ' // comment',
/* 6*/ ' #endregion',
], [r(1, 6, 0, -1), r(2, 6, 2, 0), r(4, 6, 4, 1, true)], false, markers);
});
test('Indented region in-between', () => {
assertRanges([
/* 1*/ '#region',
/* 2*/ ' // comment',
/* 3*/ ' if (x)',
/* 4*/ ' return;',
/* 5*/ '',
/* 6*/ '#endregion',
], [r(1, 6, 0, -1, true), r(3, 5, 2, 0)], false, markers);
});
test('Indented region after', () => {
assertRanges([
/* 1*/ '#region',
/* 2*/ ' // comment',
/* 3*/ '',
/* 4*/ '#endregion',
/* 5*/ ' if (x)',
/* 6*/ ' return;',
], [r(1, 4, 0, -1, true), r(5, 6, 2, -1)], false, markers);
});
test('With off-side', () => {
assertRanges([
/* 1*/ '#region',
/* 2*/ ' ',
/* 3*/ '',
/* 4*/ '#endregion',
/* 5*/ '',
], [r(1, 4, 0, -1, true)], true, markers);
});
test('Nested with off-side', () => {
assertRanges([
/* 1*/ '#region',
/* 2*/ ' ',
/* 3*/ '#region',
/* 4*/ '',
/* 5*/ '#endregion',
/* 6*/ '',
/* 7*/ '#endregion',
/* 8*/ '',
], [r(1, 7, 0, -1, true), r(3, 5, 0, 0, true)], true, markers);
});
test('Issue 35981', () => {
assertRanges([
/* 1*/ 'function thisFoldsToEndOfPage() {',
/* 2*/ ' const variable = []',
/* 3*/ ' // #region',
/* 4*/ ' .reduce((a, b) => a,[]);',
/* 5*/ '}',
/* 6*/ '',
/* 7*/ 'function thisFoldsProperly() {',
/* 8*/ ' const foo = "bar"',
/* 9*/ '}',
], [r(1, 4, 0, -1), r(2, 4, 2, 0), r(7, 8, 0, -1)], false, markers);
});
test('Misspelled Markers', () => {
assertRanges([
/* 1*/ '#Region',
/* 2*/ '#endregion',
/* 3*/ '#regionsandmore',
/* 4*/ '#endregion',
/* 5*/ '#region',
/* 6*/ '#end region',
/* 7*/ '#region',
/* 8*/ '#endregionff',
], [], true, markers);
});
test('test max folding regions', () => {
let lines = [];
let nRegions = MAX_FOLDING_REGIONS;
for (let i = 0; i < nRegions; i++) {
lines.push('#region');
}
for (let i = 0; i < nRegions; i++) {
lines.push('#endregion');
}
let model = Model.createFromString(lines.join('\n'));
let actual = computeRanges(model, false, markers, MAX_FOLDING_REGIONS);
assert.equal(actual.length, nRegions, 'len');
for (let i = 0; i < nRegions; i++) {
assert.equal(actual.getStartLineNumber(i), i + 1, 'start' + i);
assert.equal(actual.getEndLineNumber(i), nRegions * 2 - i, 'end' + i);
assert.equal(actual.getParentIndex(i), i - 1, 'parent' + i);
}
});
test('findRange', () => {
let lines = [
/* 1*/ '#region',
/* 2*/ '#endregion',
/* 3*/ 'class A {',
/* 4*/ ' void foo() {',
/* 5*/ ' if (true) {',
/* 6*/ ' return;',
/* 7*/ ' }',
/* 8*/ '',
/* 9*/ ' if (true) {',
/* 10*/ ' return;',
/* 11*/ ' }',
/* 12*/ ' }',
/* 13*/ '}'];
let textModel = Model.createFromString(lines.join('\n'));
try {
let actual = computeRanges(textModel, false, markers);
// let r0 = r(1, 2);
// let r1 = r(3, 12);
// let r2 = r(4, 11);
// let r3 = r(5, 6);
// let r4 = r(9, 10);
assert.equal(actual.findRange(1), 0, '1');
assert.equal(actual.findRange(2), 0, '2');
assert.equal(actual.findRange(3), 1, '3');
assert.equal(actual.findRange(4), 2, '4');
assert.equal(actual.findRange(5), 3, '5');
assert.equal(actual.findRange(6), 3, '6');
assert.equal(actual.findRange(7), 2, '7');
assert.equal(actual.findRange(8), 2, '8');
assert.equal(actual.findRange(9), 4, '9');
assert.equal(actual.findRange(10), 4, '10');
assert.equal(actual.findRange(11), 2, '11');
assert.equal(actual.findRange(12), 1, '12');
assert.equal(actual.findRange(13), -1, '13');
} finally {
textModel.dispose();
}
});
});

View File

@@ -5,7 +5,7 @@
'use strict';
import * as assert from 'assert';
import { IntervalTree, IntervalNode } from 'vs/editor/common/model/intervalTree';
import { IntervalTree, IntervalNode, getNodeColor, NodeColor, SENTINEL, intervalCompare } from 'vs/editor/common/model/intervalTree';
const GENERATE_TESTS = false;
let TEST_COUNT = GENERATE_TESTS ? 10000 : 0;
@@ -116,10 +116,10 @@ suite('IntervalTree', () => {
}
if (PRINT_TREE) {
this._tree.print();
printTree(this._tree);
}
this._tree.assertInvariants();
assertTreeInvariants(this._tree);
let actual = this._tree.getAllInOrder().map(n => new Interval(n.cachedAbsoluteStart, n.cachedAbsoluteEnd));
let expected = this._oracle.intervals;
@@ -553,3 +553,89 @@ suite('IntervalTree', () => {
});
});
});
function printTree(T: IntervalTree): void {
if (T.root === SENTINEL) {
console.log(`~~ empty`);
return;
}
let out: string[] = [];
_printTree(T, T.root, '', 0, out);
console.log(out.join(''));
}
function _printTree(T: IntervalTree, n: IntervalNode, indent: string, delta: number, out: string[]): void {
out.push(`${indent}[${getNodeColor(n) === NodeColor.Red ? 'R' : 'B'},${n.delta}, ${n.start}->${n.end}, ${n.maxEnd}] : {${delta + n.start}->${delta + n.end}}, maxEnd: ${n.maxEnd + delta}\n`);
if (n.left !== SENTINEL) {
_printTree(T, n.left, indent + ' ', delta, out);
} else {
out.push(`${indent} NIL\n`);
}
if (n.right !== SENTINEL) {
_printTree(T, n.right, indent + ' ', delta + n.delta, out);
} else {
out.push(`${indent} NIL\n`);
}
}
//#region Assertion
function assertTreeInvariants(T: IntervalTree): void {
assert(getNodeColor(SENTINEL) === NodeColor.Black);
assert(SENTINEL.parent === SENTINEL);
assert(SENTINEL.left === SENTINEL);
assert(SENTINEL.right === SENTINEL);
assert(SENTINEL.start === 0);
assert(SENTINEL.end === 0);
assert(SENTINEL.delta === 0);
assert(T.root.parent === SENTINEL);
assertValidTree(T);
}
function depth(n: IntervalNode): number {
if (n === SENTINEL) {
// The leafs are black
return 1;
}
assert(depth(n.left) === depth(n.right));
return (getNodeColor(n) === NodeColor.Black ? 1 : 0) + depth(n.left);
}
function assertValidNode(n: IntervalNode, delta): void {
if (n === SENTINEL) {
return;
}
let l = n.left;
let r = n.right;
if (getNodeColor(n) === NodeColor.Red) {
assert(getNodeColor(l) === NodeColor.Black);
assert(getNodeColor(r) === NodeColor.Black);
}
let expectedMaxEnd = n.end;
if (l !== SENTINEL) {
assert(intervalCompare(l.start + delta, l.end + delta, n.start + delta, n.end + delta) <= 0);
expectedMaxEnd = Math.max(expectedMaxEnd, l.maxEnd);
}
if (r !== SENTINEL) {
assert(intervalCompare(n.start + delta, n.end + delta, r.start + delta + n.delta, r.end + delta + n.delta) <= 0);
expectedMaxEnd = Math.max(expectedMaxEnd, r.maxEnd + n.delta);
}
assert(n.maxEnd === expectedMaxEnd);
assertValidNode(l, delta);
assertValidNode(r, delta + n.delta);
}
function assertValidTree(T: IntervalTree): void {
if (T.root === SENTINEL) {
return;
}
assert(getNodeColor(T.root) === NodeColor.Black);
assert(depth(T.root.left) === depth(T.root.right));
assertValidNode(T.root, 0);
}
//#endregion

View File

@@ -11,7 +11,7 @@ import { MetadataConsts } from 'vs/editor/common/modes';
import { ViewLineToken, ViewLineTokenFactory } from 'vs/editor/common/core/viewLineToken';
function assertLineTokens(_actual: LineTokens, _expected: TestToken[]): void {
let expected = ViewLineTokenFactory.inflateArr(TestToken.toTokens(_expected), _actual.getLineLength());
let expected = ViewLineTokenFactory.inflateArr(TestToken.toTokens(_expected), _actual.getLineContent().length);
let actual = _actual.inflate();
let decode = (token: ViewLineToken) => {
return {
@@ -1521,4 +1521,3 @@ suite('Editor Model - modelLine.append', () => {
);
});
});

View File

@@ -1154,7 +1154,6 @@ suite('deltaDecorations', () => {
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');
actualDecorations.sort((a, b) => strcmp(a.id, b.id));
decorations.sort((a, b) => strcmp(a.id, b.id));
assert.deepEqual(actualDecorations, decorations);
@@ -1164,7 +1163,6 @@ suite('deltaDecorations', () => {
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');
actualNewDecorations.sort((a, b) => strcmp(a.id, b.id));
newDecorations.sort((a, b) => strcmp(a.id, b.id));
assert.deepEqual(actualDecorations, decorations);

View File

@@ -197,7 +197,7 @@ suite('Editor Modes - textToHtmlTokenizer', () => {
class Mode extends MockMode {
private static _id = new LanguageIdentifier('textToHtmlTokenizerMode', 3);
private static readonly _id = new LanguageIdentifier('textToHtmlTokenizerMode', 3);
constructor() {
super(Mode._id);

View File

@@ -7,19 +7,15 @@
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';
import { InlineDecoration, InlineDecorationType } 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('abcabcabcabcabcabcabcabcabcabc', [
new LineDecoration(1, 11, 'c1', false),
new LineDecoration(3, 4, 'c2', false)
new LineDecoration(1, 11, 'c1', InlineDecorationType.Regular),
new LineDecoration(3, 4, 'c2', InlineDecorationType.Regular)
]);
assert.deepEqual(result, [
@@ -32,8 +28,8 @@ suite('Editor ViewLayout - ViewLineParts', () => {
test('issue #3462: no whitespace shown at the end of a decorated line', () => {
var result = LineDecorationsNormalizer.normalize('abcabcabcabcabcabcabcabcabcabc', [
new LineDecoration(15, 21, 'vs-whitespace', false),
new LineDecoration(20, 21, 'inline-folded', false),
new LineDecoration(15, 21, 'vs-whitespace', InlineDecorationType.Regular),
new LineDecoration(20, 21, 'inline-folded', InlineDecorationType.Regular),
]);
assert.deepEqual(result, [
@@ -45,76 +41,88 @@ suite('Editor ViewLayout - ViewLineParts', () => {
test('issue #3661: Link decoration bleeds to next line when wrapping', () => {
let result = LineDecoration.filter([
newDecoration(2, 12, 3, 30, 'detected-link')
new InlineDecoration(new Range(2, 12, 3, 30), 'detected-link', InlineDecorationType.Regular)
], 3, 12, 500);
assert.deepEqual(result, [
new LineDecoration(12, 30, 'detected-link', false),
new LineDecoration(12, 30, 'detected-link', InlineDecorationType.Regular),
]);
});
test('issue #37401: Allow both before and after decorations on empty line', () => {
let result = LineDecoration.filter([
new InlineDecoration(new Range(4, 1, 4, 2), 'before', InlineDecorationType.Before),
new InlineDecoration(new Range(4, 0, 4, 1), 'after', InlineDecorationType.After),
], 4, 1, 500);
assert.deepEqual(result, [
new LineDecoration(1, 2, 'before', InlineDecorationType.Before),
new LineDecoration(0, 1, 'after', InlineDecorationType.After),
]);
});
test('ViewLineParts', () => {
assert.deepEqual(LineDecorationsNormalizer.normalize('abcabcabcabcabcabcabcabcabcabc', [
new LineDecoration(1, 2, 'c1', false),
new LineDecoration(3, 4, 'c2', false)
new LineDecoration(1, 2, 'c1', InlineDecorationType.Regular),
new LineDecoration(3, 4, 'c2', InlineDecorationType.Regular)
]), [
new DecorationSegment(0, 0, 'c1'),
new DecorationSegment(2, 2, 'c2')
]);
assert.deepEqual(LineDecorationsNormalizer.normalize('abcabcabcabcabcabcabcabcabcabc', [
new LineDecoration(1, 3, 'c1', false),
new LineDecoration(3, 4, 'c2', false)
new LineDecoration(1, 3, 'c1', InlineDecorationType.Regular),
new LineDecoration(3, 4, 'c2', InlineDecorationType.Regular)
]), [
new DecorationSegment(0, 1, 'c1'),
new DecorationSegment(2, 2, 'c2')
]);
assert.deepEqual(LineDecorationsNormalizer.normalize('abcabcabcabcabcabcabcabcabcabc', [
new LineDecoration(1, 4, 'c1', false),
new LineDecoration(3, 4, 'c2', false)
new LineDecoration(1, 4, 'c1', InlineDecorationType.Regular),
new LineDecoration(3, 4, 'c2', InlineDecorationType.Regular)
]), [
new DecorationSegment(0, 1, 'c1'),
new DecorationSegment(2, 2, 'c1 c2')
]);
assert.deepEqual(LineDecorationsNormalizer.normalize('abcabcabcabcabcabcabcabcabcabc', [
new LineDecoration(1, 4, 'c1', false),
new LineDecoration(1, 4, 'c1*', false),
new LineDecoration(3, 4, 'c2', false)
new LineDecoration(1, 4, 'c1', InlineDecorationType.Regular),
new LineDecoration(1, 4, 'c1*', InlineDecorationType.Regular),
new LineDecoration(3, 4, 'c2', InlineDecorationType.Regular)
]), [
new DecorationSegment(0, 1, 'c1 c1*'),
new DecorationSegment(2, 2, 'c1 c1* c2')
]);
assert.deepEqual(LineDecorationsNormalizer.normalize('abcabcabcabcabcabcabcabcabcabc', [
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(1, 4, 'c1', InlineDecorationType.Regular),
new LineDecoration(1, 4, 'c1*', InlineDecorationType.Regular),
new LineDecoration(1, 4, 'c1**', InlineDecorationType.Regular),
new LineDecoration(3, 4, 'c2', InlineDecorationType.Regular)
]), [
new DecorationSegment(0, 1, 'c1 c1* c1**'),
new DecorationSegment(2, 2, 'c1 c1* c1** c2')
]);
assert.deepEqual(LineDecorationsNormalizer.normalize('abcabcabcabcabcabcabcabcabcabc', [
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 LineDecoration(1, 4, 'c1', InlineDecorationType.Regular),
new LineDecoration(1, 4, 'c1*', InlineDecorationType.Regular),
new LineDecoration(1, 4, 'c1**', InlineDecorationType.Regular),
new LineDecoration(3, 4, 'c2', InlineDecorationType.Regular),
new LineDecoration(3, 4, 'c2*', InlineDecorationType.Regular)
]), [
new DecorationSegment(0, 1, 'c1 c1* c1**'),
new DecorationSegment(2, 2, 'c1 c1* c1** c2 c2*')
]);
assert.deepEqual(LineDecorationsNormalizer.normalize('abcabcabcabcabcabcabcabcabcabc', [
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 LineDecoration(1, 4, 'c1', InlineDecorationType.Regular),
new LineDecoration(1, 4, 'c1*', InlineDecorationType.Regular),
new LineDecoration(1, 4, 'c1**', InlineDecorationType.Regular),
new LineDecoration(3, 4, 'c2', InlineDecorationType.Regular),
new LineDecoration(3, 5, 'c2*', InlineDecorationType.Regular)
]), [
new DecorationSegment(0, 1, 'c1 c1* c1**'),
new DecorationSegment(2, 2, 'c1 c1* c1** c2 c2*'),

View File

@@ -10,6 +10,7 @@ import { ViewLineToken } from 'vs/editor/common/core/viewLineToken';
import { CharCode } from 'vs/base/common/charCode';
import { MetadataConsts } from 'vs/editor/common/modes';
import { LineDecoration } from 'vs/editor/common/viewLayout/lineDecorations';
import { InlineDecorationType } from 'vs/editor/common/viewModel/viewModel';
suite('viewLineRenderer.renderLine', () => {
@@ -700,7 +701,7 @@ suite('viewLineRenderer.renderLine 2', () => {
false,
0,
[createPart(21, 3)],
[new LineDecoration(1, 22, 'link', false)],
[new LineDecoration(1, 22, 'link', InlineDecorationType.Regular)],
4,
10,
-1,
@@ -735,7 +736,7 @@ suite('viewLineRenderer.renderLine 2', () => {
createPart(84, 6),
],
[
new LineDecoration(13, 51, 'detected-link', false)
new LineDecoration(13, 51, 'detected-link', InlineDecorationType.Regular)
],
4,
10,
@@ -993,9 +994,9 @@ suite('viewLineRenderer.renderLine 2', () => {
0,
[createPart(11, 0)],
[
new LineDecoration(5, 7, 'a', false),
new LineDecoration(1, 3, 'b', false),
new LineDecoration(2, 8, 'c', false),
new LineDecoration(5, 7, 'a', InlineDecorationType.Regular),
new LineDecoration(1, 3, 'b', InlineDecorationType.Regular),
new LineDecoration(2, 8, 'c', InlineDecorationType.Regular),
],
4,
10,
@@ -1033,7 +1034,7 @@ suite('viewLineRenderer.renderLine 2', () => {
false,
0,
[createPart(4, 3)],
[new LineDecoration(1, 2, 'before', true)],
[new LineDecoration(1, 2, 'before', InlineDecorationType.Before)],
4,
10,
-1,
@@ -1062,7 +1063,7 @@ suite('viewLineRenderer.renderLine 2', () => {
false,
0,
[createPart(4, 3)],
[new LineDecoration(2, 3, 'before', true)],
[new LineDecoration(2, 3, 'before', InlineDecorationType.Before)],
4,
10,
-1,
@@ -1092,7 +1093,7 @@ suite('viewLineRenderer.renderLine 2', () => {
false,
0,
[createPart(0, 3)],
[new LineDecoration(1, 2, 'before', true)],
[new LineDecoration(1, 2, 'before', InlineDecorationType.Before)],
4,
10,
-1,
@@ -1103,7 +1104,7 @@ suite('viewLineRenderer.renderLine 2', () => {
let expected = [
'<span>',
'<span class="before">\u00a0</span>',
'<span class="before"></span>',
'</span>'
].join('');
@@ -1118,7 +1119,7 @@ suite('viewLineRenderer.renderLine 2', () => {
false,
0,
[createPart(7, 3)],
[new LineDecoration(7, 8, 'inline-folded', true)],
[new LineDecoration(7, 8, 'inline-folded', InlineDecorationType.After)],
2,
10,
10000,
@@ -1137,6 +1138,65 @@ suite('viewLineRenderer.renderLine 2', () => {
assert.deepEqual(actual.html, expected);
});
test('issue #37401: Allow both before and after decorations on empty line', () => {
let actual = renderViewLine(new RenderLineInput(
true,
'',
false,
0,
[createPart(0, 3)],
[
new LineDecoration(1, 2, 'before', InlineDecorationType.Before),
new LineDecoration(0, 1, 'after', InlineDecorationType.After),
],
2,
10,
10000,
'none',
false,
false
));
let expected = [
'<span>',
'<span class="before after"></span>',
'</span>'
].join('');
assert.deepEqual(actual.html, expected);
});
test('issue #38935: GitLens end-of-line blame no longer rendering', () => {
let actual = renderViewLine(new RenderLineInput(
true,
'\t}',
false,
0,
[createPart(2, 3)],
[
new LineDecoration(3, 3, 'ced-TextEditorDecorationType2-5e9b9b3f-3 ced-TextEditorDecorationType2-3', InlineDecorationType.Before),
new LineDecoration(3, 3, 'ced-TextEditorDecorationType2-5e9b9b3f-4 ced-TextEditorDecorationType2-4', InlineDecorationType.After),
],
4,
10,
10000,
'none',
false,
false
));
let expected = [
'<span>',
'<span class="mtk3">\u00a0\u00a0\u00a0\u00a0}</span>',
'<span class="ced-TextEditorDecorationType2-5e9b9b3f-3 ced-TextEditorDecorationType2-3 ced-TextEditorDecorationType2-5e9b9b3f-4 ced-TextEditorDecorationType2-4"></span>',
'</span>'
].join('');
assert.deepEqual(actual.html, expected);
});
function createTestGetColumnOfLinePartOffset(lineContent: string, tabSize: number, parts: ViewLineToken[], expectedPartLengths: number[]): (partIndex: number, partLength: number, offset: number, expected: number) => void {
let renderLineOutput = renderViewLine(new RenderLineInput(
false,

View File

@@ -32,22 +32,22 @@ suite('Editor ViewModel - SplitLinesCollection', () => {
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++) {
for (let col = 1; col <= 14; col++) {
assert.equal(line1.getModelColumnOfViewPosition(0, col), col, 'getInputColumnOfOutputPosition(0, ' + col + ')');
}
for (var col = 1; col <= 15; col++) {
for (let col = 1; col <= 15; col++) {
assert.equal(line1.getModelColumnOfViewPosition(1, col), 13 + col, 'getInputColumnOfOutputPosition(1, ' + col + ')');
}
for (var col = 1; col <= 16; col++) {
for (let col = 1; col <= 16; col++) {
assert.equal(line1.getModelColumnOfViewPosition(2, col), 13 + 14 + col, 'getInputColumnOfOutputPosition(2, ' + col + ')');
}
for (var col = 1; col <= 13; col++) {
for (let 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++) {
for (let 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++) {
for (let col = 1 + 13 + 14; col <= 15 + 14 + 13; col++) {
assert.deepEqual(line1.getViewPositionOfModelPosition(0, col), pos(2, col - 13 - 14), 'getOutputPositionOfInputPosition(' + col + ')');
}
@@ -61,28 +61,28 @@ suite('Editor ViewModel - SplitLinesCollection', () => {
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++) {
for (let col = 1; col <= 14; col++) {
assert.equal(line1.getModelColumnOfViewPosition(0, col), col, 'getInputColumnOfOutputPosition(0, ' + col + ')');
}
for (var col = 1; col <= 1; col++) {
for (let col = 1; col <= 1; col++) {
assert.equal(line1.getModelColumnOfViewPosition(1, 1), 13 + col, 'getInputColumnOfOutputPosition(1, ' + col + ')');
}
for (var col = 2; col <= 16; col++) {
for (let col = 2; col <= 16; col++) {
assert.equal(line1.getModelColumnOfViewPosition(1, col), 13 + col - 1, 'getInputColumnOfOutputPosition(1, ' + col + ')');
}
for (var col = 1; col <= 1; col++) {
for (let col = 1; col <= 1; col++) {
assert.equal(line1.getModelColumnOfViewPosition(2, col), 13 + 14 + col, 'getInputColumnOfOutputPosition(2, ' + col + ')');
}
for (var col = 2; col <= 17; col++) {
for (let 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++) {
for (let 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++) {
for (let 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++) {
for (let col = 1 + 13 + 14; col <= 15 + 14 + 13; col++) {
assert.deepEqual(line1.getViewPositionOfModelPosition(0, col), pos(2, 1 + col - 13 - 14), 'getOutputPositionOfInputPosition(' + col + ')');
}
});

View File

@@ -7,9 +7,9 @@
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';
import { IEditorOptions } from 'vs/editor/common/config/editorOptions';
export function testViewModel(text: string[], options: MockCodeEditorCreationOptions, callback: (viewModel: ViewModel, model: Model) => void): void {
export function testViewModel(text: string[], options: IEditorOptions, callback: (viewModel: ViewModel, model: Model) => void): void {
const EDITOR_ID = 1;
let configuration = new TestConfiguration(options);

View File

@@ -7,14 +7,15 @@
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';
import { IEditorOptions } from 'vs/editor/common/config/editorOptions';
import { InlineDecorationType } from 'vs/editor/common/viewModel/viewModel';
suite('ViewModelDecorations', () => {
test('getDecorationsViewportData', () => {
const text = [
'hello world, this is a buffer that will be wrapped'
];
const opts: MockCodeEditorCreationOptions = {
const opts: IEditorOptions = {
wordWrap: 'wordWrapColumn',
wordWrapColumn: 13
};
@@ -25,21 +26,6 @@ suite('ViewModelDecorations', () => {
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 {
@@ -53,39 +39,39 @@ suite('ViewModelDecorations', () => {
// VIEWPORT will be (1,14) -> (1,36)
// completely before viewport
dec1 = accessor.addDecoration(new Range(1, 2, 1, 3), createOpts('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'));
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'));
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'));
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'));
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'));
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'));
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'));
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'));
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'));
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'));
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'));
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'));
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'));
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'));
accessor.addDecoration(new Range(1, 40, 1, 51), createOpts('dec15'));
});
let actualDecorations = viewModel.getDecorationsInViewport(
@@ -120,107 +106,117 @@ suite('ViewModelDecorations', () => {
{
range: new Range(1, 2, 2, 1),
inlineClassName: 'i-dec2',
insertsBeforeOrAfter: false
type: InlineDecorationType.Regular
},
{
range: new Range(2, 1, 2, 1),
inlineClassName: 'a-dec2',
type: InlineDecorationType.After
},
{
range: new Range(1, 2, 2, 2),
inlineClassName: 'i-dec3',
insertsBeforeOrAfter: false
type: InlineDecorationType.Regular
},
{
range: new Range(2, 1, 2, 2),
range: new Range(2, 2, 2, 2),
inlineClassName: 'a-dec3',
insertsBeforeOrAfter: true
type: InlineDecorationType.After
},
{
range: new Range(1, 2, 4, 1),
inlineClassName: 'i-dec4',
insertsBeforeOrAfter: false
type: InlineDecorationType.Regular
},
{
range: new Range(1, 2, 5, 8),
inlineClassName: 'i-dec5',
insertsBeforeOrAfter: false
type: InlineDecorationType.Regular
},
{
range: new Range(2, 1, 2, 1),
inlineClassName: 'i-dec6',
insertsBeforeOrAfter: false
type: InlineDecorationType.Regular
},
{
range: new Range(2, 1, 2, 2),
range: new Range(2, 1, 2, 1),
inlineClassName: 'b-dec6',
insertsBeforeOrAfter: true
type: InlineDecorationType.Before
},
{
range: new Range(2, 1, 2, 1),
inlineClassName: 'a-dec6',
type: InlineDecorationType.After
},
{
range: new Range(2, 1, 2, 3),
inlineClassName: 'i-dec7',
insertsBeforeOrAfter: false
type: InlineDecorationType.Regular
},
{
range: new Range(2, 1, 2, 2),
range: new Range(2, 1, 2, 1),
inlineClassName: 'b-dec7',
insertsBeforeOrAfter: true
type: InlineDecorationType.Before
},
{
range: new Range(2, 2, 2, 3),
range: new Range(2, 3, 2, 3),
inlineClassName: 'a-dec7',
insertsBeforeOrAfter: true
type: InlineDecorationType.After
},
{
range: new Range(2, 1, 4, 1),
inlineClassName: 'i-dec8',
insertsBeforeOrAfter: false
type: InlineDecorationType.Regular
},
{
range: new Range(2, 1, 2, 2),
range: new Range(2, 1, 2, 1),
inlineClassName: 'b-dec8',
insertsBeforeOrAfter: true
type: InlineDecorationType.Before
},
{
range: new Range(2, 1, 5, 8),
inlineClassName: 'i-dec9',
insertsBeforeOrAfter: false
type: InlineDecorationType.Regular
},
{
range: new Range(2, 1, 2, 2),
range: new Range(2, 1, 2, 1),
inlineClassName: 'b-dec9',
insertsBeforeOrAfter: true
type: InlineDecorationType.Before
},
{
range: new Range(2, 3, 2, 5),
inlineClassName: 'i-dec10',
insertsBeforeOrAfter: false
type: InlineDecorationType.Regular
},
{
range: new Range(2, 3, 2, 4),
range: new Range(2, 3, 2, 3),
inlineClassName: 'b-dec10',
insertsBeforeOrAfter: true
type: InlineDecorationType.Before
},
{
range: new Range(2, 4, 2, 5),
range: new Range(2, 5, 2, 5),
inlineClassName: 'a-dec10',
insertsBeforeOrAfter: true
type: InlineDecorationType.After
},
{
range: new Range(2, 3, 4, 1),
inlineClassName: 'i-dec11',
insertsBeforeOrAfter: false
type: InlineDecorationType.Regular
},
{
range: new Range(2, 3, 2, 4),
range: new Range(2, 3, 2, 3),
inlineClassName: 'b-dec11',
insertsBeforeOrAfter: true
type: InlineDecorationType.Before
},
{
range: new Range(2, 3, 5, 8),
inlineClassName: 'i-dec12',
insertsBeforeOrAfter: false
type: InlineDecorationType.Regular
},
{
range: new Range(2, 3, 2, 4),
range: new Range(2, 3, 2, 3),
inlineClassName: 'b-dec12',
insertsBeforeOrAfter: true
type: InlineDecorationType.Before
},
]);
@@ -234,32 +230,32 @@ suite('ViewModelDecorations', () => {
{
range: new Range(1, 2, 4, 1),
inlineClassName: 'i-dec4',
insertsBeforeOrAfter: false
type: InlineDecorationType.Regular
},
{
range: new Range(1, 2, 5, 8),
inlineClassName: 'i-dec5',
insertsBeforeOrAfter: false
type: InlineDecorationType.Regular
},
{
range: new Range(2, 1, 4, 1),
inlineClassName: 'i-dec8',
insertsBeforeOrAfter: false
type: InlineDecorationType.Regular
},
{
range: new Range(2, 1, 5, 8),
inlineClassName: 'i-dec9',
insertsBeforeOrAfter: false
type: InlineDecorationType.Regular
},
{
range: new Range(2, 3, 4, 1),
inlineClassName: 'i-dec11',
insertsBeforeOrAfter: false
type: InlineDecorationType.Regular
},
{
range: new Range(2, 3, 5, 8),
inlineClassName: 'i-dec12',
insertsBeforeOrAfter: false
type: InlineDecorationType.Regular
},
]);
});
@@ -269,7 +265,7 @@ suite('ViewModelDecorations', () => {
const text = [
'hello world, this is a buffer that will be wrapped'
];
const opts: MockCodeEditorCreationOptions = {
const opts: IEditorOptions = {
wordWrap: 'wordWrapColumn',
wordWrapColumn: 13
};
@@ -280,9 +276,8 @@ suite('ViewModelDecorations', () => {
assert.equal(viewModel.getLineContent(4), 'will be ');
assert.equal(viewModel.getLineContent(5), 'wrapped');
let dec1: string;
model.changeDecorations((accessor) => {
dec1 = accessor.addDecoration(
accessor.addDecoration(
new Range(1, 50, 1, 51),
{
beforeContentClassName: 'dec1'
@@ -308,4 +303,39 @@ suite('ViewModelDecorations', () => {
assert.deepEqual(inlineDecorations2, []);
});
});
test('issue #37401: Allow both before and after decorations on empty line', () => {
const text = [
''
];
testViewModel(text, {}, (viewModel, model) => {
model.changeDecorations((accessor) => {
accessor.addDecoration(
new Range(1, 1, 1, 1),
{
beforeContentClassName: 'before1',
afterContentClassName: 'after1'
}
);
});
let inlineDecorations = viewModel.getViewLineRenderingData(
new Range(1, 1, 1, 1),
1
).inlineDecorations;
assert.deepEqual(inlineDecorations, [
{
range: new Range(1, 1, 1, 1),
inlineClassName: 'before1',
type: InlineDecorationType.Before
},
{
range: new Range(1, 1, 1, 1),
inlineClassName: 'after1',
type: InlineDecorationType.After
}
]);
});
});
});