mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 10:58:30 -05:00
Refresh master with initial release/0.24 snapshot (#332)
* Initial port of release/0.24 source code * Fix additional headers * Fix a typo in launch.json
This commit is contained in:
@@ -10,10 +10,11 @@ import { Position } from 'vs/editor/common/core/position';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { Selection } from 'vs/editor/common/core/selection';
|
||||
import { IIdentifiedSingleEditOperation } from 'vs/editor/common/editorCommon';
|
||||
import { ILineEdit, ModelLine, LineMarker, MarkersTracker } from 'vs/editor/common/model/modelLine';
|
||||
import { withMockCodeEditor } from 'vs/editor/test/common/mocks/mockCodeEditor';
|
||||
|
||||
const NO_TAB_SIZE = 0;
|
||||
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) => {
|
||||
@@ -31,15 +32,6 @@ function testCommand(lines: string[], selections: Selection[], edits: IIdentifie
|
||||
});
|
||||
}
|
||||
|
||||
function testLineEditMarker(text: string, column: number, stickToPreviousCharacter: boolean, edit: ILineEdit, expectedColumn: number): void {
|
||||
var line = new ModelLine(text, NO_TAB_SIZE);
|
||||
line.addMarker(new LineMarker('1', 0, new Position(0, column), stickToPreviousCharacter));
|
||||
|
||||
line.applyEdits(new MarkersTracker(), [edit], NO_TAB_SIZE);
|
||||
|
||||
assert.equal(line.getMarkers()[0].position.column, expectedColumn);
|
||||
}
|
||||
|
||||
suite('Editor Side Editing - collapsed selection', () => {
|
||||
|
||||
test('replace at selection', () => {
|
||||
@@ -86,14 +78,6 @@ suite('Editor Side Editing - collapsed selection', () => {
|
||||
);
|
||||
});
|
||||
|
||||
test('ModelLine.applyEdits uses `isReplace`', () => {
|
||||
testLineEditMarker('something', 1, true, { startColumn: 1, endColumn: 1, text: 'asd', forceMoveMarkers: false }, 1);
|
||||
testLineEditMarker('something', 1, true, { startColumn: 1, endColumn: 1, text: 'asd', forceMoveMarkers: true }, 4);
|
||||
|
||||
testLineEditMarker('something', 1, false, { startColumn: 1, endColumn: 1, text: 'asd', forceMoveMarkers: false }, 4);
|
||||
testLineEditMarker('something', 1, false, { startColumn: 1, endColumn: 1, text: 'asd', forceMoveMarkers: true }, 4);
|
||||
});
|
||||
|
||||
test('insert at selection', () => {
|
||||
testCommand(
|
||||
[
|
||||
@@ -204,5 +188,699 @@ suite('Editor Side Editing - collapsed selection', () => {
|
||||
[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)],
|
||||
]
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -14,7 +14,7 @@ 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 op = new TrimTrailingWhitespaceCommand(new Selection(1, 1, 1, 1), []);
|
||||
var actual = getEditOperation(model, op);
|
||||
assert.deepEqual(actual, expected);
|
||||
});
|
||||
|
||||
@@ -1453,9 +1453,9 @@ suite('Editor Controller - Regression tests', () => {
|
||||
|
||||
cursorCommand(cursor, H.Undo);
|
||||
assert.equal(model.getValue(), [
|
||||
'some lines',
|
||||
'and more lines',
|
||||
'just some text',
|
||||
' some lines',
|
||||
' and more lines',
|
||||
' just some text',
|
||||
].join('\n'), '002');
|
||||
|
||||
cursorCommand(cursor, H.Undo);
|
||||
@@ -1464,6 +1464,13 @@ suite('Editor Controller - Regression tests', () => {
|
||||
'and more lines',
|
||||
'just some text',
|
||||
].join('\n'), '003');
|
||||
|
||||
cursorCommand(cursor, H.Undo);
|
||||
assert.equal(model.getValue(), [
|
||||
'some lines',
|
||||
'and more lines',
|
||||
'just some text',
|
||||
].join('\n'), '004');
|
||||
});
|
||||
|
||||
model.dispose();
|
||||
@@ -1622,6 +1629,24 @@ suite('Editor Controller - Regression tests', () => {
|
||||
});
|
||||
});
|
||||
|
||||
test('issue #33788: Wrong cursor position when double click to select a word', () => {
|
||||
let model = Model.createFromString(
|
||||
[
|
||||
'Just some text'
|
||||
].join('\n')
|
||||
);
|
||||
|
||||
withMockCodeEditor(null, { model: model }, (editor, cursor) => {
|
||||
CoreNavigationCommands.WordSelect.runCoreEditorCommand(cursor, { position: new Position(1, 8) });
|
||||
assert.deepEqual(cursor.getSelection(), new Selection(1, 6, 1, 10));
|
||||
|
||||
CoreNavigationCommands.WordSelectDrag.runCoreEditorCommand(cursor, { position: new Position(1, 8) });
|
||||
assert.deepEqual(cursor.getSelection(), new Selection(1, 6, 1, 10));
|
||||
});
|
||||
|
||||
model.dispose();
|
||||
});
|
||||
|
||||
test('issue #9675: Undo/Redo adds a stop in between CHN Characters', () => {
|
||||
usingCursor({
|
||||
text: [
|
||||
@@ -1651,7 +1676,8 @@ suite('Editor Controller - Regression tests', () => {
|
||||
});
|
||||
});
|
||||
|
||||
test('issue #23913: Greater than 1000+ multi cursor typing replacement text appears inverted, lines begin to drop off selection', () => {
|
||||
test('issue #23913: Greater than 1000+ multi cursor typing replacement text appears inverted, lines begin to drop off selection', function () {
|
||||
this.timeout(10000);
|
||||
const LINE_CNT = 2000;
|
||||
|
||||
let text = [];
|
||||
@@ -1715,6 +1741,49 @@ suite('Editor Controller - Regression tests', () => {
|
||||
assertCursor(cursor, new Selection(1, 1, 1, 1));
|
||||
});
|
||||
});
|
||||
|
||||
test('issue #36740: wordwrap creates an extra step / character at the wrapping point', () => {
|
||||
// a single model line => 4 view lines
|
||||
withMockCodeEditor([
|
||||
[
|
||||
'Lorem ipsum ',
|
||||
'dolor sit amet ',
|
||||
'consectetur ',
|
||||
'adipiscing elit',
|
||||
].join('')
|
||||
], { wordWrap: 'wordWrapColumn', wordWrapColumn: 16 }, (editor, cursor) => {
|
||||
cursor.setSelections('test', [new Selection(1, 7, 1, 7)]);
|
||||
|
||||
moveRight(cursor);
|
||||
assertCursor(cursor, new Selection(1, 8, 1, 8));
|
||||
|
||||
moveRight(cursor);
|
||||
assertCursor(cursor, new Selection(1, 9, 1, 9));
|
||||
|
||||
moveRight(cursor);
|
||||
assertCursor(cursor, new Selection(1, 10, 1, 10));
|
||||
|
||||
moveRight(cursor);
|
||||
assertCursor(cursor, new Selection(1, 11, 1, 11));
|
||||
|
||||
moveRight(cursor);
|
||||
assertCursor(cursor, new Selection(1, 12, 1, 12));
|
||||
|
||||
moveRight(cursor);
|
||||
assertCursor(cursor, new Selection(1, 13, 1, 13));
|
||||
|
||||
// moving to view line 2
|
||||
moveRight(cursor);
|
||||
assertCursor(cursor, new Selection(1, 14, 1, 14));
|
||||
|
||||
moveLeft(cursor);
|
||||
assertCursor(cursor, new Selection(1, 13, 1, 13));
|
||||
|
||||
// moving back to view line 1
|
||||
moveLeft(cursor);
|
||||
assertCursor(cursor, new Selection(1, 12, 1, 12));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
suite('Editor Controller - Cursor Configuration', () => {
|
||||
@@ -3105,6 +3174,93 @@ suite('Editor Controller - Indentation Rules', () => {
|
||||
assert.equal(model.getLineContent(3), '}');
|
||||
});
|
||||
});
|
||||
|
||||
test('issue #36090: JS: editor.autoIndent seems to be broken', () => {
|
||||
class JSMode extends MockMode {
|
||||
private static _id = new LanguageIdentifier('indentRulesMode', 4);
|
||||
constructor() {
|
||||
super(JSMode._id);
|
||||
this._register(LanguageConfigurationRegistry.register(this.getLanguageIdentifier(), {
|
||||
brackets: [
|
||||
['{', '}'],
|
||||
['[', ']'],
|
||||
['(', ')']
|
||||
],
|
||||
indentationRules: {
|
||||
// ^(.*\*/)?\s*\}.*$
|
||||
decreaseIndentPattern: /^((?!.*?\/\*).*\*\/)?\s*[\}\]\)].*$/,
|
||||
// ^.*\{[^}"']*$
|
||||
increaseIndentPattern: /^((?!\/\/).)*(\{[^}"'`]*|\([^)"'`]*|\[[^\]"'`]*)$/
|
||||
},
|
||||
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 }
|
||||
}
|
||||
]
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
let mode = new JSMode();
|
||||
let model = Model.createFromString(
|
||||
[
|
||||
'class ItemCtrl {',
|
||||
' getPropertiesByItemId(id) {',
|
||||
' return this.fetchItem(id)',
|
||||
' .then(item => {',
|
||||
' return this.getPropertiesOfItem(item);',
|
||||
' });',
|
||||
' }',
|
||||
'}',
|
||||
].join('\n'),
|
||||
undefined,
|
||||
mode.getLanguageIdentifier()
|
||||
);
|
||||
|
||||
withMockCodeEditor(null, { model: model, autoIndent: false }, (editor, cursor) => {
|
||||
moveTo(cursor, 7, 6, false);
|
||||
assertCursor(cursor, new Selection(7, 6, 7, 6));
|
||||
|
||||
cursorCommand(cursor, H.Type, { text: '\n' }, 'keyboard');
|
||||
assert.equal(model.getValue(),
|
||||
[
|
||||
'class ItemCtrl {',
|
||||
' getPropertiesByItemId(id) {',
|
||||
' return this.fetchItem(id)',
|
||||
' .then(item => {',
|
||||
' return this.getPropertiesOfItem(item);',
|
||||
' });',
|
||||
' }',
|
||||
' ',
|
||||
'}',
|
||||
].join('\n')
|
||||
);
|
||||
assertCursor(cursor, new Selection(8, 5, 8, 5));
|
||||
});
|
||||
|
||||
model.dispose();
|
||||
mode.dispose();
|
||||
});
|
||||
});
|
||||
|
||||
interface ICursorOpts {
|
||||
@@ -3699,4 +3855,260 @@ suite('autoClosingPairs', () => {
|
||||
model.dispose();
|
||||
mode.dispose();
|
||||
});
|
||||
|
||||
test('issue #7100: Mouse word selection is strange when non-word character is at the end of line', () => {
|
||||
let model = Model.createFromString(
|
||||
[
|
||||
'before.a',
|
||||
'before',
|
||||
'hello:',
|
||||
'there:',
|
||||
'this is strange:',
|
||||
'here',
|
||||
'it',
|
||||
'is',
|
||||
].join('\n')
|
||||
);
|
||||
|
||||
withMockCodeEditor(null, { model: model }, (editor, cursor) => {
|
||||
CoreNavigationCommands.WordSelect.runEditorCommand(null, editor, {
|
||||
position: new Position(3, 7)
|
||||
});
|
||||
assertCursor(cursor, new Selection(3, 7, 3, 7));
|
||||
|
||||
CoreNavigationCommands.WordSelectDrag.runEditorCommand(null, editor, {
|
||||
position: new Position(4, 7)
|
||||
});
|
||||
assertCursor(cursor, new Selection(3, 7, 4, 7));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
suite('Undo stops', () => {
|
||||
|
||||
test('there is an undo stop between typing and deleting left', () => {
|
||||
let model = Model.createFromString(
|
||||
[
|
||||
'A line',
|
||||
'Another line',
|
||||
].join('\n')
|
||||
);
|
||||
|
||||
withMockCodeEditor(null, { model: model }, (editor, cursor) => {
|
||||
cursor.setSelections('test', [new Selection(1, 3, 1, 3)]);
|
||||
cursorCommand(cursor, H.Type, { text: 'first' }, 'keyboard');
|
||||
assert.equal(model.getLineContent(1), 'A first line');
|
||||
assertCursor(cursor, new Selection(1, 8, 1, 8));
|
||||
|
||||
CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null);
|
||||
CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null);
|
||||
assert.equal(model.getLineContent(1), 'A fir line');
|
||||
assertCursor(cursor, new Selection(1, 6, 1, 6));
|
||||
|
||||
cursorCommand(cursor, H.Undo, {});
|
||||
assert.equal(model.getLineContent(1), 'A first line');
|
||||
assertCursor(cursor, new Selection(1, 8, 1, 8));
|
||||
|
||||
cursorCommand(cursor, H.Undo, {});
|
||||
assert.equal(model.getLineContent(1), 'A line');
|
||||
assertCursor(cursor, new Selection(1, 3, 1, 3));
|
||||
});
|
||||
});
|
||||
|
||||
test('there is an undo stop between typing and deleting right', () => {
|
||||
let model = Model.createFromString(
|
||||
[
|
||||
'A line',
|
||||
'Another line',
|
||||
].join('\n')
|
||||
);
|
||||
|
||||
withMockCodeEditor(null, { model: model }, (editor, cursor) => {
|
||||
cursor.setSelections('test', [new Selection(1, 3, 1, 3)]);
|
||||
cursorCommand(cursor, H.Type, { text: 'first' }, 'keyboard');
|
||||
assert.equal(model.getLineContent(1), 'A first line');
|
||||
assertCursor(cursor, new Selection(1, 8, 1, 8));
|
||||
|
||||
CoreEditingCommands.DeleteRight.runEditorCommand(null, editor, null);
|
||||
CoreEditingCommands.DeleteRight.runEditorCommand(null, editor, null);
|
||||
assert.equal(model.getLineContent(1), 'A firstine');
|
||||
assertCursor(cursor, new Selection(1, 8, 1, 8));
|
||||
|
||||
cursorCommand(cursor, H.Undo, {});
|
||||
assert.equal(model.getLineContent(1), 'A first line');
|
||||
assertCursor(cursor, new Selection(1, 8, 1, 8));
|
||||
|
||||
cursorCommand(cursor, H.Undo, {});
|
||||
assert.equal(model.getLineContent(1), 'A line');
|
||||
assertCursor(cursor, new Selection(1, 3, 1, 3));
|
||||
});
|
||||
});
|
||||
|
||||
test('there is an undo stop between deleting left and typing', () => {
|
||||
let model = Model.createFromString(
|
||||
[
|
||||
'A line',
|
||||
'Another line',
|
||||
].join('\n')
|
||||
);
|
||||
|
||||
withMockCodeEditor(null, { model: model }, (editor, cursor) => {
|
||||
cursor.setSelections('test', [new Selection(2, 8, 2, 8)]);
|
||||
CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null);
|
||||
CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null);
|
||||
CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null);
|
||||
CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null);
|
||||
CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null);
|
||||
CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null);
|
||||
CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null);
|
||||
assert.equal(model.getLineContent(2), ' line');
|
||||
assertCursor(cursor, new Selection(2, 1, 2, 1));
|
||||
|
||||
cursorCommand(cursor, H.Type, { text: 'Second' }, 'keyboard');
|
||||
assert.equal(model.getLineContent(2), 'Second line');
|
||||
assertCursor(cursor, new Selection(2, 7, 2, 7));
|
||||
|
||||
cursorCommand(cursor, H.Undo, {});
|
||||
assert.equal(model.getLineContent(2), ' line');
|
||||
assertCursor(cursor, new Selection(2, 1, 2, 1));
|
||||
|
||||
cursorCommand(cursor, H.Undo, {});
|
||||
assert.equal(model.getLineContent(2), 'Another line');
|
||||
assertCursor(cursor, new Selection(2, 8, 2, 8));
|
||||
});
|
||||
});
|
||||
|
||||
test('there is an undo stop between deleting left and deleting right', () => {
|
||||
let model = Model.createFromString(
|
||||
[
|
||||
'A line',
|
||||
'Another line',
|
||||
].join('\n')
|
||||
);
|
||||
|
||||
withMockCodeEditor(null, { model: model }, (editor, cursor) => {
|
||||
cursor.setSelections('test', [new Selection(2, 8, 2, 8)]);
|
||||
CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null);
|
||||
CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null);
|
||||
CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null);
|
||||
CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null);
|
||||
CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null);
|
||||
CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null);
|
||||
CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null);
|
||||
assert.equal(model.getLineContent(2), ' line');
|
||||
assertCursor(cursor, new Selection(2, 1, 2, 1));
|
||||
|
||||
CoreEditingCommands.DeleteRight.runEditorCommand(null, editor, null);
|
||||
CoreEditingCommands.DeleteRight.runEditorCommand(null, editor, null);
|
||||
CoreEditingCommands.DeleteRight.runEditorCommand(null, editor, null);
|
||||
CoreEditingCommands.DeleteRight.runEditorCommand(null, editor, null);
|
||||
CoreEditingCommands.DeleteRight.runEditorCommand(null, editor, null);
|
||||
assert.equal(model.getLineContent(2), '');
|
||||
assertCursor(cursor, new Selection(2, 1, 2, 1));
|
||||
|
||||
cursorCommand(cursor, H.Undo, {});
|
||||
assert.equal(model.getLineContent(2), ' line');
|
||||
assertCursor(cursor, new Selection(2, 1, 2, 1));
|
||||
|
||||
cursorCommand(cursor, H.Undo, {});
|
||||
assert.equal(model.getLineContent(2), 'Another line');
|
||||
assertCursor(cursor, new Selection(2, 8, 2, 8));
|
||||
});
|
||||
});
|
||||
|
||||
test('there is an undo stop between deleting right and typing', () => {
|
||||
let model = Model.createFromString(
|
||||
[
|
||||
'A line',
|
||||
'Another line',
|
||||
].join('\n')
|
||||
);
|
||||
|
||||
withMockCodeEditor(null, { model: model }, (editor, cursor) => {
|
||||
cursor.setSelections('test', [new Selection(2, 9, 2, 9)]);
|
||||
CoreEditingCommands.DeleteRight.runEditorCommand(null, editor, null);
|
||||
CoreEditingCommands.DeleteRight.runEditorCommand(null, editor, null);
|
||||
CoreEditingCommands.DeleteRight.runEditorCommand(null, editor, null);
|
||||
CoreEditingCommands.DeleteRight.runEditorCommand(null, editor, null);
|
||||
assert.equal(model.getLineContent(2), 'Another ');
|
||||
assertCursor(cursor, new Selection(2, 9, 2, 9));
|
||||
|
||||
cursorCommand(cursor, H.Type, { text: 'text' }, 'keyboard');
|
||||
assert.equal(model.getLineContent(2), 'Another text');
|
||||
assertCursor(cursor, new Selection(2, 13, 2, 13));
|
||||
|
||||
cursorCommand(cursor, H.Undo, {});
|
||||
assert.equal(model.getLineContent(2), 'Another ');
|
||||
assertCursor(cursor, new Selection(2, 9, 2, 9));
|
||||
|
||||
cursorCommand(cursor, H.Undo, {});
|
||||
assert.equal(model.getLineContent(2), 'Another line');
|
||||
assertCursor(cursor, new Selection(2, 9, 2, 9));
|
||||
});
|
||||
});
|
||||
|
||||
test('there is an undo stop between deleting right and deleting left', () => {
|
||||
let model = Model.createFromString(
|
||||
[
|
||||
'A line',
|
||||
'Another line',
|
||||
].join('\n')
|
||||
);
|
||||
|
||||
withMockCodeEditor(null, { model: model }, (editor, cursor) => {
|
||||
cursor.setSelections('test', [new Selection(2, 9, 2, 9)]);
|
||||
CoreEditingCommands.DeleteRight.runEditorCommand(null, editor, null);
|
||||
CoreEditingCommands.DeleteRight.runEditorCommand(null, editor, null);
|
||||
CoreEditingCommands.DeleteRight.runEditorCommand(null, editor, null);
|
||||
CoreEditingCommands.DeleteRight.runEditorCommand(null, editor, null);
|
||||
assert.equal(model.getLineContent(2), 'Another ');
|
||||
assertCursor(cursor, new Selection(2, 9, 2, 9));
|
||||
|
||||
CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null);
|
||||
CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null);
|
||||
CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null);
|
||||
CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null);
|
||||
CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null);
|
||||
CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null);
|
||||
assert.equal(model.getLineContent(2), 'An');
|
||||
assertCursor(cursor, new Selection(2, 3, 2, 3));
|
||||
|
||||
cursorCommand(cursor, H.Undo, {});
|
||||
assert.equal(model.getLineContent(2), 'Another ');
|
||||
assertCursor(cursor, new Selection(2, 9, 2, 9));
|
||||
|
||||
cursorCommand(cursor, H.Undo, {});
|
||||
assert.equal(model.getLineContent(2), 'Another line');
|
||||
assertCursor(cursor, new Selection(2, 9, 2, 9));
|
||||
});
|
||||
});
|
||||
|
||||
test('inserts undo stop when typing space', () => {
|
||||
let model = Model.createFromString(
|
||||
[
|
||||
'A line',
|
||||
'Another line',
|
||||
].join('\n')
|
||||
);
|
||||
|
||||
withMockCodeEditor(null, { model: model }, (editor, cursor) => {
|
||||
cursor.setSelections('test', [new Selection(1, 3, 1, 3)]);
|
||||
cursorCommand(cursor, H.Type, { text: 'first and interesting' }, 'keyboard');
|
||||
assert.equal(model.getLineContent(1), 'A first and interesting line');
|
||||
assertCursor(cursor, new Selection(1, 24, 1, 24));
|
||||
|
||||
cursorCommand(cursor, H.Undo, {});
|
||||
assert.equal(model.getLineContent(1), 'A first and line');
|
||||
assertCursor(cursor, new Selection(1, 12, 1, 12));
|
||||
|
||||
cursorCommand(cursor, H.Undo, {});
|
||||
assert.equal(model.getLineContent(1), 'A first line');
|
||||
assertCursor(cursor, new Selection(1, 8, 1, 8));
|
||||
|
||||
cursorCommand(cursor, H.Undo, {});
|
||||
assert.equal(model.getLineContent(1), 'A line');
|
||||
assertCursor(cursor, new Selection(1, 3, 1, 3));
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -18,6 +18,9 @@ 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);
|
||||
}
|
||||
@@ -25,7 +28,7 @@ export class MockCodeEditor extends CommonCodeEditor {
|
||||
public layout(dimension?: editorCommon.IDimension): void { }
|
||||
|
||||
public focus(): void { }
|
||||
public isFocused(): boolean { return true; }
|
||||
public isFocused(): boolean { return this._isFocused; }
|
||||
public hasWidgetFocus(): boolean { return true; };
|
||||
|
||||
protected _enableEmptySelectionClipboard(): boolean { return false; }
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { EndOfLinePreference, EndOfLineSequence, IIdentifiedSingleEditOperation } from 'vs/editor/common/editorCommon';
|
||||
import { EndOfLineSequence, IIdentifiedSingleEditOperation } from 'vs/editor/common/editorCommon';
|
||||
import { EditableTextModel, IValidatedEditOperation } from 'vs/editor/common/model/editableTextModel';
|
||||
import { MirrorModel } from 'vs/editor/common/model/mirrorModel';
|
||||
import { assertSyncedModels, testApplyEditsWithSyncedModels } from 'vs/editor/test/common/model/editableTextModelTestUtils';
|
||||
@@ -15,12 +15,13 @@ import { IModelContentChangedEvent } from 'vs/editor/common/model/textModelEvent
|
||||
|
||||
suite('EditorModel - EditableTextModel._getInverseEdits', () => {
|
||||
|
||||
function editOp(startLineNumber: number, startColumn: number, endLineNumber: number, endColumn: number, rangeLength: number, text: string[]): IValidatedEditOperation {
|
||||
function editOp(startLineNumber: number, startColumn: number, endLineNumber: number, endColumn: number, text: string[]): IValidatedEditOperation {
|
||||
return {
|
||||
sortIndex: 0,
|
||||
identifier: null,
|
||||
range: new Range(startLineNumber, startColumn, endLineNumber, endColumn),
|
||||
rangeLength: rangeLength,
|
||||
rangeOffset: 0,
|
||||
rangeLength: 0,
|
||||
lines: text,
|
||||
forceMoveMarkers: false,
|
||||
isAutoWhitespaceEdit: false
|
||||
@@ -39,7 +40,7 @@ suite('EditorModel - EditableTextModel._getInverseEdits', () => {
|
||||
test('single insert', () => {
|
||||
assertInverseEdits(
|
||||
[
|
||||
editOp(1, 1, 1, 1, 0, ['hello'])
|
||||
editOp(1, 1, 1, 1, ['hello'])
|
||||
],
|
||||
[
|
||||
inverseEditOp(1, 1, 1, 6)
|
||||
@@ -50,8 +51,8 @@ suite('EditorModel - EditableTextModel._getInverseEdits', () => {
|
||||
test('Bug 19872: Undo is funky', () => {
|
||||
assertInverseEdits(
|
||||
[
|
||||
editOp(2, 1, 2, 2, 0, ['']),
|
||||
editOp(3, 1, 4, 2, 0, [''])
|
||||
editOp(2, 1, 2, 2, ['']),
|
||||
editOp(3, 1, 4, 2, [''])
|
||||
],
|
||||
[
|
||||
inverseEditOp(2, 1, 2, 1),
|
||||
@@ -63,8 +64,8 @@ suite('EditorModel - EditableTextModel._getInverseEdits', () => {
|
||||
test('two single unrelated inserts', () => {
|
||||
assertInverseEdits(
|
||||
[
|
||||
editOp(1, 1, 1, 1, 0, ['hello']),
|
||||
editOp(2, 1, 2, 1, 0, ['world'])
|
||||
editOp(1, 1, 1, 1, ['hello']),
|
||||
editOp(2, 1, 2, 1, ['world'])
|
||||
],
|
||||
[
|
||||
inverseEditOp(1, 1, 1, 6),
|
||||
@@ -76,8 +77,8 @@ suite('EditorModel - EditableTextModel._getInverseEdits', () => {
|
||||
test('two single inserts 1', () => {
|
||||
assertInverseEdits(
|
||||
[
|
||||
editOp(1, 1, 1, 1, 0, ['hello']),
|
||||
editOp(1, 2, 1, 2, 0, ['world'])
|
||||
editOp(1, 1, 1, 1, ['hello']),
|
||||
editOp(1, 2, 1, 2, ['world'])
|
||||
],
|
||||
[
|
||||
inverseEditOp(1, 1, 1, 6),
|
||||
@@ -89,8 +90,8 @@ suite('EditorModel - EditableTextModel._getInverseEdits', () => {
|
||||
test('two single inserts 2', () => {
|
||||
assertInverseEdits(
|
||||
[
|
||||
editOp(1, 1, 1, 1, 0, ['hello']),
|
||||
editOp(1, 4, 1, 4, 0, ['world'])
|
||||
editOp(1, 1, 1, 1, ['hello']),
|
||||
editOp(1, 4, 1, 4, ['world'])
|
||||
],
|
||||
[
|
||||
inverseEditOp(1, 1, 1, 6),
|
||||
@@ -102,7 +103,7 @@ suite('EditorModel - EditableTextModel._getInverseEdits', () => {
|
||||
test('multiline insert', () => {
|
||||
assertInverseEdits(
|
||||
[
|
||||
editOp(1, 1, 1, 1, 0, ['hello', 'world'])
|
||||
editOp(1, 1, 1, 1, ['hello', 'world'])
|
||||
],
|
||||
[
|
||||
inverseEditOp(1, 1, 2, 6)
|
||||
@@ -113,8 +114,8 @@ suite('EditorModel - EditableTextModel._getInverseEdits', () => {
|
||||
test('two unrelated multiline inserts', () => {
|
||||
assertInverseEdits(
|
||||
[
|
||||
editOp(1, 1, 1, 1, 0, ['hello', 'world']),
|
||||
editOp(2, 1, 2, 1, 0, ['how', 'are', 'you?']),
|
||||
editOp(1, 1, 1, 1, ['hello', 'world']),
|
||||
editOp(2, 1, 2, 1, ['how', 'are', 'you?']),
|
||||
],
|
||||
[
|
||||
inverseEditOp(1, 1, 2, 6),
|
||||
@@ -126,8 +127,8 @@ suite('EditorModel - EditableTextModel._getInverseEdits', () => {
|
||||
test('two multiline inserts 1', () => {
|
||||
assertInverseEdits(
|
||||
[
|
||||
editOp(1, 1, 1, 1, 0, ['hello', 'world']),
|
||||
editOp(1, 2, 1, 2, 0, ['how', 'are', 'you?']),
|
||||
editOp(1, 1, 1, 1, ['hello', 'world']),
|
||||
editOp(1, 2, 1, 2, ['how', 'are', 'you?']),
|
||||
],
|
||||
[
|
||||
inverseEditOp(1, 1, 2, 6),
|
||||
@@ -139,7 +140,7 @@ suite('EditorModel - EditableTextModel._getInverseEdits', () => {
|
||||
test('single delete', () => {
|
||||
assertInverseEdits(
|
||||
[
|
||||
editOp(1, 1, 1, 6, 0, null)
|
||||
editOp(1, 1, 1, 6, null)
|
||||
],
|
||||
[
|
||||
inverseEditOp(1, 1, 1, 1)
|
||||
@@ -150,8 +151,8 @@ suite('EditorModel - EditableTextModel._getInverseEdits', () => {
|
||||
test('two single unrelated deletes', () => {
|
||||
assertInverseEdits(
|
||||
[
|
||||
editOp(1, 1, 1, 6, 0, null),
|
||||
editOp(2, 1, 2, 6, 0, null)
|
||||
editOp(1, 1, 1, 6, null),
|
||||
editOp(2, 1, 2, 6, null)
|
||||
],
|
||||
[
|
||||
inverseEditOp(1, 1, 1, 1),
|
||||
@@ -163,8 +164,8 @@ suite('EditorModel - EditableTextModel._getInverseEdits', () => {
|
||||
test('two single deletes 1', () => {
|
||||
assertInverseEdits(
|
||||
[
|
||||
editOp(1, 1, 1, 6, 0, null),
|
||||
editOp(1, 7, 1, 12, 0, null)
|
||||
editOp(1, 1, 1, 6, null),
|
||||
editOp(1, 7, 1, 12, null)
|
||||
],
|
||||
[
|
||||
inverseEditOp(1, 1, 1, 1),
|
||||
@@ -176,8 +177,8 @@ suite('EditorModel - EditableTextModel._getInverseEdits', () => {
|
||||
test('two single deletes 2', () => {
|
||||
assertInverseEdits(
|
||||
[
|
||||
editOp(1, 1, 1, 6, 0, null),
|
||||
editOp(1, 9, 1, 14, 0, null)
|
||||
editOp(1, 1, 1, 6, null),
|
||||
editOp(1, 9, 1, 14, null)
|
||||
],
|
||||
[
|
||||
inverseEditOp(1, 1, 1, 1),
|
||||
@@ -189,7 +190,7 @@ suite('EditorModel - EditableTextModel._getInverseEdits', () => {
|
||||
test('multiline delete', () => {
|
||||
assertInverseEdits(
|
||||
[
|
||||
editOp(1, 1, 2, 6, 0, null)
|
||||
editOp(1, 1, 2, 6, null)
|
||||
],
|
||||
[
|
||||
inverseEditOp(1, 1, 1, 1)
|
||||
@@ -200,8 +201,8 @@ suite('EditorModel - EditableTextModel._getInverseEdits', () => {
|
||||
test('two unrelated multiline deletes', () => {
|
||||
assertInverseEdits(
|
||||
[
|
||||
editOp(1, 1, 2, 6, 0, null),
|
||||
editOp(3, 1, 5, 5, 0, null),
|
||||
editOp(1, 1, 2, 6, null),
|
||||
editOp(3, 1, 5, 5, null),
|
||||
],
|
||||
[
|
||||
inverseEditOp(1, 1, 1, 1),
|
||||
@@ -213,8 +214,8 @@ suite('EditorModel - EditableTextModel._getInverseEdits', () => {
|
||||
test('two multiline deletes 1', () => {
|
||||
assertInverseEdits(
|
||||
[
|
||||
editOp(1, 1, 2, 6, 0, null),
|
||||
editOp(2, 7, 4, 5, 0, null),
|
||||
editOp(1, 1, 2, 6, null),
|
||||
editOp(2, 7, 4, 5, null),
|
||||
],
|
||||
[
|
||||
inverseEditOp(1, 1, 1, 1),
|
||||
@@ -226,7 +227,7 @@ suite('EditorModel - EditableTextModel._getInverseEdits', () => {
|
||||
test('single replace', () => {
|
||||
assertInverseEdits(
|
||||
[
|
||||
editOp(1, 1, 1, 6, 0, ['Hello world'])
|
||||
editOp(1, 1, 1, 6, ['Hello world'])
|
||||
],
|
||||
[
|
||||
inverseEditOp(1, 1, 1, 12)
|
||||
@@ -237,8 +238,8 @@ suite('EditorModel - EditableTextModel._getInverseEdits', () => {
|
||||
test('two replaces', () => {
|
||||
assertInverseEdits(
|
||||
[
|
||||
editOp(1, 1, 1, 6, 0, ['Hello world']),
|
||||
editOp(1, 7, 1, 8, 0, ['How are you?']),
|
||||
editOp(1, 1, 1, 6, ['Hello world']),
|
||||
editOp(1, 7, 1, 8, ['How are you?']),
|
||||
],
|
||||
[
|
||||
inverseEditOp(1, 1, 1, 12),
|
||||
@@ -250,9 +251,9 @@ suite('EditorModel - EditableTextModel._getInverseEdits', () => {
|
||||
test('many edits', () => {
|
||||
assertInverseEdits(
|
||||
[
|
||||
editOp(1, 2, 1, 2, 0, ['', ' ']),
|
||||
editOp(1, 5, 1, 6, 0, ['']),
|
||||
editOp(1, 9, 1, 9, 0, ['', ''])
|
||||
editOp(1, 2, 1, 2, ['', ' ']),
|
||||
editOp(1, 5, 1, 6, ['']),
|
||||
editOp(1, 9, 1, 9, ['', ''])
|
||||
],
|
||||
[
|
||||
inverseEditOp(1, 2, 2, 3),
|
||||
@@ -265,11 +266,12 @@ suite('EditorModel - EditableTextModel._getInverseEdits', () => {
|
||||
|
||||
suite('EditorModel - EditableTextModel._toSingleEditOperation', () => {
|
||||
|
||||
function editOp(startLineNumber: number, startColumn: number, endLineNumber: number, endColumn: number, rangeLength: number, text: string[]): IValidatedEditOperation {
|
||||
function editOp(startLineNumber: number, startColumn: number, endLineNumber: number, endColumn: number, rangeOffset: number, rangeLength: number, text: string[]): IValidatedEditOperation {
|
||||
return {
|
||||
sortIndex: 0,
|
||||
identifier: null,
|
||||
range: new Range(startLineNumber, startColumn, endLineNumber, endColumn),
|
||||
rangeOffset: rangeOffset,
|
||||
rangeLength: rangeLength,
|
||||
lines: text,
|
||||
forceMoveMarkers: false,
|
||||
@@ -297,9 +299,9 @@ suite('EditorModel - EditableTextModel._toSingleEditOperation', () => {
|
||||
'1'
|
||||
],
|
||||
[
|
||||
editOp(1, 3, 1, 3, 0, [' new line', 'No longer'])
|
||||
editOp(1, 3, 1, 3, 2, 0, [' new line', 'No longer'])
|
||||
],
|
||||
editOp(1, 3, 1, 3, 0, [' new line', 'No longer'])
|
||||
editOp(1, 3, 1, 3, 2, 0, [' new line', 'No longer'])
|
||||
);
|
||||
});
|
||||
|
||||
@@ -311,11 +313,11 @@ suite('EditorModel - EditableTextModel._toSingleEditOperation', () => {
|
||||
'',
|
||||
'1'
|
||||
], [
|
||||
editOp(1, 1, 1, 3, 0, ['Your']),
|
||||
editOp(1, 4, 1, 4, 0, ['Interesting ']),
|
||||
editOp(2, 3, 2, 6, 0, null)
|
||||
editOp(1, 1, 1, 3, 0, 2, ['Your']),
|
||||
editOp(1, 4, 1, 4, 3, 0, ['Interesting ']),
|
||||
editOp(2, 3, 2, 6, 16, 3, null)
|
||||
],
|
||||
editOp(1, 1, 2, 6, 19, [
|
||||
editOp(1, 1, 2, 6, 0, 19, [
|
||||
'Your Interesting First Line',
|
||||
'\t\t'
|
||||
]));
|
||||
@@ -331,10 +333,10 @@ suite('EditorModel - EditableTextModel._toSingleEditOperation', () => {
|
||||
'1'
|
||||
],
|
||||
[
|
||||
editOp(1, 3, 1, 3, 0, ['', '', '', '', '']),
|
||||
editOp(3, 15, 3, 15, 0, ['a', 'b'])
|
||||
editOp(1, 3, 1, 3, 2, 0, ['', '', '', '', '']),
|
||||
editOp(3, 15, 3, 15, 45, 0, ['a', 'b'])
|
||||
],
|
||||
editOp(1, 3, 3, 15, 43, [
|
||||
editOp(1, 3, 3, 15, 2, 43, [
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
@@ -357,9 +359,9 @@ suite('EditorModel - EditableTextModel._toSingleEditOperation', () => {
|
||||
'1'
|
||||
],
|
||||
[
|
||||
editOp(1, 1, 1, 1, 0, [''])
|
||||
editOp(1, 1, 1, 1, 0, 0, [''])
|
||||
],
|
||||
editOp(1, 1, 1, 1, 0, [''])
|
||||
editOp(1, 1, 1, 1, 0, 0, [''])
|
||||
);
|
||||
});
|
||||
|
||||
@@ -373,10 +375,10 @@ suite('EditorModel - EditableTextModel._toSingleEditOperation', () => {
|
||||
'123'
|
||||
],
|
||||
[
|
||||
editOp(2, 1, 2, 3, 0, ['\t']),
|
||||
editOp(3, 1, 3, 5, 0, [''])
|
||||
editOp(2, 1, 2, 3, 14, 2, ['\t']),
|
||||
editOp(3, 1, 3, 5, 31, 4, [''])
|
||||
],
|
||||
editOp(2, 1, 3, 5, 21, ['\tMy Second Line', ''])
|
||||
editOp(2, 1, 3, 5, 14, 21, ['\tMy Second Line', ''])
|
||||
);
|
||||
});
|
||||
|
||||
@@ -386,11 +388,11 @@ suite('EditorModel - EditableTextModel._toSingleEditOperation', () => {
|
||||
'{"x" : 1}'
|
||||
],
|
||||
[
|
||||
editOp(1, 2, 1, 2, 0, ['\n ']),
|
||||
editOp(1, 5, 1, 6, 0, ['']),
|
||||
editOp(1, 9, 1, 9, 0, ['\n'])
|
||||
editOp(1, 2, 1, 2, 1, 0, ['\n ']),
|
||||
editOp(1, 5, 1, 6, 4, 1, ['']),
|
||||
editOp(1, 9, 1, 9, 8, 0, ['\n'])
|
||||
],
|
||||
editOp(1, 2, 1, 9, 7, [
|
||||
editOp(1, 2, 1, 9, 1, 7, [
|
||||
'',
|
||||
' "x": 1',
|
||||
''
|
||||
@@ -406,11 +408,11 @@ suite('EditorModel - EditableTextModel._toSingleEditOperation', () => {
|
||||
'}'
|
||||
],
|
||||
[
|
||||
editOp(1, 2, 2, 3, 0, ['']),
|
||||
editOp(2, 6, 2, 6, 0, [' ']),
|
||||
editOp(2, 9, 3, 1, 0, [''])
|
||||
editOp(1, 2, 2, 3, 1, 3, ['']),
|
||||
editOp(2, 6, 2, 6, 7, 0, [' ']),
|
||||
editOp(2, 9, 3, 1, 10, 1, [''])
|
||||
],
|
||||
editOp(1, 2, 3, 1, 10, ['"x" : 1'])
|
||||
editOp(1, 2, 3, 1, 1, 10, ['"x" : 1'])
|
||||
);
|
||||
});
|
||||
|
||||
@@ -424,10 +426,10 @@ suite('EditorModel - EditableTextModel._toSingleEditOperation', () => {
|
||||
'}'
|
||||
],
|
||||
[
|
||||
editOp(1, 2, 2, 1, 0, ['', '\t']),
|
||||
editOp(2, 11, 4, 1, 0, ['', '\t'])
|
||||
editOp(1, 2, 2, 1, 1, 1, ['', '\t']),
|
||||
editOp(2, 11, 4, 1, 12, 2, ['', '\t'])
|
||||
],
|
||||
editOp(1, 2, 4, 1, 13, [
|
||||
editOp(1, 2, 4, 1, 1, 13, [
|
||||
'',
|
||||
'\t"a": true,',
|
||||
'\t'
|
||||
@@ -446,12 +448,12 @@ suite('EditorModel - EditableTextModel._toSingleEditOperation', () => {
|
||||
'and the last line'
|
||||
],
|
||||
[
|
||||
editOp(1, 5, 3, 1, 0, [' text', 'some more text', 'some more text']),
|
||||
editOp(3, 2, 4, 1, 0, ['o more lines', 'asd', 'asd', 'asd']),
|
||||
editOp(5, 1, 5, 6, 0, ['zzzzzzzz']),
|
||||
editOp(5, 11, 6, 16, 0, ['1', '2', '3', '4'])
|
||||
editOp(1, 5, 3, 1, 4, 21, [' text', 'some more text', 'some more text']),
|
||||
editOp(3, 2, 4, 1, 26, 23, ['o more lines', 'asd', 'asd', 'asd']),
|
||||
editOp(5, 1, 5, 6, 50, 5, ['zzzzzzzz']),
|
||||
editOp(5, 11, 6, 16, 60, 22, ['1', '2', '3', '4'])
|
||||
],
|
||||
editOp(1, 5, 6, 16, 78, [
|
||||
editOp(1, 5, 6, 16, 4, 78, [
|
||||
' text',
|
||||
'some more text',
|
||||
'some more textno more lines',
|
||||
@@ -475,17 +477,17 @@ suite('EditorModel - EditableTextModel._toSingleEditOperation', () => {
|
||||
' ,"e": /*comment*/ [null] }',
|
||||
],
|
||||
[
|
||||
editOp(1, 1, 1, 2, 0, ['']),
|
||||
editOp(1, 3, 1, 10, 0, ['', ' ']),
|
||||
editOp(1, 16, 2, 14, 0, ['', ' ']),
|
||||
editOp(2, 18, 3, 9, 0, ['', ' ']),
|
||||
editOp(3, 22, 4, 9, 0, ['']),
|
||||
editOp(4, 10, 4, 10, 0, ['', ' ']),
|
||||
editOp(4, 28, 4, 28, 0, ['', ' ']),
|
||||
editOp(4, 32, 4, 32, 0, ['', ' ']),
|
||||
editOp(4, 33, 4, 34, 0, ['', ''])
|
||||
editOp(1, 1, 1, 2, 0, 1, ['']),
|
||||
editOp(1, 3, 1, 10, 2, 7, ['', ' ']),
|
||||
editOp(1, 16, 2, 14, 15, 14, ['', ' ']),
|
||||
editOp(2, 18, 3, 9, 33, 9, ['', ' ']),
|
||||
editOp(3, 22, 4, 9, 55, 9, ['']),
|
||||
editOp(4, 10, 4, 10, 65, 0, ['', ' ']),
|
||||
editOp(4, 28, 4, 28, 83, 0, ['', ' ']),
|
||||
editOp(4, 32, 4, 32, 87, 0, ['', ' ']),
|
||||
editOp(4, 33, 4, 34, 88, 1, ['', ''])
|
||||
],
|
||||
editOp(1, 1, 4, 34, 89, [
|
||||
editOp(1, 1, 4, 34, 0, 89, [
|
||||
'{',
|
||||
' "d": [',
|
||||
' null',
|
||||
@@ -505,11 +507,11 @@ suite('EditorModel - EditableTextModel._toSingleEditOperation', () => {
|
||||
' ,def'
|
||||
],
|
||||
[
|
||||
editOp(1, 1, 1, 4, 0, ['']),
|
||||
editOp(1, 7, 2, 2, 0, ['']),
|
||||
editOp(2, 3, 2, 3, 0, ['', ''])
|
||||
editOp(1, 1, 1, 4, 0, 3, ['']),
|
||||
editOp(1, 7, 2, 2, 6, 2, ['']),
|
||||
editOp(2, 3, 2, 3, 9, 0, ['', ''])
|
||||
],
|
||||
editOp(1, 1, 2, 3, 9, [
|
||||
editOp(1, 1, 2, 3, 0, 9, [
|
||||
'abc,',
|
||||
''
|
||||
])
|
||||
@@ -1567,7 +1569,6 @@ suite('EditorModel - EditableTextModel.applyEdits', () => {
|
||||
});
|
||||
|
||||
let assertMirrorModels = () => {
|
||||
model._assertLineNumbersOK();
|
||||
assert.equal(mirrorModel2.getText(), model.getValue(), 'mirror model 2 text OK');
|
||||
assert.equal(mirrorModel2.version, model.getVersionId(), 'mirror model 2 version OK');
|
||||
};
|
||||
@@ -1579,257 +1580,3 @@ suite('EditorModel - EditableTextModel.applyEdits', () => {
|
||||
mirrorModel2.dispose();
|
||||
});
|
||||
});
|
||||
|
||||
interface ILightWeightMarker {
|
||||
id: string;
|
||||
lineNumber: number;
|
||||
column: number;
|
||||
stickToPreviousCharacter: boolean;
|
||||
}
|
||||
|
||||
suite('EditorModel - EditableTextModel.applyEdits & markers', () => {
|
||||
|
||||
function editOp(startLineNumber: number, startColumn: number, endLineNumber: number, endColumn: number, text: string[]): IIdentifiedSingleEditOperation {
|
||||
return {
|
||||
identifier: null,
|
||||
range: new Range(startLineNumber, startColumn, endLineNumber, endColumn),
|
||||
text: text.join('\n'),
|
||||
forceMoveMarkers: false
|
||||
};
|
||||
}
|
||||
|
||||
function marker(id: string, lineNumber: number, column: number, stickToPreviousCharacter: boolean): ILightWeightMarker {
|
||||
return {
|
||||
id: id,
|
||||
lineNumber: lineNumber,
|
||||
column: column,
|
||||
stickToPreviousCharacter: stickToPreviousCharacter
|
||||
};
|
||||
}
|
||||
|
||||
function toMarkersMap(markers: ILightWeightMarker[]): { [markerId: string]: ILightWeightMarker } {
|
||||
var result: { [markerId: string]: ILightWeightMarker } = {};
|
||||
markers.forEach(m => {
|
||||
result[m.id] = m;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
function testApplyEditsAndMarkers(text: string[], markers: ILightWeightMarker[], edits: IIdentifiedSingleEditOperation[], changedMarkers: string[], expectedText: string[], expectedMarkers: ILightWeightMarker[]): void {
|
||||
var textStr = text.join('\n');
|
||||
var expectedTextStr = expectedText.join('\n');
|
||||
var markersMap = toMarkersMap(markers);
|
||||
// var expectedMarkersMap = toMarkersMap(expectedMarkers);
|
||||
var markerId2ModelMarkerId = Object.create(null);
|
||||
|
||||
var model = EditableTextModel.createFromString(textStr);
|
||||
model.setEOL(EndOfLineSequence.LF);
|
||||
|
||||
// Add markers
|
||||
markers.forEach((m) => {
|
||||
let modelMarkerId = model._addMarker(0, m.lineNumber, m.column, m.stickToPreviousCharacter);
|
||||
markerId2ModelMarkerId[m.id] = modelMarkerId;
|
||||
});
|
||||
|
||||
// Apply edits & collect inverse edits
|
||||
model.applyEdits(edits);
|
||||
model._assertLineNumbersOK();
|
||||
|
||||
// Assert edits produced expected result
|
||||
assert.deepEqual(model.getValue(EndOfLinePreference.LF), expectedTextStr);
|
||||
|
||||
let actualChangedMarkers: string[] = [];
|
||||
for (let i = 0, len = expectedMarkers.length; i < len; i++) {
|
||||
let expectedMarker = expectedMarkers[i];
|
||||
let initialMarker = markersMap[expectedMarker.id];
|
||||
let expectedMarkerModelMarkerId = markerId2ModelMarkerId[expectedMarker.id];
|
||||
let actualMarker = model._getMarker(expectedMarkerModelMarkerId);
|
||||
|
||||
if (actualMarker.lineNumber !== initialMarker.lineNumber || actualMarker.column !== initialMarker.column) {
|
||||
actualChangedMarkers.push(initialMarker.id);
|
||||
}
|
||||
|
||||
assert.equal(actualMarker.lineNumber, expectedMarker.lineNumber, 'marker lineNumber of marker ' + expectedMarker.id);
|
||||
assert.equal(actualMarker.column, expectedMarker.column, 'marker column of marker ' + expectedMarker.id);
|
||||
}
|
||||
|
||||
changedMarkers.sort();
|
||||
actualChangedMarkers.sort();
|
||||
assert.deepEqual(actualChangedMarkers, changedMarkers, 'changed markers');
|
||||
|
||||
model.dispose();
|
||||
}
|
||||
|
||||
test('no markers changed', () => {
|
||||
testApplyEditsAndMarkers(
|
||||
[
|
||||
'Hello world,',
|
||||
'this is a short text',
|
||||
'that is used in testing'
|
||||
],
|
||||
[
|
||||
marker('a', 1, 1, true),
|
||||
marker('b', 1, 1, false),
|
||||
marker('c', 1, 7, false),
|
||||
marker('d', 1, 12, true),
|
||||
marker('e', 2, 1, false),
|
||||
marker('f', 2, 16, true),
|
||||
marker('g', 2, 21, true),
|
||||
marker('h', 3, 24, false)
|
||||
],
|
||||
[
|
||||
editOp(1, 13, 1, 13, [' how are you?'])
|
||||
],
|
||||
[],
|
||||
[
|
||||
'Hello world, how are you?',
|
||||
'this is a short text',
|
||||
'that is used in testing'
|
||||
],
|
||||
[
|
||||
marker('a', 1, 1, true),
|
||||
marker('b', 1, 1, false),
|
||||
marker('c', 1, 7, false),
|
||||
marker('d', 1, 12, true),
|
||||
marker('e', 2, 1, false),
|
||||
marker('f', 2, 16, true),
|
||||
marker('g', 2, 21, true),
|
||||
marker('h', 3, 24, false)
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
test('first line changes', () => {
|
||||
testApplyEditsAndMarkers(
|
||||
[
|
||||
'Hello world,',
|
||||
'this is a short text',
|
||||
'that is used in testing'
|
||||
],
|
||||
[
|
||||
marker('a', 1, 1, true),
|
||||
marker('b', 1, 1, false),
|
||||
marker('c', 1, 7, false),
|
||||
marker('d', 1, 12, true),
|
||||
marker('e', 2, 1, false),
|
||||
marker('f', 2, 16, true),
|
||||
marker('g', 2, 21, true),
|
||||
marker('h', 3, 24, false)
|
||||
],
|
||||
[
|
||||
editOp(1, 7, 1, 12, ['friends'])
|
||||
],
|
||||
[],
|
||||
[
|
||||
'Hello friends,',
|
||||
'this is a short text',
|
||||
'that is used in testing'
|
||||
],
|
||||
[
|
||||
marker('a', 1, 1, true),
|
||||
marker('b', 1, 1, false),
|
||||
marker('c', 1, 7, false),
|
||||
marker('d', 1, 12, true),
|
||||
marker('e', 2, 1, false),
|
||||
marker('f', 2, 16, true),
|
||||
marker('g', 2, 21, true),
|
||||
marker('h', 3, 24, false)
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
test('inserting lines', () => {
|
||||
testApplyEditsAndMarkers(
|
||||
[
|
||||
'Hello world,',
|
||||
'this is a short text',
|
||||
'that is used in testing'
|
||||
],
|
||||
[
|
||||
marker('a', 1, 1, true),
|
||||
marker('b', 1, 1, false),
|
||||
marker('c', 1, 7, false),
|
||||
marker('d', 1, 12, true),
|
||||
marker('e', 2, 1, false),
|
||||
marker('f', 2, 16, true),
|
||||
marker('g', 2, 21, true),
|
||||
marker('h', 3, 24, false)
|
||||
],
|
||||
[
|
||||
editOp(1, 7, 1, 12, ['friends']),
|
||||
editOp(1, 13, 1, 13, ['', 'this is an inserted line', 'and another one. By the way,'])
|
||||
],
|
||||
['e', 'f', 'g', 'h'],
|
||||
[
|
||||
'Hello friends,',
|
||||
'this is an inserted line',
|
||||
'and another one. By the way,',
|
||||
'this is a short text',
|
||||
'that is used in testing'
|
||||
],
|
||||
[
|
||||
marker('a', 1, 1, true),
|
||||
marker('b', 1, 1, false),
|
||||
marker('c', 1, 7, false),
|
||||
marker('d', 1, 12, true),
|
||||
marker('e', 4, 1, false),
|
||||
marker('f', 4, 16, true),
|
||||
marker('g', 4, 21, true),
|
||||
marker('h', 5, 24, false)
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
test('replacing a lot', () => {
|
||||
testApplyEditsAndMarkers(
|
||||
[
|
||||
'Hello world,',
|
||||
'this is a short text',
|
||||
'that is used in testing',
|
||||
'more lines...',
|
||||
'more lines...',
|
||||
'more lines...',
|
||||
'more lines...'
|
||||
],
|
||||
[
|
||||
marker('a', 1, 1, true),
|
||||
marker('b', 1, 1, false),
|
||||
marker('c', 1, 7, false),
|
||||
marker('d', 1, 12, true),
|
||||
marker('e', 2, 1, false),
|
||||
marker('f', 2, 16, true),
|
||||
marker('g', 2, 21, true),
|
||||
marker('h', 3, 24, false),
|
||||
marker('i', 5, 1, false),
|
||||
marker('j', 6, 1, false),
|
||||
marker('k', 7, 14, false),
|
||||
],
|
||||
[
|
||||
editOp(1, 7, 1, 12, ['friends']),
|
||||
editOp(1, 13, 1, 13, ['', 'this is an inserted line', 'and another one. By the way,', 'This is another line']),
|
||||
editOp(2, 1, 7, 14, ['Some new text here'])
|
||||
],
|
||||
['e', 'f', 'g', 'h', 'i', 'j', 'k'],
|
||||
[
|
||||
'Hello friends,',
|
||||
'this is an inserted line',
|
||||
'and another one. By the way,',
|
||||
'This is another line',
|
||||
'Some new text here'
|
||||
],
|
||||
[
|
||||
marker('a', 1, 1, true),
|
||||
marker('b', 1, 1, false),
|
||||
marker('c', 1, 7, false),
|
||||
marker('d', 1, 12, true),
|
||||
marker('e', 5, 1, false),
|
||||
marker('f', 5, 16, true),
|
||||
marker('g', 5, 19, true),
|
||||
marker('h', 5, 19, false),
|
||||
marker('i', 5, 19, false),
|
||||
marker('j', 5, 19, false),
|
||||
marker('k', 5, 19, false),
|
||||
]
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -105,7 +105,6 @@ export function assertSyncedModels(text: string, callback: (model: EditableTextM
|
||||
|
||||
var assertMirrorModels = () => {
|
||||
assertLineMapping(model, 'model');
|
||||
model._assertLineNumbersOK();
|
||||
assert.equal(mirrorModel2.getText(), model.getValue(), 'mirror model 2 text OK');
|
||||
assert.equal(mirrorModel2.version, model.getVersionId(), 'mirror model 2 version OK');
|
||||
};
|
||||
|
||||
@@ -7,62 +7,76 @@
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { Model } from 'vs/editor/common/model/model';
|
||||
import { computeRanges } from 'vs/editor/common/model/indentRanges';
|
||||
import { computeRanges, MAX_FOLDING_REGIONS } from 'vs/editor/common/model/indentRanges';
|
||||
import { FoldingMarkers } from 'vs/editor/common/modes/languageConfiguration';
|
||||
|
||||
export interface IndentRange {
|
||||
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', () => {
|
||||
function assertRanges(lines: string[], expected: IndentRange[]): void {
|
||||
let model = Model.createFromString(lines.join('\n'));
|
||||
let actual = computeRanges(model);
|
||||
actual.sort((r1, r2) => r1.startLineNumber - r2.startLineNumber);
|
||||
assert.deepEqual(actual, expected);
|
||||
model.dispose();
|
||||
}
|
||||
|
||||
function r(startLineNumber: number, endLineNumber: number, indent: number): IndentRange {
|
||||
return { startLineNumber, endLineNumber, indent };
|
||||
}
|
||||
|
||||
test('Fold one level', () => {
|
||||
assertRanges([
|
||||
let range = [
|
||||
'A',
|
||||
' A',
|
||||
' A',
|
||||
' A'
|
||||
], [r(1, 4, 0)]);
|
||||
];
|
||||
assertRanges(range, [r(1, 4, 0, -1)], true);
|
||||
assertRanges(range, [r(1, 4, 0, -1)], false);
|
||||
});
|
||||
|
||||
test('Fold two levels', () => {
|
||||
assertRanges([
|
||||
let range = [
|
||||
'A',
|
||||
' A',
|
||||
' A',
|
||||
' A',
|
||||
' A'
|
||||
], [r(1, 5, 0), r(3, 5, 2)]);
|
||||
];
|
||||
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', () => {
|
||||
assertRanges([
|
||||
let range = [
|
||||
'A',
|
||||
' A',
|
||||
' A',
|
||||
' A',
|
||||
'A'
|
||||
], [r(1, 4, 0), r(2, 4, 2), r(3, 4, 4)]);
|
||||
];
|
||||
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', () => {
|
||||
assertRanges([
|
||||
let range = [
|
||||
' A',
|
||||
' A',
|
||||
'A'
|
||||
], []);
|
||||
];
|
||||
assertRanges(range, [], true);
|
||||
assertRanges(range, [], false);
|
||||
});
|
||||
|
||||
test('Fold Java', () => {
|
||||
@@ -80,7 +94,7 @@ suite('Indentation Folding', () => {
|
||||
/*11*/ 'interface B {',
|
||||
/*12*/ ' void bar();',
|
||||
/*13*/ '}',
|
||||
], [r(1, 9, 0), r(2, 4, 2), r(7, 8, 2), r(11, 12, 0)]);
|
||||
], [r(1, 9, 0, -1), r(2, 4, 2, 0), r(7, 8, 2, 0), r(11, 12, 0, -1)], false);
|
||||
});
|
||||
|
||||
test('Fold Javadoc', () => {
|
||||
@@ -92,9 +106,9 @@ suite('Indentation Folding', () => {
|
||||
/* 5*/ ' void foo() {',
|
||||
/* 6*/ ' }',
|
||||
/* 7*/ '}',
|
||||
], [r(1, 3, 0), r(4, 6, 0)]);
|
||||
], [r(1, 3, 0, -1), r(4, 6, 0, -1)], false);
|
||||
});
|
||||
test('Fold Whitespace', () => {
|
||||
test('Fold Whitespace Java', () => {
|
||||
assertRanges([
|
||||
/* 1*/ 'class A {',
|
||||
/* 2*/ '',
|
||||
@@ -104,7 +118,20 @@ suite('Indentation Folding', () => {
|
||||
/* 6*/ ' }',
|
||||
/* 7*/ ' ',
|
||||
/* 8*/ '}',
|
||||
], [r(1, 7, 0), r(3, 5, 2)]);
|
||||
], [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', () => {
|
||||
@@ -117,6 +144,245 @@ suite('Indentation Folding', () => {
|
||||
/* 6*/ ' \t}',
|
||||
/* 7*/ ' ',
|
||||
/* 8*/ '}',
|
||||
], [r(1, 7, 0), r(3, 5, 4)]);
|
||||
], [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();
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
555
src/vs/editor/test/common/model/intervalTree.test.ts
Normal file
555
src/vs/editor/test/common/model/intervalTree.test.ts
Normal file
@@ -0,0 +1,555 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { IntervalTree, IntervalNode } from 'vs/editor/common/model/intervalTree';
|
||||
|
||||
const GENERATE_TESTS = false;
|
||||
let TEST_COUNT = GENERATE_TESTS ? 10000 : 0;
|
||||
let PRINT_TREE = false;
|
||||
const MIN_INTERVAL_START = 1;
|
||||
const MAX_INTERVAL_END = 100;
|
||||
const MIN_INSERTS = 1;
|
||||
const MAX_INSERTS = 30;
|
||||
const MIN_CHANGE_CNT = 10;
|
||||
const MAX_CHANGE_CNT = 20;
|
||||
|
||||
suite('IntervalTree', () => {
|
||||
|
||||
class Interval {
|
||||
_intervalBrand: void;
|
||||
|
||||
public start: number;
|
||||
public end: number;
|
||||
|
||||
constructor(start: number, end: number) {
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
}
|
||||
}
|
||||
|
||||
class Oracle {
|
||||
public intervals: Interval[];
|
||||
|
||||
constructor() {
|
||||
this.intervals = [];
|
||||
}
|
||||
|
||||
public insert(interval: Interval): Interval {
|
||||
this.intervals.push(interval);
|
||||
this.intervals.sort((a, b) => {
|
||||
if (a.start === b.start) {
|
||||
return a.end - b.end;
|
||||
}
|
||||
return a.start - b.start;
|
||||
});
|
||||
return interval;
|
||||
}
|
||||
|
||||
public delete(interval: Interval): void {
|
||||
for (let i = 0, len = this.intervals.length; i < len; i++) {
|
||||
if (this.intervals[i] === interval) {
|
||||
this.intervals.splice(i, 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public search(interval: Interval): Interval[] {
|
||||
let result: Interval[] = [];
|
||||
for (let i = 0, len = this.intervals.length; i < len; i++) {
|
||||
let int = this.intervals[i];
|
||||
if (int.start <= interval.end && int.end >= interval.start) {
|
||||
result.push(int);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
class TestState {
|
||||
private _oracle: Oracle = new Oracle();
|
||||
private _tree: IntervalTree = new IntervalTree();
|
||||
private _lastNodeId = -1;
|
||||
private _treeNodes: IntervalNode[] = [];
|
||||
private _oracleNodes: Interval[] = [];
|
||||
|
||||
public acceptOp(op: IOperation): void {
|
||||
|
||||
if (op.type === 'insert') {
|
||||
if (PRINT_TREE) {
|
||||
console.log(`insert: {${JSON.stringify(new Interval(op.begin, op.end))}}`);
|
||||
}
|
||||
let nodeId = (++this._lastNodeId);
|
||||
this._treeNodes[nodeId] = new IntervalNode(null, op.begin, op.end);
|
||||
this._tree.insert(this._treeNodes[nodeId]);
|
||||
this._oracleNodes[nodeId] = this._oracle.insert(new Interval(op.begin, op.end));
|
||||
} else if (op.type === 'delete') {
|
||||
if (PRINT_TREE) {
|
||||
console.log(`delete: {${JSON.stringify(this._oracleNodes[op.id])}}`);
|
||||
}
|
||||
this._tree.delete(this._treeNodes[op.id]);
|
||||
this._oracle.delete(this._oracleNodes[op.id]);
|
||||
|
||||
this._treeNodes[op.id] = null;
|
||||
this._oracleNodes[op.id] = null;
|
||||
} else if (op.type === 'change') {
|
||||
|
||||
this._tree.delete(this._treeNodes[op.id]);
|
||||
this._treeNodes[op.id].reset(0, op.begin, op.end, null);
|
||||
this._tree.insert(this._treeNodes[op.id]);
|
||||
|
||||
this._oracle.delete(this._oracleNodes[op.id]);
|
||||
this._oracleNodes[op.id].start = op.begin;
|
||||
this._oracleNodes[op.id].end = op.end;
|
||||
this._oracle.insert(this._oracleNodes[op.id]);
|
||||
|
||||
} else {
|
||||
let actualNodes = this._tree.intervalSearch(op.begin, op.end, 0, false, 0);
|
||||
let actual = actualNodes.map(n => new Interval(n.cachedAbsoluteStart, n.cachedAbsoluteEnd));
|
||||
let expected = this._oracle.search(new Interval(op.begin, op.end));
|
||||
assert.deepEqual(actual, expected);
|
||||
return;
|
||||
}
|
||||
|
||||
if (PRINT_TREE) {
|
||||
this._tree.print();
|
||||
}
|
||||
|
||||
this._tree.assertInvariants();
|
||||
|
||||
let actual = this._tree.getAllInOrder().map(n => new Interval(n.cachedAbsoluteStart, n.cachedAbsoluteEnd));
|
||||
let expected = this._oracle.intervals;
|
||||
assert.deepEqual(actual, expected);
|
||||
}
|
||||
|
||||
public getExistingNodeId(index: number): number {
|
||||
let currIndex = -1;
|
||||
for (let i = 0; i < this._treeNodes.length; i++) {
|
||||
if (this._treeNodes[i] === null) {
|
||||
continue;
|
||||
}
|
||||
currIndex++;
|
||||
if (currIndex === index) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
throw new Error('unexpected');
|
||||
}
|
||||
}
|
||||
|
||||
interface IInsertOperation {
|
||||
type: 'insert';
|
||||
begin: number;
|
||||
end: number;
|
||||
}
|
||||
|
||||
interface IDeleteOperation {
|
||||
type: 'delete';
|
||||
id: number;
|
||||
}
|
||||
|
||||
interface IChangeOperation {
|
||||
type: 'change';
|
||||
id: number;
|
||||
begin: number;
|
||||
end: number;
|
||||
}
|
||||
|
||||
interface ISearchOperation {
|
||||
type: 'search';
|
||||
begin: number;
|
||||
end: number;
|
||||
}
|
||||
|
||||
type IOperation = IInsertOperation | IDeleteOperation | IChangeOperation | ISearchOperation;
|
||||
|
||||
function testIntervalTree(ops: IOperation[]): void {
|
||||
let state = new TestState();
|
||||
for (let i = 0; i < ops.length; i++) {
|
||||
state.acceptOp(ops[i]);
|
||||
}
|
||||
}
|
||||
|
||||
function getRandomInt(min: number, max: number): number {
|
||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||
}
|
||||
|
||||
function getRandomRange(min: number, max: number): [number, number] {
|
||||
let begin = getRandomInt(min, max);
|
||||
let length: number;
|
||||
if (getRandomInt(1, 10) <= 2) {
|
||||
// large range
|
||||
length = getRandomInt(0, max - begin);
|
||||
} else {
|
||||
// small range
|
||||
length = getRandomInt(0, Math.min(max - begin, 10));
|
||||
}
|
||||
return [begin, begin + length];
|
||||
}
|
||||
|
||||
class AutoTest {
|
||||
private _ops: IOperation[] = [];
|
||||
private _state: TestState = new TestState();
|
||||
private _insertCnt: number;
|
||||
private _deleteCnt: number;
|
||||
private _changeCnt: number;
|
||||
|
||||
constructor() {
|
||||
this._insertCnt = getRandomInt(MIN_INSERTS, MAX_INSERTS);
|
||||
this._changeCnt = getRandomInt(MIN_CHANGE_CNT, MAX_CHANGE_CNT);
|
||||
this._deleteCnt = 0;
|
||||
}
|
||||
|
||||
private _doRandomInsert(): void {
|
||||
let range = getRandomRange(MIN_INTERVAL_START, MAX_INTERVAL_END);
|
||||
this._run({
|
||||
type: 'insert',
|
||||
begin: range[0],
|
||||
end: range[1]
|
||||
});
|
||||
}
|
||||
|
||||
private _doRandomDelete(): void {
|
||||
let idx = getRandomInt(Math.floor(this._deleteCnt / 2), this._deleteCnt - 1);
|
||||
this._run({
|
||||
type: 'delete',
|
||||
id: this._state.getExistingNodeId(idx)
|
||||
});
|
||||
}
|
||||
|
||||
private _doRandomChange(): void {
|
||||
let idx = getRandomInt(0, this._deleteCnt - 1);
|
||||
let range = getRandomRange(MIN_INTERVAL_START, MAX_INTERVAL_END);
|
||||
this._run({
|
||||
type: 'change',
|
||||
id: this._state.getExistingNodeId(idx),
|
||||
begin: range[0],
|
||||
end: range[1]
|
||||
});
|
||||
}
|
||||
|
||||
public run() {
|
||||
while (this._insertCnt > 0 || this._deleteCnt > 0 || this._changeCnt > 0) {
|
||||
if (this._insertCnt > 0) {
|
||||
this._doRandomInsert();
|
||||
this._insertCnt--;
|
||||
this._deleteCnt++;
|
||||
} else if (this._changeCnt > 0) {
|
||||
this._doRandomChange();
|
||||
this._changeCnt--;
|
||||
} else {
|
||||
this._doRandomDelete();
|
||||
this._deleteCnt--;
|
||||
}
|
||||
|
||||
// Let's also search for something...
|
||||
let searchRange = getRandomRange(MIN_INTERVAL_START, MAX_INTERVAL_END);
|
||||
this._run({
|
||||
type: 'search',
|
||||
begin: searchRange[0],
|
||||
end: searchRange[1]
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private _run(op: IOperation): void {
|
||||
this._ops.push(op);
|
||||
this._state.acceptOp(op);
|
||||
}
|
||||
|
||||
public print(): void {
|
||||
console.log(`testIntervalTree(${JSON.stringify(this._ops)})`);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
suite('generated', () => {
|
||||
test('gen01', () => {
|
||||
testIntervalTree([
|
||||
{ type: 'insert', begin: 28, end: 35 },
|
||||
{ type: 'insert', begin: 52, end: 54 },
|
||||
{ type: 'insert', begin: 63, end: 69 }
|
||||
]);
|
||||
});
|
||||
|
||||
test('gen02', () => {
|
||||
testIntervalTree([
|
||||
{ type: 'insert', begin: 80, end: 89 },
|
||||
{ type: 'insert', begin: 92, end: 100 },
|
||||
{ type: 'insert', begin: 99, end: 99 }
|
||||
]);
|
||||
});
|
||||
|
||||
test('gen03', () => {
|
||||
testIntervalTree([
|
||||
{ type: 'insert', begin: 89, end: 96 },
|
||||
{ type: 'insert', begin: 71, end: 74 },
|
||||
{ type: 'delete', id: 1 }
|
||||
]);
|
||||
});
|
||||
|
||||
test('gen04', () => {
|
||||
testIntervalTree([
|
||||
{ type: 'insert', begin: 44, end: 46 },
|
||||
{ type: 'insert', begin: 85, end: 88 },
|
||||
{ type: 'delete', id: 0 }
|
||||
]);
|
||||
});
|
||||
|
||||
test('gen05', () => {
|
||||
testIntervalTree([
|
||||
{ type: 'insert', begin: 82, end: 90 },
|
||||
{ type: 'insert', begin: 69, end: 73 },
|
||||
{ type: 'delete', id: 0 },
|
||||
{ type: 'delete', id: 1 }
|
||||
]);
|
||||
});
|
||||
|
||||
test('gen06', () => {
|
||||
testIntervalTree([
|
||||
{ type: 'insert', begin: 41, end: 63 },
|
||||
{ type: 'insert', begin: 98, end: 98 },
|
||||
{ type: 'insert', begin: 47, end: 51 },
|
||||
{ type: 'delete', id: 2 }
|
||||
]);
|
||||
});
|
||||
|
||||
test('gen07', () => {
|
||||
testIntervalTree([
|
||||
{ type: 'insert', begin: 24, end: 26 },
|
||||
{ type: 'insert', begin: 11, end: 28 },
|
||||
{ type: 'insert', begin: 27, end: 30 },
|
||||
{ type: 'insert', begin: 80, end: 85 },
|
||||
{ type: 'delete', id: 1 }
|
||||
]);
|
||||
});
|
||||
|
||||
test('gen08', () => {
|
||||
testIntervalTree([
|
||||
{ type: 'insert', begin: 100, end: 100 },
|
||||
{ type: 'insert', begin: 100, end: 100 }
|
||||
]);
|
||||
});
|
||||
|
||||
test('gen09', () => {
|
||||
testIntervalTree([
|
||||
{ type: 'insert', begin: 58, end: 65 },
|
||||
{ type: 'insert', begin: 82, end: 96 },
|
||||
{ type: 'insert', begin: 58, end: 65 }
|
||||
]);
|
||||
});
|
||||
|
||||
test('gen10', () => {
|
||||
testIntervalTree([
|
||||
{ type: 'insert', begin: 32, end: 40 },
|
||||
{ type: 'insert', begin: 25, end: 29 },
|
||||
{ type: 'insert', begin: 24, end: 32 }
|
||||
]);
|
||||
});
|
||||
|
||||
test('gen11', () => {
|
||||
testIntervalTree([
|
||||
{ type: 'insert', begin: 25, end: 70 },
|
||||
{ type: 'insert', begin: 99, end: 100 },
|
||||
{ type: 'insert', begin: 46, end: 51 },
|
||||
{ type: 'insert', begin: 57, end: 57 },
|
||||
{ type: 'delete', id: 2 }
|
||||
]);
|
||||
});
|
||||
|
||||
test('gen12', () => {
|
||||
testIntervalTree([
|
||||
{ type: 'insert', begin: 20, end: 26 },
|
||||
{ type: 'insert', begin: 10, end: 18 },
|
||||
{ type: 'insert', begin: 99, end: 99 },
|
||||
{ type: 'insert', begin: 37, end: 59 },
|
||||
{ type: 'delete', id: 2 }
|
||||
]);
|
||||
});
|
||||
|
||||
test('gen13', () => {
|
||||
testIntervalTree([
|
||||
{ type: 'insert', begin: 3, end: 91 },
|
||||
{ type: 'insert', begin: 57, end: 57 },
|
||||
{ type: 'insert', begin: 35, end: 44 },
|
||||
{ type: 'insert', begin: 72, end: 81 },
|
||||
{ type: 'delete', id: 2 }
|
||||
]);
|
||||
});
|
||||
|
||||
test('gen14', () => {
|
||||
testIntervalTree([
|
||||
{ type: 'insert', begin: 58, end: 61 },
|
||||
{ type: 'insert', begin: 34, end: 35 },
|
||||
{ type: 'insert', begin: 56, end: 62 },
|
||||
{ type: 'insert', begin: 69, end: 78 },
|
||||
{ type: 'delete', id: 0 }
|
||||
]);
|
||||
});
|
||||
|
||||
test('gen15', () => {
|
||||
testIntervalTree([
|
||||
{ type: 'insert', begin: 63, end: 69 },
|
||||
{ type: 'insert', begin: 17, end: 24 },
|
||||
{ type: 'insert', begin: 3, end: 13 },
|
||||
{ type: 'insert', begin: 84, end: 94 },
|
||||
{ type: 'insert', begin: 18, end: 23 },
|
||||
{ type: 'insert', begin: 96, end: 98 },
|
||||
{ type: 'delete', id: 1 }
|
||||
]);
|
||||
});
|
||||
|
||||
test('gen16', () => {
|
||||
testIntervalTree([
|
||||
{ type: 'insert', begin: 27, end: 27 },
|
||||
{ type: 'insert', begin: 42, end: 87 },
|
||||
{ type: 'insert', begin: 42, end: 49 },
|
||||
{ type: 'insert', begin: 69, end: 71 },
|
||||
{ type: 'insert', begin: 20, end: 27 },
|
||||
{ type: 'insert', begin: 8, end: 9 },
|
||||
{ type: 'insert', begin: 42, end: 49 },
|
||||
{ type: 'delete', id: 1 }
|
||||
]);
|
||||
});
|
||||
|
||||
test('gen17', () => {
|
||||
testIntervalTree([
|
||||
{ type: 'insert', begin: 21, end: 23 },
|
||||
{ type: 'insert', begin: 83, end: 87 },
|
||||
{ type: 'insert', begin: 56, end: 58 },
|
||||
{ type: 'insert', begin: 1, end: 55 },
|
||||
{ type: 'insert', begin: 56, end: 59 },
|
||||
{ type: 'insert', begin: 58, end: 60 },
|
||||
{ type: 'insert', begin: 56, end: 65 },
|
||||
{ type: 'delete', id: 1 },
|
||||
{ type: 'delete', id: 0 },
|
||||
{ type: 'delete', id: 6 }
|
||||
]);
|
||||
});
|
||||
|
||||
test('gen18', () => {
|
||||
testIntervalTree([
|
||||
{ type: 'insert', begin: 25, end: 25 },
|
||||
{ type: 'insert', begin: 67, end: 79 },
|
||||
{ type: 'delete', id: 0 },
|
||||
{ type: 'search', begin: 65, end: 75 }
|
||||
]);
|
||||
});
|
||||
|
||||
test('force delta overflow', () => {
|
||||
// Search the IntervalNode ctor for FORCE_OVERFLOWING_TEST
|
||||
// to force that this test leads to a delta normalization
|
||||
testIntervalTree([
|
||||
{ type: 'insert', begin: 686081138593427, end: 733009856502260 },
|
||||
{ type: 'insert', begin: 591031326181669, end: 591031326181672 },
|
||||
{ type: 'insert', begin: 940037682731896, end: 940037682731903 },
|
||||
{ type: 'insert', begin: 598413641151120, end: 598413641151128 },
|
||||
{ type: 'insert', begin: 800564156553344, end: 800564156553351 },
|
||||
{ type: 'insert', begin: 894198957565481, end: 894198957565491 }
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
// TEST_COUNT = 0;
|
||||
// PRINT_TREE = true;
|
||||
|
||||
for (let i = 0; i < TEST_COUNT; i++) {
|
||||
if (i % 100 === 0) {
|
||||
console.log(`TEST ${i + 1}/${TEST_COUNT}`);
|
||||
}
|
||||
let test = new AutoTest();
|
||||
|
||||
try {
|
||||
test.run();
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
test.print();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
suite('searching', () => {
|
||||
|
||||
function createCormenTree(): IntervalTree {
|
||||
let r = new IntervalTree();
|
||||
let data: [number, number][] = [
|
||||
[16, 21],
|
||||
[8, 9],
|
||||
[25, 30],
|
||||
[5, 8],
|
||||
[15, 23],
|
||||
[17, 19],
|
||||
[26, 26],
|
||||
[0, 3],
|
||||
[6, 10],
|
||||
[19, 20]
|
||||
];
|
||||
data.forEach((int) => {
|
||||
let node = new IntervalNode(null, int[0], int[1]);
|
||||
r.insert(node);
|
||||
});
|
||||
return r;
|
||||
}
|
||||
|
||||
const T = createCormenTree();
|
||||
|
||||
function assertIntervalSearch(start: number, end: number, expected: [number, number][]): void {
|
||||
let actualNodes = T.intervalSearch(start, end, 0, false, 0);
|
||||
let actual = actualNodes.map((n) => <[number, number]>[n.cachedAbsoluteStart, n.cachedAbsoluteEnd]);
|
||||
assert.deepEqual(actual, expected);
|
||||
}
|
||||
|
||||
test('cormen 1->2', () => {
|
||||
assertIntervalSearch(
|
||||
1, 2,
|
||||
[
|
||||
[0, 3],
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
test('cormen 4->8', () => {
|
||||
assertIntervalSearch(
|
||||
4, 8,
|
||||
[
|
||||
[5, 8],
|
||||
[6, 10],
|
||||
[8, 9],
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
test('cormen 10->15', () => {
|
||||
assertIntervalSearch(
|
||||
10, 15,
|
||||
[
|
||||
[6, 10],
|
||||
[15, 23],
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
test('cormen 21->25', () => {
|
||||
assertIntervalSearch(
|
||||
21, 25,
|
||||
[
|
||||
[15, 23],
|
||||
[16, 21],
|
||||
[25, 30],
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
test('cormen 24->24', () => {
|
||||
assertIntervalSearch(
|
||||
24, 24,
|
||||
[
|
||||
]
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
File diff suppressed because it is too large
Load Diff
@@ -8,7 +8,7 @@ import * as assert from 'assert';
|
||||
import { EditOperation } from 'vs/editor/common/core/editOperation';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { IModelDeltaDecoration, TrackedRangeStickiness } from 'vs/editor/common/editorCommon';
|
||||
import { IModelDeltaDecoration, TrackedRangeStickiness, EndOfLineSequence } from 'vs/editor/common/editorCommon';
|
||||
import { Model } from 'vs/editor/common/model/model';
|
||||
|
||||
// --------- utils
|
||||
@@ -27,7 +27,8 @@ function modelHasDecorations(model: Model, decorations: ILightWeightDecoration2[
|
||||
className: actualDecorations[i].options.className
|
||||
});
|
||||
}
|
||||
assert.deepEqual(modelDecorations, decorations, 'Model decorations');
|
||||
modelDecorations.sort((a, b) => Range.compareRangesUsingStarts(a.range, b.range));
|
||||
assert.deepEqual(modelDecorations, decorations);
|
||||
}
|
||||
|
||||
function modelHasDecoration(model: Model, startLineNumber: number, startColumn: number, endLineNumber: number, endColumn: number, className: string) {
|
||||
@@ -168,13 +169,13 @@ suite('Editor Model - Model Decorations', () => {
|
||||
var decId1 = addDecoration(thisModel, 1, 2, 3, 2, 'myType1');
|
||||
var decId2 = addDecoration(thisModel, 1, 2, 3, 1, 'myType2');
|
||||
modelHasDecorations(thisModel, [
|
||||
{
|
||||
range: new Range(1, 2, 3, 2),
|
||||
className: 'myType1'
|
||||
},
|
||||
{
|
||||
range: new Range(1, 2, 3, 1),
|
||||
className: 'myType2'
|
||||
},
|
||||
{
|
||||
range: new Range(1, 2, 3, 2),
|
||||
className: 'myType1'
|
||||
}
|
||||
]);
|
||||
thisModel.changeDecorations((changeAccessor) => {
|
||||
@@ -207,9 +208,6 @@ suite('Editor Model - Model Decorations', () => {
|
||||
let listenerCalled = 0;
|
||||
thisModel.onDidChangeDecorations((e) => {
|
||||
listenerCalled++;
|
||||
assert.equal(e.addedDecorations.length, 1);
|
||||
assert.equal(e.changedDecorations.length, 0);
|
||||
assert.equal(e.removedDecorations.length, 0);
|
||||
});
|
||||
addDecoration(thisModel, 1, 2, 3, 2, 'myType');
|
||||
assert.equal(listenerCalled, 1, 'listener called');
|
||||
@@ -220,10 +218,6 @@ suite('Editor Model - Model Decorations', () => {
|
||||
let decId = addDecoration(thisModel, 1, 2, 3, 2, 'myType');
|
||||
thisModel.onDidChangeDecorations((e) => {
|
||||
listenerCalled++;
|
||||
assert.equal(e.addedDecorations.length, 0);
|
||||
assert.equal(e.changedDecorations.length, 1);
|
||||
assert.equal(e.changedDecorations[0], decId);
|
||||
assert.equal(e.removedDecorations.length, 0);
|
||||
});
|
||||
thisModel.changeDecorations((changeAccessor) => {
|
||||
changeAccessor.changeDecoration(decId, new Range(1, 1, 1, 2));
|
||||
@@ -236,10 +230,6 @@ suite('Editor Model - Model Decorations', () => {
|
||||
let decId = addDecoration(thisModel, 1, 2, 3, 2, 'myType');
|
||||
thisModel.onDidChangeDecorations((e) => {
|
||||
listenerCalled++;
|
||||
assert.equal(e.addedDecorations.length, 0);
|
||||
assert.equal(e.changedDecorations.length, 0);
|
||||
assert.equal(e.removedDecorations.length, 1);
|
||||
assert.equal(e.removedDecorations[0], decId);
|
||||
});
|
||||
thisModel.changeDecorations((changeAccessor) => {
|
||||
changeAccessor.removeDecoration(decId);
|
||||
@@ -249,20 +239,31 @@ suite('Editor Model - Model Decorations', () => {
|
||||
|
||||
test('decorations emit event when inserting one line text before it', () => {
|
||||
let listenerCalled = 0;
|
||||
let decId = addDecoration(thisModel, 1, 2, 3, 2, 'myType');
|
||||
addDecoration(thisModel, 1, 2, 3, 2, 'myType');
|
||||
|
||||
thisModel.onDidChangeDecorations((e) => {
|
||||
listenerCalled++;
|
||||
assert.equal(e.addedDecorations.length, 0);
|
||||
assert.equal(e.changedDecorations.length, 1);
|
||||
assert.equal(e.changedDecorations[0], decId);
|
||||
assert.equal(e.removedDecorations.length, 0);
|
||||
});
|
||||
|
||||
thisModel.applyEdits([EditOperation.insert(new Position(1, 1), 'Hallo ')]);
|
||||
assert.equal(listenerCalled, 1, 'listener called');
|
||||
});
|
||||
|
||||
test('decorations do not emit event on no-op deltaDecorations', () => {
|
||||
let listenerCalled = 0;
|
||||
|
||||
thisModel.onDidChangeDecorations((e) => {
|
||||
listenerCalled++;
|
||||
});
|
||||
|
||||
thisModel.deltaDecorations([], []);
|
||||
thisModel.changeDecorations((accessor) => {
|
||||
accessor.deltaDecorations([], []);
|
||||
});
|
||||
|
||||
assert.equal(listenerCalled, 0, 'listener not called');
|
||||
});
|
||||
|
||||
// --------- editing text & effects on decorations
|
||||
|
||||
test('decorations are updated when inserting one line text before it', () => {
|
||||
@@ -365,6 +366,740 @@ suite('Editor Model - Model Decorations', () => {
|
||||
thisModel.applyEdits([EditOperation.delete(new Range(1, 1, 3, 1))]);
|
||||
modelHasDecoration(thisModel, 1, 1, 2, 1, 'myType');
|
||||
});
|
||||
|
||||
test('decorations are updated when changing EOL', () => {
|
||||
addDecoration(thisModel, 1, 2, 4, 1, 'myType1');
|
||||
addDecoration(thisModel, 1, 3, 4, 1, 'myType2');
|
||||
addDecoration(thisModel, 1, 4, 4, 1, 'myType3');
|
||||
addDecoration(thisModel, 1, 5, 4, 1, 'myType4');
|
||||
addDecoration(thisModel, 1, 6, 4, 1, 'myType5');
|
||||
addDecoration(thisModel, 1, 7, 4, 1, 'myType6');
|
||||
addDecoration(thisModel, 1, 8, 4, 1, 'myType7');
|
||||
addDecoration(thisModel, 1, 9, 4, 1, 'myType8');
|
||||
addDecoration(thisModel, 1, 10, 4, 1, 'myType9');
|
||||
thisModel.applyEdits([EditOperation.insert(new Position(1, 1), 'x')]);
|
||||
thisModel.setEOL(EndOfLineSequence.CRLF);
|
||||
thisModel.applyEdits([EditOperation.insert(new Position(1, 1), 'x')]);
|
||||
modelHasDecorations(thisModel, [
|
||||
{ range: new Range(1, 4, 4, 1), className: 'myType1' },
|
||||
{ range: new Range(1, 5, 4, 1), className: 'myType2' },
|
||||
{ range: new Range(1, 6, 4, 1), className: 'myType3' },
|
||||
{ range: new Range(1, 7, 4, 1), className: 'myType4' },
|
||||
{ range: new Range(1, 8, 4, 1), className: 'myType5' },
|
||||
{ range: new Range(1, 9, 4, 1), className: 'myType6' },
|
||||
{ range: new Range(1, 10, 4, 1), className: 'myType7' },
|
||||
{ range: new Range(1, 11, 4, 1), className: 'myType8' },
|
||||
{ range: new Range(1, 12, 4, 1), className: 'myType9' },
|
||||
]);
|
||||
});
|
||||
|
||||
test('an apparently simple edit', () => {
|
||||
addDecoration(thisModel, 1, 2, 4, 1, 'myType1');
|
||||
thisModel.applyEdits([EditOperation.replace(new Range(1, 14, 2, 1), 'x')]);
|
||||
modelHasDecorations(thisModel, [
|
||||
{ range: new Range(1, 2, 3, 1), className: 'myType1' },
|
||||
]);
|
||||
});
|
||||
|
||||
test('removeAllDecorationsWithOwnerId can be called after model dispose', () => {
|
||||
let model = Model.createFromString('asd');
|
||||
model.dispose();
|
||||
model.removeAllDecorationsWithOwnerId(1);
|
||||
});
|
||||
|
||||
test('removeAllDecorationsWithOwnerId works', () => {
|
||||
thisModel.deltaDecorations([], [{ range: new Range(1, 2, 4, 1), options: { className: 'myType1' } }], 1);
|
||||
thisModel.removeAllDecorationsWithOwnerId(1);
|
||||
modelHasNoDecorations(thisModel);
|
||||
});
|
||||
});
|
||||
|
||||
suite('Decorations and editing', () => {
|
||||
|
||||
function _runTest(decRange: Range, stickiness: TrackedRangeStickiness, editRange: Range, editText: string, editForceMoveMarkers: boolean, expectedDecRange: Range, msg: string): void {
|
||||
let model = Model.createFromString([
|
||||
'My First Line',
|
||||
'My Second Line',
|
||||
'Third Line'
|
||||
].join('\n'));
|
||||
|
||||
const id = model.deltaDecorations([], [{ range: decRange, options: { stickiness: stickiness } }])[0];
|
||||
model.applyEdits([{ range: editRange, text: editText, forceMoveMarkers: editForceMoveMarkers, identifier: null }]);
|
||||
const actual = model.getDecorationRange(id);
|
||||
assert.deepEqual(actual, expectedDecRange, msg);
|
||||
|
||||
model.dispose();
|
||||
}
|
||||
|
||||
function runTest(decRange: Range, editRange: Range, editText: string, expectedDecRange: Range[][]): void {
|
||||
_runTest(decRange, 0, editRange, editText, false, expectedDecRange[0][0], 'no-0-AlwaysGrowsWhenTypingAtEdges');
|
||||
_runTest(decRange, 1, editRange, editText, false, expectedDecRange[0][1], 'no-1-NeverGrowsWhenTypingAtEdges');
|
||||
_runTest(decRange, 2, editRange, editText, false, expectedDecRange[0][2], 'no-2-GrowsOnlyWhenTypingBefore');
|
||||
_runTest(decRange, 3, editRange, editText, false, expectedDecRange[0][3], 'no-3-GrowsOnlyWhenTypingAfter');
|
||||
|
||||
_runTest(decRange, 0, editRange, editText, true, expectedDecRange[1][0], 'force-0-AlwaysGrowsWhenTypingAtEdges');
|
||||
_runTest(decRange, 1, editRange, editText, true, expectedDecRange[1][1], 'force-1-NeverGrowsWhenTypingAtEdges');
|
||||
_runTest(decRange, 2, editRange, editText, true, expectedDecRange[1][2], 'force-2-GrowsOnlyWhenTypingBefore');
|
||||
_runTest(decRange, 3, editRange, editText, true, expectedDecRange[1][3], 'force-3-GrowsOnlyWhenTypingAfter');
|
||||
}
|
||||
|
||||
suite('insert', () => {
|
||||
suite('collapsed dec', () => {
|
||||
test('before', () => {
|
||||
runTest(
|
||||
new Range(1, 4, 1, 4),
|
||||
new Range(1, 3, 1, 3), 'xx',
|
||||
[
|
||||
[new Range(1, 6, 1, 6), new Range(1, 6, 1, 6), new Range(1, 6, 1, 6), new Range(1, 6, 1, 6)],
|
||||
[new Range(1, 6, 1, 6), new Range(1, 6, 1, 6), new Range(1, 6, 1, 6), new Range(1, 6, 1, 6)],
|
||||
]
|
||||
);
|
||||
});
|
||||
test('equal', () => {
|
||||
runTest(
|
||||
new Range(1, 4, 1, 4),
|
||||
new Range(1, 4, 1, 4), 'xx',
|
||||
[
|
||||
[new Range(1, 4, 1, 6), new Range(1, 6, 1, 6), new Range(1, 4, 1, 4), new Range(1, 6, 1, 6)],
|
||||
[new Range(1, 6, 1, 6), new Range(1, 6, 1, 6), new Range(1, 6, 1, 6), new Range(1, 6, 1, 6)],
|
||||
]
|
||||
);
|
||||
});
|
||||
test('after', () => {
|
||||
runTest(
|
||||
new Range(1, 4, 1, 4),
|
||||
new Range(1, 5, 1, 5), 'xx',
|
||||
[
|
||||
[new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4)],
|
||||
[new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(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 Range(1, 6, 1, 11), new Range(1, 6, 1, 11), new Range(1, 6, 1, 11), new Range(1, 6, 1, 11)],
|
||||
[new Range(1, 6, 1, 11), new Range(1, 6, 1, 11), new Range(1, 6, 1, 11), new Range(1, 6, 1, 11)],
|
||||
]
|
||||
);
|
||||
});
|
||||
test('start', () => {
|
||||
runTest(
|
||||
new Range(1, 4, 1, 9),
|
||||
new Range(1, 4, 1, 4), 'xx',
|
||||
[
|
||||
[new Range(1, 4, 1, 11), new Range(1, 6, 1, 11), new Range(1, 4, 1, 11), new Range(1, 6, 1, 11)],
|
||||
[new Range(1, 6, 1, 11), new Range(1, 6, 1, 11), new Range(1, 6, 1, 11), new Range(1, 6, 1, 11)],
|
||||
]
|
||||
);
|
||||
});
|
||||
test('inside', () => {
|
||||
runTest(
|
||||
new Range(1, 4, 1, 9),
|
||||
new Range(1, 5, 1, 5), 'xx',
|
||||
[
|
||||
[new Range(1, 4, 1, 11), new Range(1, 4, 1, 11), new Range(1, 4, 1, 11), new Range(1, 4, 1, 11)],
|
||||
[new Range(1, 4, 1, 11), new Range(1, 4, 1, 11), new Range(1, 4, 1, 11), new Range(1, 4, 1, 11)],
|
||||
]
|
||||
);
|
||||
});
|
||||
test('end', () => {
|
||||
runTest(
|
||||
new Range(1, 4, 1, 9),
|
||||
new Range(1, 9, 1, 9), 'xx',
|
||||
[
|
||||
[new Range(1, 4, 1, 11), new Range(1, 4, 1, 9), new Range(1, 4, 1, 9), new Range(1, 4, 1, 11)],
|
||||
[new Range(1, 4, 1, 11), new Range(1, 4, 1, 11), new Range(1, 4, 1, 11), new Range(1, 4, 1, 11)],
|
||||
]
|
||||
);
|
||||
});
|
||||
test('after', () => {
|
||||
runTest(
|
||||
new Range(1, 4, 1, 9),
|
||||
new Range(1, 10, 1, 10), 'xx',
|
||||
[
|
||||
[new Range(1, 4, 1, 9), new Range(1, 4, 1, 9), new Range(1, 4, 1, 9), new Range(1, 4, 1, 9)],
|
||||
[new Range(1, 4, 1, 9), new Range(1, 4, 1, 9), new Range(1, 4, 1, 9), new Range(1, 4, 1, 9)],
|
||||
]
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
suite('delete', () => {
|
||||
suite('collapsed dec', () => {
|
||||
test('edit.end < range.start', () => {
|
||||
runTest(
|
||||
new Range(1, 4, 1, 4),
|
||||
new Range(1, 1, 1, 3), '',
|
||||
[
|
||||
[new Range(1, 2, 1, 2), new Range(1, 2, 1, 2), new Range(1, 2, 1, 2), new Range(1, 2, 1, 2)],
|
||||
[new Range(1, 2, 1, 2), new Range(1, 2, 1, 2), new Range(1, 2, 1, 2), new Range(1, 2, 1, 2)],
|
||||
]
|
||||
);
|
||||
});
|
||||
test('edit.end <= range.start', () => {
|
||||
runTest(
|
||||
new Range(1, 4, 1, 4),
|
||||
new Range(1, 2, 1, 4), '',
|
||||
[
|
||||
[new Range(1, 2, 1, 2), new Range(1, 2, 1, 2), new Range(1, 2, 1, 2), new Range(1, 2, 1, 2)],
|
||||
[new Range(1, 2, 1, 2), new Range(1, 2, 1, 2), new Range(1, 2, 1, 2), new Range(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 Range(1, 3, 1, 3), new Range(1, 3, 1, 3), new Range(1, 3, 1, 3), new Range(1, 3, 1, 3)],
|
||||
[new Range(1, 3, 1, 3), new Range(1, 3, 1, 3), new Range(1, 3, 1, 3), new Range(1, 3, 1, 3)],
|
||||
]
|
||||
);
|
||||
});
|
||||
test('edit.start >= range.end', () => {
|
||||
runTest(
|
||||
new Range(1, 4, 1, 4),
|
||||
new Range(1, 4, 1, 6), '',
|
||||
[
|
||||
[new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4)],
|
||||
[new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4)],
|
||||
]
|
||||
);
|
||||
});
|
||||
test('edit.start > range.end', () => {
|
||||
runTest(
|
||||
new Range(1, 4, 1, 4),
|
||||
new Range(1, 5, 1, 7), '',
|
||||
[
|
||||
[new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4)],
|
||||
[new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(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 Range(1, 2, 1, 7), new Range(1, 2, 1, 7), new Range(1, 2, 1, 7), new Range(1, 2, 1, 7)],
|
||||
[new Range(1, 2, 1, 7), new Range(1, 2, 1, 7), new Range(1, 2, 1, 7), new Range(1, 2, 1, 7)],
|
||||
]
|
||||
);
|
||||
});
|
||||
test('edit.end <= range.start', () => {
|
||||
runTest(
|
||||
new Range(1, 4, 1, 9),
|
||||
new Range(1, 2, 1, 4), '',
|
||||
[
|
||||
[new Range(1, 2, 1, 7), new Range(1, 2, 1, 7), new Range(1, 2, 1, 7), new Range(1, 2, 1, 7)],
|
||||
[new Range(1, 2, 1, 7), new Range(1, 2, 1, 7), new Range(1, 2, 1, 7), new Range(1, 2, 1, 7)],
|
||||
]
|
||||
);
|
||||
});
|
||||
test('edit.start < range.start && edit.end < range.end', () => {
|
||||
runTest(
|
||||
new Range(1, 4, 1, 9),
|
||||
new Range(1, 3, 1, 5), '',
|
||||
[
|
||||
[new Range(1, 3, 1, 7), new Range(1, 3, 1, 7), new Range(1, 3, 1, 7), new Range(1, 3, 1, 7)],
|
||||
[new Range(1, 3, 1, 7), new Range(1, 3, 1, 7), new Range(1, 3, 1, 7), new Range(1, 3, 1, 7)],
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
test('edit.start < range.start && edit.end == range.end', () => {
|
||||
runTest(
|
||||
new Range(1, 4, 1, 9),
|
||||
new Range(1, 3, 1, 9), '',
|
||||
[
|
||||
[new Range(1, 3, 1, 3), new Range(1, 3, 1, 3), new Range(1, 3, 1, 3), new Range(1, 3, 1, 3)],
|
||||
[new Range(1, 3, 1, 3), new Range(1, 3, 1, 3), new Range(1, 3, 1, 3), new Range(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 Range(1, 3, 1, 3), new Range(1, 3, 1, 3), new Range(1, 3, 1, 3), new Range(1, 3, 1, 3)],
|
||||
[new Range(1, 3, 1, 3), new Range(1, 3, 1, 3), new Range(1, 3, 1, 3), new Range(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 Range(1, 4, 1, 7), new Range(1, 4, 1, 7), new Range(1, 4, 1, 7), new Range(1, 4, 1, 7)],
|
||||
[new Range(1, 4, 1, 7), new Range(1, 4, 1, 7), new Range(1, 4, 1, 7), new Range(1, 4, 1, 7)],
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
test('edit.start == range.start && edit.end == range.end', () => {
|
||||
runTest(
|
||||
new Range(1, 4, 1, 9),
|
||||
new Range(1, 4, 1, 9), '',
|
||||
[
|
||||
[new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4)],
|
||||
[new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(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 Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4)],
|
||||
[new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(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 Range(1, 4, 1, 7), new Range(1, 4, 1, 7), new Range(1, 4, 1, 7), new Range(1, 4, 1, 7)],
|
||||
[new Range(1, 4, 1, 7), new Range(1, 4, 1, 7), new Range(1, 4, 1, 7), new Range(1, 4, 1, 7)],
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
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 Range(1, 4, 1, 5), new Range(1, 4, 1, 5), new Range(1, 4, 1, 5), new Range(1, 4, 1, 5)],
|
||||
[new Range(1, 4, 1, 5), new Range(1, 4, 1, 5), new Range(1, 4, 1, 5), new Range(1, 4, 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, 10), '',
|
||||
[
|
||||
[new Range(1, 4, 1, 5), new Range(1, 4, 1, 5), new Range(1, 4, 1, 5), new Range(1, 4, 1, 5)],
|
||||
[new Range(1, 4, 1, 5), new Range(1, 4, 1, 5), new Range(1, 4, 1, 5), new Range(1, 4, 1, 5)],
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
test('edit.start == range.end', () => {
|
||||
runTest(
|
||||
new Range(1, 4, 1, 9),
|
||||
new Range(1, 9, 1, 11), '',
|
||||
[
|
||||
[new Range(1, 4, 1, 9), new Range(1, 4, 1, 9), new Range(1, 4, 1, 9), new Range(1, 4, 1, 9)],
|
||||
[new Range(1, 4, 1, 9), new Range(1, 4, 1, 9), new Range(1, 4, 1, 9), new Range(1, 4, 1, 9)],
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
test('edit.start > range.end', () => {
|
||||
runTest(
|
||||
new Range(1, 4, 1, 9),
|
||||
new Range(1, 10, 1, 11), '',
|
||||
[
|
||||
[new Range(1, 4, 1, 9), new Range(1, 4, 1, 9), new Range(1, 4, 1, 9), new Range(1, 4, 1, 9)],
|
||||
[new Range(1, 4, 1, 9), new Range(1, 4, 1, 9), new Range(1, 4, 1, 9), new Range(1, 4, 1, 9)],
|
||||
]
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
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 Range(1, 3, 1, 3), new Range(1, 3, 1, 3), new Range(1, 3, 1, 3), new Range(1, 3, 1, 3)],
|
||||
[new Range(1, 3, 1, 3), new Range(1, 3, 1, 3), new Range(1, 3, 1, 3), new Range(1, 3, 1, 3)],
|
||||
]
|
||||
);
|
||||
});
|
||||
test('edit.end <= range.start', () => {
|
||||
runTest(
|
||||
new Range(1, 4, 1, 4),
|
||||
new Range(1, 2, 1, 4), 'c',
|
||||
[
|
||||
[new Range(1, 3, 1, 3), new Range(1, 3, 1, 3), new Range(1, 3, 1, 3), new Range(1, 3, 1, 3)],
|
||||
[new Range(1, 3, 1, 3), new Range(1, 3, 1, 3), new Range(1, 3, 1, 3), new Range(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 Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4)],
|
||||
[new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4)],
|
||||
]
|
||||
);
|
||||
});
|
||||
test('edit.start >= range.end', () => {
|
||||
runTest(
|
||||
new Range(1, 4, 1, 4),
|
||||
new Range(1, 4, 1, 6), 'c',
|
||||
[
|
||||
[new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4)],
|
||||
[new Range(1, 5, 1, 5), new Range(1, 5, 1, 5), new Range(1, 5, 1, 5), new Range(1, 5, 1, 5)],
|
||||
]
|
||||
);
|
||||
});
|
||||
test('edit.start > range.end', () => {
|
||||
runTest(
|
||||
new Range(1, 4, 1, 4),
|
||||
new Range(1, 5, 1, 7), 'c',
|
||||
[
|
||||
[new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4)],
|
||||
[new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(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 Range(1, 3, 1, 8), new Range(1, 3, 1, 8), new Range(1, 3, 1, 8), new Range(1, 3, 1, 8)],
|
||||
[new Range(1, 3, 1, 8), new Range(1, 3, 1, 8), new Range(1, 3, 1, 8), new Range(1, 3, 1, 8)],
|
||||
]
|
||||
);
|
||||
});
|
||||
test('edit.end <= range.start', () => {
|
||||
runTest(
|
||||
new Range(1, 4, 1, 9),
|
||||
new Range(1, 2, 1, 4), 'c',
|
||||
[
|
||||
[new Range(1, 3, 1, 8), new Range(1, 3, 1, 8), new Range(1, 3, 1, 8), new Range(1, 3, 1, 8)],
|
||||
[new Range(1, 3, 1, 8), new Range(1, 3, 1, 8), new Range(1, 3, 1, 8), new Range(1, 3, 1, 8)],
|
||||
]
|
||||
);
|
||||
});
|
||||
test('edit.start < range.start && edit.end < range.end', () => {
|
||||
runTest(
|
||||
new Range(1, 4, 1, 9),
|
||||
new Range(1, 3, 1, 5), 'c',
|
||||
[
|
||||
[new Range(1, 4, 1, 8), new Range(1, 4, 1, 8), new Range(1, 4, 1, 8), new Range(1, 4, 1, 8)],
|
||||
[new Range(1, 4, 1, 8), new Range(1, 4, 1, 8), new Range(1, 4, 1, 8), new Range(1, 4, 1, 8)],
|
||||
]
|
||||
);
|
||||
});
|
||||
test('edit.start < range.start && edit.end == range.end', () => {
|
||||
runTest(
|
||||
new Range(1, 4, 1, 9),
|
||||
new Range(1, 3, 1, 9), 'c',
|
||||
[
|
||||
[new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4)],
|
||||
[new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(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 Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4)],
|
||||
[new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(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 Range(1, 4, 1, 8), new Range(1, 4, 1, 8), new Range(1, 4, 1, 8), new Range(1, 4, 1, 8)],
|
||||
[new Range(1, 5, 1, 8), new Range(1, 5, 1, 8), new Range(1, 5, 1, 8), new Range(1, 5, 1, 8)],
|
||||
]
|
||||
);
|
||||
});
|
||||
test('edit.start == range.start && edit.end == range.end', () => {
|
||||
runTest(
|
||||
new Range(1, 4, 1, 9),
|
||||
new Range(1, 4, 1, 9), 'c',
|
||||
[
|
||||
[new Range(1, 4, 1, 5), new Range(1, 4, 1, 5), new Range(1, 4, 1, 5), new Range(1, 4, 1, 5)],
|
||||
[new Range(1, 5, 1, 5), new Range(1, 5, 1, 5), new Range(1, 5, 1, 5), new Range(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 Range(1, 4, 1, 5), new Range(1, 4, 1, 5), new Range(1, 4, 1, 5), new Range(1, 4, 1, 5)],
|
||||
[new Range(1, 5, 1, 5), new Range(1, 5, 1, 5), new Range(1, 5, 1, 5), new Range(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 Range(1, 4, 1, 8), new Range(1, 4, 1, 8), new Range(1, 4, 1, 8), new Range(1, 4, 1, 8)],
|
||||
[new Range(1, 4, 1, 8), new Range(1, 4, 1, 8), new Range(1, 4, 1, 8), new Range(1, 4, 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, 9), 'c',
|
||||
[
|
||||
[new Range(1, 4, 1, 6), new Range(1, 4, 1, 6), new Range(1, 4, 1, 6), new Range(1, 4, 1, 6)],
|
||||
[new Range(1, 4, 1, 6), new Range(1, 4, 1, 6), new Range(1, 4, 1, 6), new Range(1, 4, 1, 6)],
|
||||
]
|
||||
);
|
||||
});
|
||||
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 Range(1, 4, 1, 6), new Range(1, 4, 1, 6), new Range(1, 4, 1, 6), new Range(1, 4, 1, 6)],
|
||||
[new Range(1, 4, 1, 6), new Range(1, 4, 1, 6), new Range(1, 4, 1, 6), new Range(1, 4, 1, 6)],
|
||||
]
|
||||
);
|
||||
});
|
||||
test('edit.start == range.end', () => {
|
||||
runTest(
|
||||
new Range(1, 4, 1, 9),
|
||||
new Range(1, 9, 1, 11), 'c',
|
||||
[
|
||||
[new Range(1, 4, 1, 9), new Range(1, 4, 1, 9), new Range(1, 4, 1, 9), new Range(1, 4, 1, 9)],
|
||||
[new Range(1, 4, 1, 10), new Range(1, 4, 1, 10), new Range(1, 4, 1, 10), new Range(1, 4, 1, 10)],
|
||||
]
|
||||
);
|
||||
});
|
||||
test('edit.start > range.end', () => {
|
||||
runTest(
|
||||
new Range(1, 4, 1, 9),
|
||||
new Range(1, 10, 1, 11), 'c',
|
||||
[
|
||||
[new Range(1, 4, 1, 9), new Range(1, 4, 1, 9), new Range(1, 4, 1, 9), new Range(1, 4, 1, 9)],
|
||||
[new Range(1, 4, 1, 9), new Range(1, 4, 1, 9), new Range(1, 4, 1, 9), new Range(1, 4, 1, 9)],
|
||||
]
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
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 Range(1, 6, 1, 6), new Range(1, 6, 1, 6), new Range(1, 6, 1, 6), new Range(1, 6, 1, 6)],
|
||||
[new Range(1, 6, 1, 6), new Range(1, 6, 1, 6), new Range(1, 6, 1, 6), new Range(1, 6, 1, 6)],
|
||||
]
|
||||
);
|
||||
});
|
||||
test('edit.end <= range.start', () => {
|
||||
runTest(
|
||||
new Range(1, 4, 1, 4),
|
||||
new Range(1, 2, 1, 4), 'cccc',
|
||||
[
|
||||
[new Range(1, 4, 1, 6), new Range(1, 6, 1, 6), new Range(1, 4, 1, 4), new Range(1, 6, 1, 6)],
|
||||
[new Range(1, 6, 1, 6), new Range(1, 6, 1, 6), new Range(1, 6, 1, 6), new Range(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 Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4)],
|
||||
[new Range(1, 7, 1, 7), new Range(1, 7, 1, 7), new Range(1, 7, 1, 7), new Range(1, 7, 1, 7)],
|
||||
]
|
||||
);
|
||||
});
|
||||
test('edit.start >= range.end', () => {
|
||||
runTest(
|
||||
new Range(1, 4, 1, 4),
|
||||
new Range(1, 4, 1, 6), 'cccc',
|
||||
[
|
||||
[new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4)],
|
||||
[new Range(1, 8, 1, 8), new Range(1, 8, 1, 8), new Range(1, 8, 1, 8), new Range(1, 8, 1, 8)],
|
||||
]
|
||||
);
|
||||
});
|
||||
test('edit.start > range.end', () => {
|
||||
runTest(
|
||||
new Range(1, 4, 1, 4),
|
||||
new Range(1, 5, 1, 7), 'cccc',
|
||||
[
|
||||
[new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4)],
|
||||
[new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(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 Range(1, 6, 1, 11), new Range(1, 6, 1, 11), new Range(1, 6, 1, 11), new Range(1, 6, 1, 11)],
|
||||
[new Range(1, 6, 1, 11), new Range(1, 6, 1, 11), new Range(1, 6, 1, 11), new Range(1, 6, 1, 11)],
|
||||
]
|
||||
);
|
||||
});
|
||||
test('edit.end <= range.start', () => {
|
||||
runTest(
|
||||
new Range(1, 4, 1, 9),
|
||||
new Range(1, 2, 1, 4), 'cccc',
|
||||
[
|
||||
[new Range(1, 4, 1, 11), new Range(1, 6, 1, 11), new Range(1, 4, 1, 11), new Range(1, 6, 1, 11)],
|
||||
[new Range(1, 6, 1, 11), new Range(1, 6, 1, 11), new Range(1, 6, 1, 11), new Range(1, 6, 1, 11)],
|
||||
]
|
||||
);
|
||||
});
|
||||
test('edit.start < range.start && edit.end < range.end', () => {
|
||||
runTest(
|
||||
new Range(1, 4, 1, 9),
|
||||
new Range(1, 3, 1, 5), 'cccc',
|
||||
[
|
||||
[new Range(1, 4, 1, 11), new Range(1, 4, 1, 11), new Range(1, 4, 1, 11), new Range(1, 4, 1, 11)],
|
||||
[new Range(1, 7, 1, 11), new Range(1, 7, 1, 11), new Range(1, 7, 1, 11), new Range(1, 7, 1, 11)],
|
||||
]
|
||||
);
|
||||
});
|
||||
test('edit.start < range.start && edit.end == range.end', () => {
|
||||
runTest(
|
||||
new Range(1, 4, 1, 9),
|
||||
new Range(1, 3, 1, 9), 'cccc',
|
||||
[
|
||||
[new Range(1, 4, 1, 7), new Range(1, 4, 1, 7), new Range(1, 4, 1, 7), new Range(1, 4, 1, 7)],
|
||||
[new Range(1, 7, 1, 7), new Range(1, 7, 1, 7), new Range(1, 7, 1, 7), new Range(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 Range(1, 4, 1, 7), new Range(1, 4, 1, 7), new Range(1, 4, 1, 7), new Range(1, 4, 1, 7)],
|
||||
[new Range(1, 7, 1, 7), new Range(1, 7, 1, 7), new Range(1, 7, 1, 7), new Range(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 Range(1, 4, 1, 11), new Range(1, 4, 1, 11), new Range(1, 4, 1, 11), new Range(1, 4, 1, 11)],
|
||||
[new Range(1, 8, 1, 11), new Range(1, 8, 1, 11), new Range(1, 8, 1, 11), new Range(1, 8, 1, 11)],
|
||||
]
|
||||
);
|
||||
});
|
||||
test('edit.start == range.start && edit.end == range.end', () => {
|
||||
runTest(
|
||||
new Range(1, 4, 1, 9),
|
||||
new Range(1, 4, 1, 9), 'cccc',
|
||||
[
|
||||
[new Range(1, 4, 1, 8), new Range(1, 4, 1, 8), new Range(1, 4, 1, 8), new Range(1, 4, 1, 8)],
|
||||
[new Range(1, 8, 1, 8), new Range(1, 8, 1, 8), new Range(1, 8, 1, 8), new Range(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 Range(1, 4, 1, 8), new Range(1, 4, 1, 8), new Range(1, 4, 1, 8), new Range(1, 4, 1, 8)],
|
||||
[new Range(1, 8, 1, 8), new Range(1, 8, 1, 8), new Range(1, 8, 1, 8), new Range(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 Range(1, 4, 1, 11), new Range(1, 4, 1, 11), new Range(1, 4, 1, 11), new Range(1, 4, 1, 11)],
|
||||
[new Range(1, 4, 1, 11), new Range(1, 4, 1, 11), new Range(1, 4, 1, 11), new Range(1, 4, 1, 11)],
|
||||
]
|
||||
);
|
||||
});
|
||||
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 Range(1, 4, 1, 9), new Range(1, 4, 1, 9), new Range(1, 4, 1, 9), new Range(1, 4, 1, 9)],
|
||||
[new Range(1, 4, 1, 9), new Range(1, 4, 1, 9), new Range(1, 4, 1, 9), new Range(1, 4, 1, 9)],
|
||||
]
|
||||
);
|
||||
});
|
||||
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 Range(1, 4, 1, 9), new Range(1, 4, 1, 9), new Range(1, 4, 1, 9), new Range(1, 4, 1, 9)],
|
||||
[new Range(1, 4, 1, 9), new Range(1, 4, 1, 9), new Range(1, 4, 1, 9), new Range(1, 4, 1, 9)],
|
||||
]
|
||||
);
|
||||
});
|
||||
test('edit.start == range.end', () => {
|
||||
runTest(
|
||||
new Range(1, 4, 1, 9),
|
||||
new Range(1, 9, 1, 11), 'cccc',
|
||||
[
|
||||
[new Range(1, 4, 1, 9), new Range(1, 4, 1, 9), new Range(1, 4, 1, 9), new Range(1, 4, 1, 9)],
|
||||
[new Range(1, 4, 1, 13), new Range(1, 4, 1, 13), new Range(1, 4, 1, 13), new Range(1, 4, 1, 13)],
|
||||
]
|
||||
);
|
||||
});
|
||||
test('edit.start > range.end', () => {
|
||||
runTest(
|
||||
new Range(1, 4, 1, 9),
|
||||
new Range(1, 10, 1, 11), 'cccc',
|
||||
[
|
||||
[new Range(1, 4, 1, 9), new Range(1, 4, 1, 9), new Range(1, 4, 1, 9), new Range(1, 4, 1, 9)],
|
||||
[new Range(1, 4, 1, 9), new Range(1, 4, 1, 9), new Range(1, 4, 1, 9), new Range(1, 4, 1, 9)],
|
||||
]
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
interface ILightWeightDecoration {
|
||||
@@ -420,7 +1155,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');
|
||||
assert.equal(2 * initialIds.length, model._getMarkersCount(), 'does not leak markers');
|
||||
actualDecorations.sort((a, b) => strcmp(a.id, b.id));
|
||||
decorations.sort((a, b) => strcmp(a.id, b.id));
|
||||
assert.deepEqual(actualDecorations, decorations);
|
||||
@@ -431,7 +1165,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');
|
||||
assert.equal(2 * newIds.length, model._getMarkersCount(), 'does not leak markers');
|
||||
actualNewDecorations.sort((a, b) => strcmp(a.id, b.id));
|
||||
newDecorations.sort((a, b) => strcmp(a.id, b.id));
|
||||
assert.deepEqual(actualDecorations, decorations);
|
||||
|
||||
@@ -820,178 +820,4 @@ suite('TextModel.mightContainRTL', () => {
|
||||
assert.equal(model.mightContainRTL(), false);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
suite('TextModel.getLineIndentGuide', () => {
|
||||
function assertIndentGuides(lines: [number, string][]): void {
|
||||
let text = lines.map(l => l[1]).join('\n');
|
||||
let model = TextModel.createFromString(text);
|
||||
|
||||
let actual: [number, string][] = [];
|
||||
for (let line = 1; line <= model.getLineCount(); line++) {
|
||||
actual[line - 1] = [model.getLineIndentGuide(line), model.getLineContent(line)];
|
||||
}
|
||||
|
||||
// let expected = lines.map(l => l[0]);
|
||||
|
||||
assert.deepEqual(actual, lines);
|
||||
|
||||
model.dispose();
|
||||
}
|
||||
|
||||
test('getLineIndentGuide one level', () => {
|
||||
assertIndentGuides([
|
||||
[0, 'A'],
|
||||
[1, ' A'],
|
||||
[1, ' A'],
|
||||
[1, ' A'],
|
||||
]);
|
||||
});
|
||||
|
||||
test('getLineIndentGuide two levels', () => {
|
||||
assertIndentGuides([
|
||||
[0, 'A'],
|
||||
[1, ' A'],
|
||||
[1, ' A'],
|
||||
[1, ' A'],
|
||||
[1, ' A'],
|
||||
]);
|
||||
});
|
||||
|
||||
test('getLineIndentGuide three levels', () => {
|
||||
assertIndentGuides([
|
||||
[0, 'A'],
|
||||
[1, ' A'],
|
||||
[1, ' A'],
|
||||
[2, ' A'],
|
||||
[0, 'A'],
|
||||
]);
|
||||
});
|
||||
|
||||
test('getLineIndentGuide decreasing indent', () => {
|
||||
assertIndentGuides([
|
||||
[0, ' A'],
|
||||
[0, ' A'],
|
||||
[0, 'A'],
|
||||
]);
|
||||
});
|
||||
|
||||
test('getLineIndentGuide Java', () => {
|
||||
assertIndentGuides([
|
||||
/* 1*/[0, 'class A {'],
|
||||
/* 2*/[1, ' void foo() {'],
|
||||
/* 3*/[1, ' console.log(1);'],
|
||||
/* 4*/[1, ' console.log(2);'],
|
||||
/* 5*/[1, ' }'],
|
||||
/* 6*/[1, ''],
|
||||
/* 7*/[1, ' void bar() {'],
|
||||
/* 8*/[1, ' console.log(3);'],
|
||||
/* 9*/[1, ' }'],
|
||||
/*10*/[0, '}'],
|
||||
/*11*/[0, 'interface B {'],
|
||||
/*12*/[1, ' void bar();'],
|
||||
/*13*/[0, '}'],
|
||||
]);
|
||||
});
|
||||
|
||||
test('getLineIndentGuide Javadoc', () => {
|
||||
assertIndentGuides([
|
||||
[0, '/**'],
|
||||
[1, ' * Comment'],
|
||||
[1, ' */'],
|
||||
[0, 'class A {'],
|
||||
[1, ' void foo() {'],
|
||||
[1, ' }'],
|
||||
[0, '}'],
|
||||
]);
|
||||
});
|
||||
|
||||
test('getLineIndentGuide Whitespace', () => {
|
||||
assertIndentGuides([
|
||||
[0, 'class A {'],
|
||||
[1, ''],
|
||||
[1, ' void foo() {'],
|
||||
[1, ' '],
|
||||
[1, ' return 1;'],
|
||||
[1, ' }'],
|
||||
[1, ' '],
|
||||
[0, '}'],
|
||||
]);
|
||||
});
|
||||
|
||||
test('getLineIndentGuide Tabs', () => {
|
||||
assertIndentGuides([
|
||||
[0, 'class A {'],
|
||||
[1, '\t\t'],
|
||||
[1, '\tvoid foo() {'],
|
||||
[2, '\t \t//hello'],
|
||||
[2, '\t return 2;'],
|
||||
[1, ' \t}'],
|
||||
[1, ' '],
|
||||
[0, '}'],
|
||||
]);
|
||||
});
|
||||
|
||||
test('getLineIndentGuide checker.ts', () => {
|
||||
assertIndentGuides([
|
||||
/* 1*/[0, '/// <reference path="binder.ts"/>'],
|
||||
/* 2*/[0, ''],
|
||||
/* 3*/[0, '/* @internal */'],
|
||||
/* 4*/[0, 'namespace ts {'],
|
||||
/* 5*/[1, ' let nextSymbolId = 1;'],
|
||||
/* 6*/[1, ' let nextNodeId = 1;'],
|
||||
/* 7*/[1, ' let nextMergeId = 1;'],
|
||||
/* 8*/[1, ' let nextFlowId = 1;'],
|
||||
/* 9*/[1, ''],
|
||||
/*10*/[1, ' export function getNodeId(node: Node): number {'],
|
||||
/*11*/[2, ' if (!node.id) {'],
|
||||
/*12*/[3, ' node.id = nextNodeId;'],
|
||||
/*13*/[3, ' nextNodeId++;'],
|
||||
/*14*/[2, ' }'],
|
||||
/*15*/[2, ' return node.id;'],
|
||||
/*16*/[1, ' }'],
|
||||
/*17*/[0, '}'],
|
||||
]);
|
||||
});
|
||||
|
||||
test('issue #8425 - Missing indentation lines for first level indentation', () => {
|
||||
assertIndentGuides([
|
||||
[1, '\tindent1'],
|
||||
[2, '\t\tindent2'],
|
||||
[2, '\t\tindent2'],
|
||||
[1, '\tindent1'],
|
||||
]);
|
||||
});
|
||||
|
||||
test('issue #8952 - Indentation guide lines going through text on .yml file', () => {
|
||||
assertIndentGuides([
|
||||
[0, 'properties:'],
|
||||
[1, ' emailAddress:'],
|
||||
[2, ' - bla'],
|
||||
[2, ' - length:'],
|
||||
[3, ' max: 255'],
|
||||
[0, 'getters:'],
|
||||
]);
|
||||
});
|
||||
|
||||
test('issue #11892 - Indent guides look funny', () => {
|
||||
assertIndentGuides([
|
||||
[0, 'function test(base) {'],
|
||||
[1, '\tswitch (base) {'],
|
||||
[2, '\t\tcase 1:'],
|
||||
[3, '\t\t\treturn 1;'],
|
||||
[2, '\t\tcase 2:'],
|
||||
[3, '\t\t\treturn 2;'],
|
||||
[1, '\t}'],
|
||||
[0, '}'],
|
||||
]);
|
||||
});
|
||||
|
||||
test('issue #12398 - Problem in indent guidelines', () => {
|
||||
assertIndentGuides([
|
||||
[2, '\t\t.bla'],
|
||||
[3, '\t\t\tlabel(for)'],
|
||||
[0, 'include script'],
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -359,3 +359,179 @@ suite('TextModelWithTokens regression tests', () => {
|
||||
registration.dispose();
|
||||
});
|
||||
});
|
||||
|
||||
suite('TextModel.getLineIndentGuide', () => {
|
||||
function assertIndentGuides(lines: [number, string][]): void {
|
||||
let text = lines.map(l => l[1]).join('\n');
|
||||
let model = Model.createFromString(text);
|
||||
|
||||
let actualIndents = model.getLinesIndentGuides(1, model.getLineCount());
|
||||
|
||||
let actual: [number, string][] = [];
|
||||
for (let line = 1; line <= model.getLineCount(); line++) {
|
||||
actual[line - 1] = [actualIndents[line - 1], model.getLineContent(line)];
|
||||
}
|
||||
|
||||
// let expected = lines.map(l => l[0]);
|
||||
|
||||
assert.deepEqual(actual, lines);
|
||||
|
||||
model.dispose();
|
||||
}
|
||||
|
||||
test('getLineIndentGuide one level', () => {
|
||||
assertIndentGuides([
|
||||
[0, 'A'],
|
||||
[1, ' A'],
|
||||
[1, ' A'],
|
||||
[1, ' A'],
|
||||
]);
|
||||
});
|
||||
|
||||
test('getLineIndentGuide two levels', () => {
|
||||
assertIndentGuides([
|
||||
[0, 'A'],
|
||||
[1, ' A'],
|
||||
[1, ' A'],
|
||||
[1, ' A'],
|
||||
[1, ' A'],
|
||||
]);
|
||||
});
|
||||
|
||||
test('getLineIndentGuide three levels', () => {
|
||||
assertIndentGuides([
|
||||
[0, 'A'],
|
||||
[1, ' A'],
|
||||
[1, ' A'],
|
||||
[2, ' A'],
|
||||
[0, 'A'],
|
||||
]);
|
||||
});
|
||||
|
||||
test('getLineIndentGuide decreasing indent', () => {
|
||||
assertIndentGuides([
|
||||
[1, ' A'],
|
||||
[1, ' A'],
|
||||
[0, 'A'],
|
||||
]);
|
||||
});
|
||||
|
||||
test('getLineIndentGuide Java', () => {
|
||||
assertIndentGuides([
|
||||
/* 1*/[0, 'class A {'],
|
||||
/* 2*/[1, ' void foo() {'],
|
||||
/* 3*/[1, ' console.log(1);'],
|
||||
/* 4*/[1, ' console.log(2);'],
|
||||
/* 5*/[1, ' }'],
|
||||
/* 6*/[1, ''],
|
||||
/* 7*/[1, ' void bar() {'],
|
||||
/* 8*/[1, ' console.log(3);'],
|
||||
/* 9*/[1, ' }'],
|
||||
/*10*/[0, '}'],
|
||||
/*11*/[0, 'interface B {'],
|
||||
/*12*/[1, ' void bar();'],
|
||||
/*13*/[0, '}'],
|
||||
]);
|
||||
});
|
||||
|
||||
test('getLineIndentGuide Javadoc', () => {
|
||||
assertIndentGuides([
|
||||
[0, '/**'],
|
||||
[1, ' * Comment'],
|
||||
[1, ' */'],
|
||||
[0, 'class A {'],
|
||||
[1, ' void foo() {'],
|
||||
[1, ' }'],
|
||||
[0, '}'],
|
||||
]);
|
||||
});
|
||||
|
||||
test('getLineIndentGuide Whitespace', () => {
|
||||
assertIndentGuides([
|
||||
[0, 'class A {'],
|
||||
[1, ''],
|
||||
[1, ' void foo() {'],
|
||||
[1, ' '],
|
||||
[2, ' return 1;'],
|
||||
[1, ' }'],
|
||||
[1, ' '],
|
||||
[0, '}'],
|
||||
]);
|
||||
});
|
||||
|
||||
test('getLineIndentGuide Tabs', () => {
|
||||
assertIndentGuides([
|
||||
[0, 'class A {'],
|
||||
[1, '\t\t'],
|
||||
[1, '\tvoid foo() {'],
|
||||
[2, '\t \t//hello'],
|
||||
[2, '\t return 2;'],
|
||||
[1, ' \t}'],
|
||||
[1, ' '],
|
||||
[0, '}'],
|
||||
]);
|
||||
});
|
||||
|
||||
test('getLineIndentGuide checker.ts', () => {
|
||||
assertIndentGuides([
|
||||
/* 1*/[0, '/// <reference path="binder.ts"/>'],
|
||||
/* 2*/[0, ''],
|
||||
/* 3*/[0, '/* @internal */'],
|
||||
/* 4*/[0, 'namespace ts {'],
|
||||
/* 5*/[1, ' let nextSymbolId = 1;'],
|
||||
/* 6*/[1, ' let nextNodeId = 1;'],
|
||||
/* 7*/[1, ' let nextMergeId = 1;'],
|
||||
/* 8*/[1, ' let nextFlowId = 1;'],
|
||||
/* 9*/[1, ''],
|
||||
/*10*/[1, ' export function getNodeId(node: Node): number {'],
|
||||
/*11*/[2, ' if (!node.id) {'],
|
||||
/*12*/[3, ' node.id = nextNodeId;'],
|
||||
/*13*/[3, ' nextNodeId++;'],
|
||||
/*14*/[2, ' }'],
|
||||
/*15*/[2, ' return node.id;'],
|
||||
/*16*/[1, ' }'],
|
||||
/*17*/[0, '}'],
|
||||
]);
|
||||
});
|
||||
|
||||
test('issue #8425 - Missing indentation lines for first level indentation', () => {
|
||||
assertIndentGuides([
|
||||
[1, '\tindent1'],
|
||||
[2, '\t\tindent2'],
|
||||
[2, '\t\tindent2'],
|
||||
[1, '\tindent1'],
|
||||
]);
|
||||
});
|
||||
|
||||
test('issue #8952 - Indentation guide lines going through text on .yml file', () => {
|
||||
assertIndentGuides([
|
||||
[0, 'properties:'],
|
||||
[1, ' emailAddress:'],
|
||||
[2, ' - bla'],
|
||||
[2, ' - length:'],
|
||||
[3, ' max: 255'],
|
||||
[0, 'getters:'],
|
||||
]);
|
||||
});
|
||||
|
||||
test('issue #11892 - Indent guides look funny', () => {
|
||||
assertIndentGuides([
|
||||
[0, 'function test(base) {'],
|
||||
[1, '\tswitch (base) {'],
|
||||
[2, '\t\tcase 1:'],
|
||||
[3, '\t\t\treturn 1;'],
|
||||
[2, '\t\tcase 2:'],
|
||||
[3, '\t\t\treturn 2;'],
|
||||
[1, '\t}'],
|
||||
[0, '}'],
|
||||
]);
|
||||
});
|
||||
|
||||
test('issue #12398 - Problem in indent guidelines', () => {
|
||||
assertIndentGuides([
|
||||
[2, '\t\t.bla'],
|
||||
[3, '\t\t\tlabel(for)'],
|
||||
[0, 'include script'],
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -190,4 +190,11 @@ suite('Editor Modes - Link Computer', () => {
|
||||
' http://***/_api/web/lists/GetByTitle(\'Teambuildingaanvragen\')/items '
|
||||
);
|
||||
});
|
||||
|
||||
test('issue #7855', () => {
|
||||
assertLink(
|
||||
'7. At this point, ServiceMain has been called. There is no functionality presently in ServiceMain, but you can consult the [MSDN documentation](https://msdn.microsoft.com/en-us/library/windows/desktop/ms687414(v=vs.85).aspx) to add functionality as desired!',
|
||||
' https://msdn.microsoft.com/en-us/library/windows/desktop/ms687414(v=vs.85).aspx '
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -88,7 +88,7 @@ suite('EditorSimpleWorker', () => {
|
||||
|
||||
test('MoreMinimal', function () {
|
||||
|
||||
return worker.computeMoreMinimalEdits(model.uri.toString(), [{ text: 'This is line One', range: new Range(1, 1, 1, 17) }], []).then(edits => {
|
||||
return worker.computeMoreMinimalEdits(model.uri.toString(), [{ text: 'This is line One', range: new Range(1, 1, 1, 17) }]).then(edits => {
|
||||
assert.equal(edits.length, 1);
|
||||
const [first] = edits;
|
||||
assert.equal(first.text, 'O');
|
||||
@@ -104,7 +104,7 @@ suite('EditorSimpleWorker', () => {
|
||||
'}'
|
||||
], '\n');
|
||||
|
||||
return worker.computeMoreMinimalEdits(model.uri.toString(), [{ text: '{\r\n\t"a":1\r\n}', range: new Range(1, 1, 3, 2) }], []).then(edits => {
|
||||
return worker.computeMoreMinimalEdits(model.uri.toString(), [{ text: '{\r\n\t"a":1\r\n}', range: new Range(1, 1, 3, 2) }]).then(edits => {
|
||||
assert.equal(edits.length, 0);
|
||||
});
|
||||
});
|
||||
@@ -117,7 +117,7 @@ suite('EditorSimpleWorker', () => {
|
||||
'}'
|
||||
], '\n');
|
||||
|
||||
return worker.computeMoreMinimalEdits(model.uri.toString(), [{ text: '{\r\n\t"b":1\r\n}', range: new Range(1, 1, 3, 2) }], []).then(edits => {
|
||||
return worker.computeMoreMinimalEdits(model.uri.toString(), [{ text: '{\r\n\t"b":1\r\n}', range: new Range(1, 1, 3, 2) }]).then(edits => {
|
||||
assert.equal(edits.length, 1);
|
||||
const [first] = edits;
|
||||
assert.equal(first.text, 'b');
|
||||
@@ -133,7 +133,7 @@ suite('EditorSimpleWorker', () => {
|
||||
'}' // 3
|
||||
]);
|
||||
|
||||
return worker.computeMoreMinimalEdits(model.uri.toString(), [{ text: '\n', range: new Range(3, 2, 4, 1000) }], []).then(edits => {
|
||||
return worker.computeMoreMinimalEdits(model.uri.toString(), [{ text: '\n', range: new Range(3, 2, 4, 1000) }]).then(edits => {
|
||||
assert.equal(edits.length, 1);
|
||||
const [first] = edits;
|
||||
assert.equal(first.text, '\n');
|
||||
|
||||
@@ -17,7 +17,7 @@ suite('Editor ViewLayout - ViewLineParts', () => {
|
||||
|
||||
test('Bug 9827:Overlapping inline decorations can cause wrong inline class to be applied', () => {
|
||||
|
||||
var result = LineDecorationsNormalizer.normalize([
|
||||
var result = LineDecorationsNormalizer.normalize('abcabcabcabcabcabcabcabcabcabc', [
|
||||
new LineDecoration(1, 11, 'c1', false),
|
||||
new LineDecoration(3, 4, 'c2', false)
|
||||
]);
|
||||
@@ -31,7 +31,7 @@ suite('Editor ViewLayout - ViewLineParts', () => {
|
||||
|
||||
test('issue #3462: no whitespace shown at the end of a decorated line', () => {
|
||||
|
||||
var result = LineDecorationsNormalizer.normalize([
|
||||
var result = LineDecorationsNormalizer.normalize('abcabcabcabcabcabcabcabcabcabc', [
|
||||
new LineDecoration(15, 21, 'vs-whitespace', false),
|
||||
new LineDecoration(20, 21, 'inline-folded', false),
|
||||
]);
|
||||
@@ -55,7 +55,7 @@ suite('Editor ViewLayout - ViewLineParts', () => {
|
||||
|
||||
test('ViewLineParts', () => {
|
||||
|
||||
assert.deepEqual(LineDecorationsNormalizer.normalize([
|
||||
assert.deepEqual(LineDecorationsNormalizer.normalize('abcabcabcabcabcabcabcabcabcabc', [
|
||||
new LineDecoration(1, 2, 'c1', false),
|
||||
new LineDecoration(3, 4, 'c2', false)
|
||||
]), [
|
||||
@@ -63,7 +63,7 @@ suite('Editor ViewLayout - ViewLineParts', () => {
|
||||
new DecorationSegment(2, 2, 'c2')
|
||||
]);
|
||||
|
||||
assert.deepEqual(LineDecorationsNormalizer.normalize([
|
||||
assert.deepEqual(LineDecorationsNormalizer.normalize('abcabcabcabcabcabcabcabcabcabc', [
|
||||
new LineDecoration(1, 3, 'c1', false),
|
||||
new LineDecoration(3, 4, 'c2', false)
|
||||
]), [
|
||||
@@ -71,7 +71,7 @@ suite('Editor ViewLayout - ViewLineParts', () => {
|
||||
new DecorationSegment(2, 2, 'c2')
|
||||
]);
|
||||
|
||||
assert.deepEqual(LineDecorationsNormalizer.normalize([
|
||||
assert.deepEqual(LineDecorationsNormalizer.normalize('abcabcabcabcabcabcabcabcabcabc', [
|
||||
new LineDecoration(1, 4, 'c1', false),
|
||||
new LineDecoration(3, 4, 'c2', false)
|
||||
]), [
|
||||
@@ -79,7 +79,7 @@ suite('Editor ViewLayout - ViewLineParts', () => {
|
||||
new DecorationSegment(2, 2, 'c1 c2')
|
||||
]);
|
||||
|
||||
assert.deepEqual(LineDecorationsNormalizer.normalize([
|
||||
assert.deepEqual(LineDecorationsNormalizer.normalize('abcabcabcabcabcabcabcabcabcabc', [
|
||||
new LineDecoration(1, 4, 'c1', false),
|
||||
new LineDecoration(1, 4, 'c1*', false),
|
||||
new LineDecoration(3, 4, 'c2', false)
|
||||
@@ -88,7 +88,7 @@ suite('Editor ViewLayout - ViewLineParts', () => {
|
||||
new DecorationSegment(2, 2, 'c1 c1* c2')
|
||||
]);
|
||||
|
||||
assert.deepEqual(LineDecorationsNormalizer.normalize([
|
||||
assert.deepEqual(LineDecorationsNormalizer.normalize('abcabcabcabcabcabcabcabcabcabc', [
|
||||
new LineDecoration(1, 4, 'c1', false),
|
||||
new LineDecoration(1, 4, 'c1*', false),
|
||||
new LineDecoration(1, 4, 'c1**', false),
|
||||
@@ -98,7 +98,7 @@ suite('Editor ViewLayout - ViewLineParts', () => {
|
||||
new DecorationSegment(2, 2, 'c1 c1* c1** c2')
|
||||
]);
|
||||
|
||||
assert.deepEqual(LineDecorationsNormalizer.normalize([
|
||||
assert.deepEqual(LineDecorationsNormalizer.normalize('abcabcabcabcabcabcabcabcabcabc', [
|
||||
new LineDecoration(1, 4, 'c1', false),
|
||||
new LineDecoration(1, 4, 'c1*', false),
|
||||
new LineDecoration(1, 4, 'c1**', false),
|
||||
@@ -109,7 +109,7 @@ suite('Editor ViewLayout - ViewLineParts', () => {
|
||||
new DecorationSegment(2, 2, 'c1 c1* c1** c2 c2*')
|
||||
]);
|
||||
|
||||
assert.deepEqual(LineDecorationsNormalizer.normalize([
|
||||
assert.deepEqual(LineDecorationsNormalizer.normalize('abcabcabcabcabcabcabcabcabcabc', [
|
||||
new LineDecoration(1, 4, 'c1', false),
|
||||
new LineDecoration(1, 4, 'c1*', false),
|
||||
new LineDecoration(1, 4, 'c1**', false),
|
||||
|
||||
@@ -1052,6 +1052,36 @@ suite('viewLineRenderer.renderLine 2', () => {
|
||||
assert.deepEqual(actual.html, expected);
|
||||
});
|
||||
|
||||
test('issue #32436: Non-monospace font + visible whitespace + After decorator causes line to "jump"', () => {
|
||||
|
||||
let lineContent = '\tbla';
|
||||
|
||||
let actual = renderViewLine(new RenderLineInput(
|
||||
false,
|
||||
lineContent,
|
||||
false,
|
||||
0,
|
||||
[createPart(4, 3)],
|
||||
[new LineDecoration(2, 3, 'before', true)],
|
||||
4,
|
||||
10,
|
||||
-1,
|
||||
'all',
|
||||
false,
|
||||
true
|
||||
));
|
||||
|
||||
let expected = [
|
||||
'<span>',
|
||||
'<span class="vs-whitespace" style="width:40px">\u2192\u00a0\u00a0\u00a0</span>',
|
||||
'<span class="mtk3 before">b</span>',
|
||||
'<span class="mtk3">la</span>',
|
||||
'</span>'
|
||||
].join('');
|
||||
|
||||
assert.deepEqual(actual.html, expected);
|
||||
});
|
||||
|
||||
test('issue #30133: Empty lines don\'t render inline decorations', () => {
|
||||
|
||||
let lineContent = '';
|
||||
@@ -1080,6 +1110,33 @@ suite('viewLineRenderer.renderLine 2', () => {
|
||||
assert.deepEqual(actual.html, expected);
|
||||
});
|
||||
|
||||
test('issue #37208: Collapsing bullet point containing emoji in Markdown document results in [??] character', () => {
|
||||
|
||||
let actual = renderViewLine(new RenderLineInput(
|
||||
true,
|
||||
' 1. 🙏',
|
||||
false,
|
||||
0,
|
||||
[createPart(7, 3)],
|
||||
[new LineDecoration(7, 8, 'inline-folded', true)],
|
||||
2,
|
||||
10,
|
||||
10000,
|
||||
'none',
|
||||
false,
|
||||
false
|
||||
));
|
||||
|
||||
let expected = [
|
||||
'<span>',
|
||||
'<span class="mtk3">\u00a0\u00a01.\u00a0</span>',
|
||||
'<span class="mtk3 inline-folded">🙏</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,
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
import * as assert from 'assert';
|
||||
import { WrappingIndent } from 'vs/editor/common/config/editorOptions';
|
||||
import { CharacterHardWrappingLineMapperFactory } from 'vs/editor/common/viewModel/characterHardWrappingLineMapper';
|
||||
import { ILineMapperFactory } from 'vs/editor/common/viewModel/splitLinesCollection';
|
||||
import { ILineMapperFactory, ILineMapping } from 'vs/editor/common/viewModel/splitLinesCollection';
|
||||
|
||||
function assertLineMapping(factory: ILineMapperFactory, tabSize: number, breakAfter: number, annotatedText: string, wrappingIndent = WrappingIndent.None) {
|
||||
function assertLineMapping(factory: ILineMapperFactory, tabSize: number, breakAfter: number, annotatedText: string, wrappingIndent = WrappingIndent.None): ILineMapping {
|
||||
|
||||
let rawText = '';
|
||||
let currentLineIndex = 0;
|
||||
@@ -42,6 +42,8 @@ function assertLineMapping(factory: ILineMapperFactory, tabSize: number, breakAf
|
||||
}
|
||||
|
||||
assert.equal(actualAnnotatedText, annotatedText);
|
||||
|
||||
return mapper;
|
||||
}
|
||||
|
||||
suite('Editor ViewModel - CharacterHardWrappingLineMapper', () => {
|
||||
@@ -106,4 +108,10 @@ suite('Editor ViewModel - CharacterHardWrappingLineMapper', () => {
|
||||
let factory = new CharacterHardWrappingLineMapperFactory('', ' ', '');
|
||||
assertLineMapping(factory, 4, 24, 'a/ very/long/line/of/tex|t/that/expands/beyon|d/your/typical/line/|of/code/', WrappingIndent.Indent);
|
||||
});
|
||||
|
||||
test('issue #35162: wrappingIndent not consistently working', () => {
|
||||
let factory = new CharacterHardWrappingLineMapperFactory('', ' ', '');
|
||||
let mapper = assertLineMapping(factory, 4, 24, ' t h i s |i s |a l |o n |g l |i n |e', WrappingIndent.Indent);
|
||||
assert.equal(mapper.getWrappedLinesIndent(), ' \t');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -136,15 +136,17 @@ suite('Editor ViewModel - SplitLinesCollection', () => {
|
||||
assert.equal(linesCollection.getViewLineCount(), 6);
|
||||
|
||||
// getOutputIndentGuide
|
||||
assert.equal(linesCollection.getViewLineIndentGuide(-1), 0);
|
||||
assert.equal(linesCollection.getViewLineIndentGuide(0), 0);
|
||||
assert.equal(linesCollection.getViewLineIndentGuide(1), 0);
|
||||
assert.equal(linesCollection.getViewLineIndentGuide(2), 1);
|
||||
assert.equal(linesCollection.getViewLineIndentGuide(3), 0);
|
||||
assert.equal(linesCollection.getViewLineIndentGuide(4), 0);
|
||||
assert.equal(linesCollection.getViewLineIndentGuide(5), 1);
|
||||
assert.equal(linesCollection.getViewLineIndentGuide(6), 0);
|
||||
assert.equal(linesCollection.getViewLineIndentGuide(7), 0);
|
||||
assert.deepEqual(linesCollection.getViewLinesIndentGuides(-1, -1), [0]);
|
||||
assert.deepEqual(linesCollection.getViewLinesIndentGuides(0, 0), [0]);
|
||||
assert.deepEqual(linesCollection.getViewLinesIndentGuides(1, 1), [0]);
|
||||
assert.deepEqual(linesCollection.getViewLinesIndentGuides(2, 2), [1]);
|
||||
assert.deepEqual(linesCollection.getViewLinesIndentGuides(3, 3), [0]);
|
||||
assert.deepEqual(linesCollection.getViewLinesIndentGuides(4, 4), [0]);
|
||||
assert.deepEqual(linesCollection.getViewLinesIndentGuides(5, 5), [1]);
|
||||
assert.deepEqual(linesCollection.getViewLinesIndentGuides(6, 6), [0]);
|
||||
assert.deepEqual(linesCollection.getViewLinesIndentGuides(7, 7), [0]);
|
||||
|
||||
assert.deepEqual(linesCollection.getViewLinesIndentGuides(0, 7), [0, 1, 0, 0, 1, 0]);
|
||||
|
||||
// getOutputLineContent
|
||||
assert.equal(linesCollection.getViewLineContent(-1), 'int main() {');
|
||||
|
||||
@@ -91,23 +91,23 @@ suite('ViewModelDecorations', () => {
|
||||
let actualDecorations = viewModel.getDecorationsInViewport(
|
||||
new Range(2, viewModel.getLineMinColumn(2), 3, viewModel.getLineMaxColumn(3))
|
||||
).map((dec) => {
|
||||
return dec.source.id;
|
||||
return dec.options.className;
|
||||
});
|
||||
|
||||
assert.deepEqual(actualDecorations, [
|
||||
dec2,
|
||||
dec3,
|
||||
dec4,
|
||||
dec5,
|
||||
dec6,
|
||||
dec7,
|
||||
dec8,
|
||||
dec9,
|
||||
dec10,
|
||||
dec11,
|
||||
dec12,
|
||||
dec13,
|
||||
dec14,
|
||||
'dec2',
|
||||
'dec3',
|
||||
'dec4',
|
||||
'dec5',
|
||||
'dec6',
|
||||
'dec7',
|
||||
'dec8',
|
||||
'dec9',
|
||||
'dec10',
|
||||
'dec11',
|
||||
'dec12',
|
||||
'dec13',
|
||||
'dec14',
|
||||
]);
|
||||
|
||||
let inlineDecorations1 = viewModel.getViewLineRenderingData(
|
||||
|
||||
@@ -41,4 +41,148 @@ suite('ViewModel', () => {
|
||||
assert.equal(viewModel.getLineCount(), 10);
|
||||
});
|
||||
});
|
||||
|
||||
function assertGetPlainTextToCopy(text: string[], ranges: Range[], emptySelectionClipboard: boolean, expected: string): void {
|
||||
testViewModel(text, {}, (viewModel, model) => {
|
||||
let actual = viewModel.getPlainTextToCopy(ranges, emptySelectionClipboard);
|
||||
assert.equal(actual, expected);
|
||||
});
|
||||
}
|
||||
|
||||
const USUAL_TEXT = [
|
||||
'',
|
||||
'line2',
|
||||
'line3',
|
||||
'line4',
|
||||
''
|
||||
];
|
||||
|
||||
test('getPlainTextToCopy 0/1', () => {
|
||||
assertGetPlainTextToCopy(
|
||||
USUAL_TEXT,
|
||||
[
|
||||
new Range(2, 2, 2, 2)
|
||||
],
|
||||
false,
|
||||
''
|
||||
);
|
||||
});
|
||||
|
||||
test('getPlainTextToCopy 0/1 - emptySelectionClipboard', () => {
|
||||
assertGetPlainTextToCopy(
|
||||
USUAL_TEXT,
|
||||
[
|
||||
new Range(2, 2, 2, 2)
|
||||
],
|
||||
true,
|
||||
'line2\n'
|
||||
);
|
||||
});
|
||||
|
||||
test('getPlainTextToCopy 1/1', () => {
|
||||
assertGetPlainTextToCopy(
|
||||
USUAL_TEXT,
|
||||
[
|
||||
new Range(2, 2, 2, 6)
|
||||
],
|
||||
false,
|
||||
'ine2'
|
||||
);
|
||||
});
|
||||
|
||||
test('getPlainTextToCopy 1/1 - emptySelectionClipboard', () => {
|
||||
assertGetPlainTextToCopy(
|
||||
USUAL_TEXT,
|
||||
[
|
||||
new Range(2, 2, 2, 6)
|
||||
],
|
||||
true,
|
||||
'ine2'
|
||||
);
|
||||
});
|
||||
|
||||
test('getPlainTextToCopy 0/2', () => {
|
||||
assertGetPlainTextToCopy(
|
||||
USUAL_TEXT,
|
||||
[
|
||||
new Range(2, 2, 2, 2),
|
||||
new Range(3, 2, 3, 2),
|
||||
],
|
||||
false,
|
||||
''
|
||||
);
|
||||
});
|
||||
|
||||
test('getPlainTextToCopy 0/2 - emptySelectionClipboard', () => {
|
||||
assertGetPlainTextToCopy(
|
||||
USUAL_TEXT,
|
||||
[
|
||||
new Range(2, 2, 2, 2),
|
||||
new Range(3, 2, 3, 2),
|
||||
],
|
||||
true,
|
||||
'line2\nline3\n'
|
||||
);
|
||||
});
|
||||
|
||||
test('getPlainTextToCopy 1/2', () => {
|
||||
assertGetPlainTextToCopy(
|
||||
USUAL_TEXT,
|
||||
[
|
||||
new Range(2, 2, 2, 6),
|
||||
new Range(3, 2, 3, 2),
|
||||
],
|
||||
false,
|
||||
'ine2'
|
||||
);
|
||||
});
|
||||
|
||||
test('getPlainTextToCopy 1/2 - emptySelectionClipboard', () => {
|
||||
assertGetPlainTextToCopy(
|
||||
USUAL_TEXT,
|
||||
[
|
||||
new Range(2, 2, 2, 6),
|
||||
new Range(3, 2, 3, 2),
|
||||
],
|
||||
true,
|
||||
'ine2'
|
||||
);
|
||||
});
|
||||
|
||||
test('getPlainTextToCopy 2/2', () => {
|
||||
assertGetPlainTextToCopy(
|
||||
USUAL_TEXT,
|
||||
[
|
||||
new Range(2, 2, 2, 6),
|
||||
new Range(3, 2, 3, 6),
|
||||
],
|
||||
false,
|
||||
'ine2\nine3'
|
||||
);
|
||||
});
|
||||
|
||||
test('getPlainTextToCopy 2/2 reversed', () => {
|
||||
assertGetPlainTextToCopy(
|
||||
USUAL_TEXT,
|
||||
[
|
||||
new Range(3, 2, 3, 6),
|
||||
new Range(2, 2, 2, 6),
|
||||
],
|
||||
false,
|
||||
'ine2\nine3'
|
||||
);
|
||||
});
|
||||
|
||||
test('getPlainTextToCopy 0/3 - emptySelectionClipboard', () => {
|
||||
assertGetPlainTextToCopy(
|
||||
USUAL_TEXT,
|
||||
[
|
||||
new Range(2, 2, 2, 2),
|
||||
new Range(2, 3, 2, 3),
|
||||
new Range(3, 2, 3, 2),
|
||||
],
|
||||
true,
|
||||
'line2\nline3\n'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user