Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/editor/test/common/model/editableTextModelTestUtils.ts
3296 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import assert from 'assert';
7
import { ISingleEditOperation } from '../../../common/core/editOperation.js';
8
import { Position } from '../../../common/core/position.js';
9
import { EndOfLinePreference, EndOfLineSequence } from '../../../common/model.js';
10
import { MirrorTextModel } from '../../../common/model/mirrorTextModel.js';
11
import { TextModel } from '../../../common/model/textModel.js';
12
import { IModelContentChangedEvent } from '../../../common/textModelEvents.js';
13
import { createTextModel } from '../testTextModel.js';
14
15
export function testApplyEditsWithSyncedModels(original: string[], edits: ISingleEditOperation[], expected: string[], inputEditsAreInvalid: boolean = false): void {
16
const originalStr = original.join('\n');
17
const expectedStr = expected.join('\n');
18
19
assertSyncedModels(originalStr, (model, assertMirrorModels) => {
20
// Apply edits & collect inverse edits
21
const inverseEdits = model.applyEdits(edits, true);
22
23
// Assert edits produced expected result
24
assert.deepStrictEqual(model.getValue(EndOfLinePreference.LF), expectedStr);
25
26
assertMirrorModels();
27
28
// Apply the inverse edits
29
const inverseInverseEdits = model.applyEdits(inverseEdits, true);
30
31
// Assert the inverse edits brought back model to original state
32
assert.deepStrictEqual(model.getValue(EndOfLinePreference.LF), originalStr);
33
34
if (!inputEditsAreInvalid) {
35
const simplifyEdit = (edit: ISingleEditOperation) => {
36
return {
37
range: edit.range,
38
text: edit.text,
39
forceMoveMarkers: edit.forceMoveMarkers || false
40
};
41
};
42
// Assert the inverse of the inverse edits are the original edits
43
assert.deepStrictEqual(inverseInverseEdits.map(simplifyEdit), edits.map(simplifyEdit));
44
}
45
46
assertMirrorModels();
47
});
48
}
49
50
const enum AssertDocumentLineMappingDirection {
51
OffsetToPosition,
52
PositionToOffset
53
}
54
55
function assertOneDirectionLineMapping(model: TextModel, direction: AssertDocumentLineMappingDirection, msg: string): void {
56
const allText = model.getValue();
57
58
let line = 1, column = 1, previousIsCarriageReturn = false;
59
for (let offset = 0; offset <= allText.length; offset++) {
60
// The position coordinate system cannot express the position between \r and \n
61
const position: Position = new Position(line, column + (previousIsCarriageReturn ? -1 : 0));
62
63
if (direction === AssertDocumentLineMappingDirection.OffsetToPosition) {
64
const actualPosition = model.getPositionAt(offset);
65
assert.strictEqual(actualPosition.toString(), position.toString(), msg + ' - getPositionAt mismatch for offset ' + offset);
66
} else {
67
// The position coordinate system cannot express the position between \r and \n
68
const expectedOffset: number = offset + (previousIsCarriageReturn ? -1 : 0);
69
const actualOffset = model.getOffsetAt(position);
70
assert.strictEqual(actualOffset, expectedOffset, msg + ' - getOffsetAt mismatch for position ' + position.toString());
71
}
72
73
if (allText.charAt(offset) === '\n') {
74
line++;
75
column = 1;
76
} else {
77
column++;
78
}
79
80
previousIsCarriageReturn = (allText.charAt(offset) === '\r');
81
}
82
}
83
84
function assertLineMapping(model: TextModel, msg: string): void {
85
assertOneDirectionLineMapping(model, AssertDocumentLineMappingDirection.PositionToOffset, msg);
86
assertOneDirectionLineMapping(model, AssertDocumentLineMappingDirection.OffsetToPosition, msg);
87
}
88
89
90
export function assertSyncedModels(text: string, callback: (model: TextModel, assertMirrorModels: () => void) => void, setup: ((model: TextModel) => void) | null = null): void {
91
const model = createTextModel(text);
92
model.setEOL(EndOfLineSequence.LF);
93
assertLineMapping(model, 'model');
94
95
if (setup) {
96
setup(model);
97
assertLineMapping(model, 'model');
98
}
99
100
const mirrorModel2 = new MirrorTextModel(null!, model.getLinesContent(), model.getEOL(), model.getVersionId());
101
let mirrorModel2PrevVersionId = model.getVersionId();
102
103
const disposable = model.onDidChangeContent((e: IModelContentChangedEvent) => {
104
const versionId = e.versionId;
105
if (versionId < mirrorModel2PrevVersionId) {
106
console.warn('Model version id did not advance between edits (2)');
107
}
108
mirrorModel2PrevVersionId = versionId;
109
mirrorModel2.onEvents(e);
110
});
111
112
const assertMirrorModels = () => {
113
assertLineMapping(model, 'model');
114
assert.strictEqual(mirrorModel2.getText(), model.getValue(), 'mirror model 2 text OK');
115
assert.strictEqual(mirrorModel2.version, model.getVersionId(), 'mirror model 2 version OK');
116
};
117
118
callback(model, assertMirrorModels);
119
120
disposable.dispose();
121
model.dispose();
122
mirrorModel2.dispose();
123
}
124
125