Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/emmet/src/test/editPointSelectItemBalance.test.ts
4774 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 'mocha';
7
import * as assert from 'assert';
8
import { Selection } from 'vscode';
9
import { withRandomFileEditor, closeAllEditors } from './testUtils';
10
import { fetchEditPoint } from '../editPoint';
11
import { fetchSelectItem } from '../selectItem';
12
import { balanceOut, balanceIn } from '../balance';
13
14
suite('Tests for Next/Previous Select/Edit point and Balance actions', () => {
15
teardown(closeAllEditors);
16
17
const cssContents = `
18
.boo {
19
margin: 20px 10px;
20
background-image: url('tryme.png');
21
}
22
23
.boo .hoo {
24
margin: 10px;
25
}
26
`;
27
28
const scssContents = `
29
.boo {
30
margin: 20px 10px;
31
background-image: url('tryme.png');
32
33
.boo .hoo {
34
margin: 10px;
35
}
36
}
37
`;
38
39
const htmlContents = `
40
<!DOCTYPE html>
41
<html lang="en">
42
<head>
43
<meta charset="">
44
<meta name="viewport" content="width=device-width, initial-scale=1.0">
45
<title></title>
46
</head>
47
<body>
48
<div>
49
\t\t
50
</div>
51
<div class="header">
52
<ul class="nav main">
53
<li class="item1">Item 1</li>
54
<li class="item2">Item 2</li>
55
</ul>
56
</div>
57
</body>
58
</html>
59
`;
60
61
test('Emmet Next/Prev Edit point in html file', function (): any {
62
return withRandomFileEditor(htmlContents, '.html', (editor, _) => {
63
editor.selections = [new Selection(1, 5, 1, 5)];
64
65
const expectedNextEditPoints: [number, number][] = [[4, 16], [6, 8], [10, 2], [10, 2]];
66
expectedNextEditPoints.forEach(([line, col]) => {
67
fetchEditPoint('next');
68
testSelection(editor.selection, col, line);
69
});
70
71
const expectedPrevEditPoints = [[6, 8], [4, 16], [4, 16]];
72
expectedPrevEditPoints.forEach(([line, col]) => {
73
fetchEditPoint('prev');
74
testSelection(editor.selection, col, line);
75
});
76
77
return Promise.resolve();
78
});
79
});
80
81
test('Emmet Select Next/Prev Item in html file', function (): any {
82
return withRandomFileEditor(htmlContents, '.html', (editor, _) => {
83
editor.selections = [new Selection(2, 2, 2, 2)];
84
85
const expectedNextItemPoints: [number, number, number][] = [
86
[2, 1, 5], // html
87
[2, 6, 15], // lang="en"
88
[2, 12, 14], // en
89
[3, 1, 5], // head
90
[4, 2, 6], // meta
91
[4, 7, 17], // charset=""
92
[5, 2, 6], // meta
93
[5, 7, 22], // name="viewport"
94
[5, 13, 21], // viewport
95
[5, 23, 70], // content="width=device-width, initial-scale=1.0"
96
[5, 32, 69], // width=device-width, initial-scale=1.0
97
[5, 32, 51], // width=device-width,
98
[5, 52, 69], // initial-scale=1.0
99
[6, 2, 7] // title
100
];
101
expectedNextItemPoints.forEach(([line, colstart, colend]) => {
102
fetchSelectItem('next');
103
testSelection(editor.selection, colstart, line, colend);
104
});
105
106
editor.selections = [new Selection(6, 15, 6, 15)];
107
expectedNextItemPoints.reverse().forEach(([line, colstart, colend]) => {
108
fetchSelectItem('prev');
109
testSelection(editor.selection, colstart, line, colend);
110
});
111
112
return Promise.resolve();
113
});
114
});
115
116
test('Emmet Select Next/Prev item at boundary', function (): any {
117
return withRandomFileEditor(htmlContents, '.html', (editor, _) => {
118
editor.selections = [new Selection(4, 1, 4, 1)];
119
120
fetchSelectItem('next');
121
testSelection(editor.selection, 2, 4, 6);
122
123
editor.selections = [new Selection(4, 1, 4, 1)];
124
125
fetchSelectItem('prev');
126
testSelection(editor.selection, 1, 3, 5);
127
128
return Promise.resolve();
129
});
130
});
131
132
test('Emmet Next/Prev Item in html template', function (): any {
133
const templateContents = `
134
<script type="text/template">
135
<div class="header">
136
<ul class="nav main">
137
</ul>
138
</div>
139
</script>
140
`;
141
return withRandomFileEditor(templateContents, '.html', (editor, _) => {
142
editor.selections = [new Selection(2, 2, 2, 2)];
143
144
const expectedNextItemPoints: [number, number, number][] = [
145
[2, 2, 5], // div
146
[2, 6, 20], // class="header"
147
[2, 13, 19], // header
148
[3, 3, 5], // ul
149
[3, 6, 22], // class="nav main"
150
[3, 13, 21], // nav main
151
[3, 13, 16], // nav
152
[3, 17, 21], // main
153
];
154
expectedNextItemPoints.forEach(([line, colstart, colend]) => {
155
fetchSelectItem('next');
156
testSelection(editor.selection, colstart, line, colend);
157
});
158
159
editor.selections = [new Selection(4, 1, 4, 1)];
160
expectedNextItemPoints.reverse().forEach(([line, colstart, colend]) => {
161
fetchSelectItem('prev');
162
testSelection(editor.selection, colstart, line, colend);
163
});
164
165
return Promise.resolve();
166
});
167
});
168
169
test('Emmet Select Next/Prev Item in css file', function (): any {
170
return withRandomFileEditor(cssContents, '.css', (editor, _) => {
171
editor.selections = [new Selection(0, 0, 0, 0)];
172
173
const expectedNextItemPoints: [number, number, number][] = [
174
[1, 0, 4], // .boo
175
[2, 1, 19], // margin: 20px 10px;
176
[2, 9, 18], // 20px 10px
177
[2, 9, 13], // 20px
178
[2, 14, 18], // 10px
179
[3, 1, 36], // background-image: url('tryme.png');
180
[3, 19, 35], // url('tryme.png')
181
[6, 0, 9], // .boo .hoo
182
[7, 1, 14], // margin: 10px;
183
[7, 9, 13], // 10px
184
];
185
expectedNextItemPoints.forEach(([line, colstart, colend]) => {
186
fetchSelectItem('next');
187
testSelection(editor.selection, colstart, line, colend);
188
});
189
190
editor.selections = [new Selection(9, 0, 9, 0)];
191
expectedNextItemPoints.reverse().forEach(([line, colstart, colend]) => {
192
fetchSelectItem('prev');
193
testSelection(editor.selection, colstart, line, colend);
194
});
195
196
return Promise.resolve();
197
});
198
});
199
200
test('Emmet Select Next/Prev Item in scss file with nested rules', function (): any {
201
return withRandomFileEditor(scssContents, '.scss', (editor, _) => {
202
editor.selections = [new Selection(0, 0, 0, 0)];
203
204
const expectedNextItemPoints: [number, number, number][] = [
205
[1, 0, 4], // .boo
206
[2, 1, 19], // margin: 20px 10px;
207
[2, 9, 18], // 20px 10px
208
[2, 9, 13], // 20px
209
[2, 14, 18], // 10px
210
[3, 1, 36], // background-image: url('tryme.png');
211
[3, 19, 35], // url('tryme.png')
212
[5, 1, 10], // .boo .hoo
213
[6, 2, 15], // margin: 10px;
214
[6, 10, 14], // 10px
215
];
216
expectedNextItemPoints.forEach(([line, colstart, colend]) => {
217
fetchSelectItem('next');
218
testSelection(editor.selection, colstart, line, colend);
219
});
220
221
editor.selections = [new Selection(8, 0, 8, 0)];
222
expectedNextItemPoints.reverse().forEach(([line, colstart, colend]) => {
223
fetchSelectItem('prev');
224
testSelection(editor.selection, colstart, line, colend);
225
});
226
227
return Promise.resolve();
228
});
229
});
230
231
test('Emmet Balance Out in html file', function (): any {
232
return withRandomFileEditor(htmlContents, 'html', (editor, _) => {
233
234
editor.selections = [new Selection(14, 6, 14, 10)];
235
const expectedBalanceOutRanges: [number, number, number, number][] = [
236
[14, 3, 14, 32], // <li class="item1">Item 1</li>
237
[13, 23, 16, 2], // inner contents of <ul class="nav main">
238
[13, 2, 16, 7], // outer contents of <ul class="nav main">
239
[12, 21, 17, 1], // inner contents of <div class="header">
240
[12, 1, 17, 7], // outer contents of <div class="header">
241
[8, 6, 18, 0], // inner contents of <body>
242
[8, 0, 18, 7], // outer contents of <body>
243
[2, 16, 19, 0], // inner contents of <html>
244
[2, 0, 19, 7], // outer contents of <html>
245
];
246
expectedBalanceOutRanges.forEach(([linestart, colstart, lineend, colend]) => {
247
balanceOut();
248
testSelection(editor.selection, colstart, linestart, colend, lineend);
249
});
250
251
editor.selections = [new Selection(12, 7, 12, 7)];
252
const expectedBalanceInRanges: [number, number, number, number][] = [
253
[12, 21, 17, 1], // inner contents of <div class="header">
254
[13, 2, 16, 7], // outer contents of <ul class="nav main">
255
[13, 23, 16, 2], // inner contents of <ul class="nav main">
256
[14, 3, 14, 32], // <li class="item1">Item 1</li>
257
[14, 21, 14, 27] // Item 1
258
];
259
expectedBalanceInRanges.forEach(([linestart, colstart, lineend, colend]) => {
260
balanceIn();
261
testSelection(editor.selection, colstart, linestart, colend, lineend);
262
});
263
264
return Promise.resolve();
265
});
266
});
267
268
test('Emmet Balance In using the same stack as Balance out in html file', function (): any {
269
return withRandomFileEditor(htmlContents, 'html', (editor, _) => {
270
271
editor.selections = [new Selection(15, 6, 15, 10)];
272
const expectedBalanceOutRanges: [number, number, number, number][] = [
273
[15, 3, 15, 32], // <li class="item1">Item 2</li>
274
[13, 23, 16, 2], // inner contents of <ul class="nav main">
275
[13, 2, 16, 7], // outer contents of <ul class="nav main">
276
[12, 21, 17, 1], // inner contents of <div class="header">
277
[12, 1, 17, 7], // outer contents of <div class="header">
278
[8, 6, 18, 0], // inner contents of <body>
279
[8, 0, 18, 7], // outer contents of <body>
280
[2, 16, 19, 0], // inner contents of <html>
281
[2, 0, 19, 7], // outer contents of <html>
282
];
283
expectedBalanceOutRanges.forEach(([linestart, colstart, lineend, colend]) => {
284
balanceOut();
285
testSelection(editor.selection, colstart, linestart, colend, lineend);
286
});
287
288
expectedBalanceOutRanges.reverse().forEach(([linestart, colstart, lineend, colend]) => {
289
testSelection(editor.selection, colstart, linestart, colend, lineend);
290
balanceIn();
291
});
292
293
return Promise.resolve();
294
});
295
});
296
297
test('Emmet Balance In when selection doesnt span entire node or its inner contents', function (): any {
298
return withRandomFileEditor(htmlContents, 'html', (editor, _) => {
299
300
editor.selection = new Selection(13, 7, 13, 10); // Inside the open tag of <ul class="nav main">
301
balanceIn();
302
testSelection(editor.selection, 23, 13, 2, 16); // inner contents of <ul class="nav main">
303
304
editor.selection = new Selection(16, 4, 16, 5); // Inside the open close of <ul class="nav main">
305
balanceIn();
306
testSelection(editor.selection, 23, 13, 2, 16); // inner contents of <ul class="nav main">
307
308
editor.selection = new Selection(13, 7, 14, 2); // Inside the open tag of <ul class="nav main"> and the next line
309
balanceIn();
310
testSelection(editor.selection, 23, 13, 2, 16); // inner contents of <ul class="nav main">
311
312
return Promise.resolve();
313
});
314
});
315
316
test('Emmet Balance In/Out in html template', function (): any {
317
const htmlTemplate = `
318
<script type="text/html">
319
<div class="header">
320
<ul class="nav main">
321
<li class="item1">Item 1</li>
322
<li class="item2">Item 2</li>
323
</ul>
324
</div>
325
</script>`;
326
327
return withRandomFileEditor(htmlTemplate, 'html', (editor, _) => {
328
329
editor.selections = [new Selection(5, 24, 5, 24)];
330
const expectedBalanceOutRanges: [number, number, number, number][] = [
331
[5, 20, 5, 26], // <li class="item1">``Item 2''</li>
332
[5, 2, 5, 31], // ``<li class="item1">Item 2</li>''
333
[3, 22, 6, 1], // inner contents of ul
334
[3, 1, 6, 6], // outer contents of ul
335
[2, 20, 7, 0], // inner contents of div
336
[2, 0, 7, 6], // outer contents of div
337
];
338
expectedBalanceOutRanges.forEach(([linestart, colstart, lineend, colend]) => {
339
balanceOut();
340
testSelection(editor.selection, colstart, linestart, colend, lineend);
341
});
342
343
expectedBalanceOutRanges.pop();
344
expectedBalanceOutRanges.reverse().forEach(([linestart, colstart, lineend, colend]) => {
345
balanceIn();
346
testSelection(editor.selection, colstart, linestart, colend, lineend);
347
});
348
349
return Promise.resolve();
350
});
351
});
352
});
353
354
function testSelection(selection: Selection, startChar: number, startline: number, endChar?: number, endLine?: number) {
355
assert.strictEqual(selection.anchor.line, startline);
356
assert.strictEqual(selection.anchor.character, startChar);
357
if (!endLine && endLine !== 0) {
358
assert.strictEqual(selection.isSingleLine, true);
359
} else {
360
assert.strictEqual(selection.active.line, endLine);
361
}
362
if (!endChar && endChar !== 0) {
363
assert.strictEqual(selection.isEmpty, true);
364
} else {
365
assert.strictEqual(selection.active.character, endChar);
366
}
367
}
368
369