Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/editor/test/common/model/modelInjectedText.test.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 { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../base/test/common/utils.js';
8
import { EditOperation } from '../../../common/core/editOperation.js';
9
import { Range } from '../../../common/core/range.js';
10
import { InternalModelContentChangeEvent, LineInjectedText, ModelRawChange, RawContentChangedType } from '../../../common/textModelEvents.js';
11
import { createTextModel } from '../testTextModel.js';
12
13
suite('Editor Model - Injected Text Events', () => {
14
const store = ensureNoDisposablesAreLeakedInTestSuite();
15
16
test('Basic', () => {
17
const thisModel = store.add(createTextModel('First Line\nSecond Line'));
18
19
const recordedChanges = new Array<unknown>();
20
21
store.add(thisModel.onDidChangeContentOrInjectedText((e) => {
22
const changes = (e instanceof InternalModelContentChangeEvent ? e.rawContentChangedEvent.changes : e.changes);
23
for (const change of changes) {
24
recordedChanges.push(mapChange(change));
25
}
26
}));
27
28
// Initial decoration
29
let decorations = thisModel.deltaDecorations([], [{
30
options: {
31
after: { content: 'injected1' },
32
description: 'test1',
33
showIfCollapsed: true
34
},
35
range: new Range(1, 1, 1, 1),
36
}]);
37
assert.deepStrictEqual(recordedChanges.splice(0), [
38
{
39
kind: 'lineChanged',
40
line: '[injected1]First Line',
41
lineNumber: 1,
42
}
43
]);
44
45
// Decoration change
46
decorations = thisModel.deltaDecorations(decorations, [{
47
options: {
48
after: { content: 'injected1' },
49
description: 'test1',
50
showIfCollapsed: true
51
},
52
range: new Range(2, 1, 2, 1),
53
}, {
54
options: {
55
after: { content: 'injected2' },
56
description: 'test2',
57
showIfCollapsed: true
58
},
59
range: new Range(2, 2, 2, 2),
60
}]);
61
assert.deepStrictEqual(recordedChanges.splice(0), [
62
{
63
kind: 'lineChanged',
64
line: 'First Line',
65
lineNumber: 1,
66
},
67
{
68
kind: 'lineChanged',
69
line: '[injected1]S[injected2]econd Line',
70
lineNumber: 2,
71
}
72
]);
73
74
// Simple Insert
75
thisModel.applyEdits([EditOperation.replace(new Range(2, 2, 2, 2), 'Hello')]);
76
assert.deepStrictEqual(recordedChanges.splice(0), [
77
{
78
kind: 'lineChanged',
79
line: '[injected1]SHello[injected2]econd Line',
80
lineNumber: 2,
81
}
82
]);
83
84
// Multi-Line Insert
85
thisModel.pushEditOperations(null, [EditOperation.replace(new Range(2, 2, 2, 2), '\n\n\n')], null);
86
assert.deepStrictEqual(thisModel.getAllDecorations(undefined).map(d => ({ description: d.options.description, range: d.range.toString() })), [{
87
'description': 'test1',
88
'range': '[2,1 -> 2,1]'
89
},
90
{
91
'description': 'test2',
92
'range': '[2,2 -> 5,6]'
93
}]);
94
assert.deepStrictEqual(recordedChanges.splice(0), [
95
{
96
kind: 'lineChanged',
97
line: '[injected1]S',
98
lineNumber: 2,
99
},
100
{
101
fromLineNumber: 3,
102
kind: 'linesInserted',
103
lines: [
104
'',
105
'',
106
'Hello[injected2]econd Line',
107
]
108
}
109
]);
110
111
112
// Multi-Line Replace
113
thisModel.pushEditOperations(null, [EditOperation.replace(new Range(3, 1, 5, 1), '\n\n\n\n\n\n\n\n\n\n\n\n\n')], null);
114
assert.deepStrictEqual(recordedChanges.splice(0), [
115
{
116
'kind': 'lineChanged',
117
'line': '',
118
'lineNumber': 5,
119
},
120
{
121
'kind': 'lineChanged',
122
'line': '',
123
'lineNumber': 4,
124
},
125
{
126
'kind': 'lineChanged',
127
'line': '',
128
'lineNumber': 3,
129
},
130
{
131
'fromLineNumber': 6,
132
'kind': 'linesInserted',
133
'lines': [
134
'',
135
'',
136
'',
137
'',
138
'',
139
'',
140
'',
141
'',
142
'',
143
'',
144
'Hello[injected2]econd Line',
145
]
146
}
147
]);
148
149
// Multi-Line Replace undo
150
assert.strictEqual(thisModel.undo(), undefined);
151
assert.deepStrictEqual(recordedChanges.splice(0), [
152
{
153
kind: 'lineChanged',
154
line: '[injected1]SHello[injected2]econd Line',
155
lineNumber: 2,
156
},
157
{
158
kind: 'linesDeleted',
159
}
160
]);
161
});
162
});
163
164
function mapChange(change: ModelRawChange): unknown {
165
if (change.changeType === RawContentChangedType.LineChanged) {
166
(change.injectedText || []).every(e => {
167
assert.deepStrictEqual(e.lineNumber, change.lineNumber);
168
});
169
170
return {
171
kind: 'lineChanged',
172
line: getDetail(change.detail, change.injectedText),
173
lineNumber: change.lineNumber,
174
};
175
} else if (change.changeType === RawContentChangedType.LinesInserted) {
176
return {
177
kind: 'linesInserted',
178
lines: change.detail.map((e, idx) => getDetail(e, change.injectedTexts[idx])),
179
fromLineNumber: change.fromLineNumber
180
};
181
} else if (change.changeType === RawContentChangedType.LinesDeleted) {
182
return {
183
kind: 'linesDeleted',
184
};
185
} else if (change.changeType === RawContentChangedType.EOLChanged) {
186
return {
187
kind: 'eolChanged'
188
};
189
} else if (change.changeType === RawContentChangedType.Flush) {
190
return {
191
kind: 'flush'
192
};
193
}
194
return { kind: 'unknown' };
195
}
196
197
function getDetail(line: string, injectedTexts: LineInjectedText[] | null): string {
198
return LineInjectedText.applyInjectedText(line, (injectedTexts || []).map(t => t.withText(`[${t.options.content}]`)));
199
}
200
201