Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/editor/test/common/viewLayout/viewLineRenderer.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 { CharCode } from '../../../../base/common/charCode.js';
8
import * as strings from '../../../../base/common/strings.js';
9
import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../base/test/common/utils.js';
10
import { MetadataConsts } from '../../../common/encodedTokenAttributes.js';
11
import { IViewLineTokens } from '../../../common/tokens/lineTokens.js';
12
import { LineDecoration } from '../../../common/viewLayout/lineDecorations.js';
13
import { CharacterMapping, DomPosition, RenderLineInput, RenderLineOutput2, renderViewLine2 as renderViewLine } from '../../../common/viewLayout/viewLineRenderer.js';
14
import { TestLineToken, TestLineTokens } from '../core/testLineToken.js';
15
import { OffsetRange } from '../../../common/core/ranges/offsetRange.js';
16
import { InlineDecorationType } from '../../../common/viewModel/inlineDecorations.js';
17
18
function createViewLineTokens(viewLineTokens: TestLineToken[]): IViewLineTokens {
19
return new TestLineTokens(viewLineTokens);
20
}
21
22
function createPart(endIndex: number, foreground: number): TestLineToken {
23
return new TestLineToken(endIndex, (
24
foreground << MetadataConsts.FOREGROUND_OFFSET
25
) >>> 0);
26
}
27
28
function inflateRenderLineOutput(renderLineOutput: RenderLineOutput2) {
29
// remove encompassing <span> to simplify test writing.
30
let html = renderLineOutput.html;
31
if (html.startsWith('<span>')) {
32
html = html.replace(/^<span>/, '');
33
}
34
html = html.replace(/<\/span>$/, '');
35
const spans: string[] = [];
36
let lastIndex = 0;
37
do {
38
const newIndex = html.indexOf('<span', lastIndex + 1);
39
if (newIndex === -1) {
40
break;
41
}
42
spans.push(html.substring(lastIndex, newIndex));
43
lastIndex = newIndex;
44
} while (true);
45
spans.push(html.substring(lastIndex));
46
47
return {
48
html: spans,
49
mapping: renderLineOutput.characterMapping.inflate(),
50
};
51
}
52
53
suite('viewLineRenderer.renderLine', () => {
54
55
ensureNoDisposablesAreLeakedInTestSuite();
56
57
function assertCharacterReplacement(lineContent: string, tabSize: number, expected: string, expectedCharOffsetInPart: number[]): void {
58
const _actual = renderViewLine(new RenderLineInput(
59
false,
60
true,
61
lineContent,
62
false,
63
strings.isBasicASCII(lineContent),
64
false,
65
0,
66
createViewLineTokens([new TestLineToken(lineContent.length, 0)]),
67
[],
68
tabSize,
69
0,
70
0,
71
0,
72
0,
73
-1,
74
'none',
75
false,
76
false,
77
null,
78
null,
79
14
80
));
81
82
assert.strictEqual(_actual.html, '<span><span class="mtk0">' + expected + '</span></span>');
83
const info = expectedCharOffsetInPart.map<CharacterMappingInfo>((absoluteOffset) => [absoluteOffset, [0, absoluteOffset]]);
84
assertCharacterMapping3(_actual.characterMapping, info);
85
}
86
87
test('replaces spaces', () => {
88
assertCharacterReplacement(' ', 4, '\u00a0', [0, 1]);
89
assertCharacterReplacement(' ', 4, '\u00a0\u00a0', [0, 1, 2]);
90
assertCharacterReplacement('a b', 4, 'a\u00a0\u00a0b', [0, 1, 2, 3, 4]);
91
});
92
93
test('escapes HTML markup', () => {
94
assertCharacterReplacement('a<b', 4, 'a&lt;b', [0, 1, 2, 3]);
95
assertCharacterReplacement('a>b', 4, 'a&gt;b', [0, 1, 2, 3]);
96
assertCharacterReplacement('a&b', 4, 'a&amp;b', [0, 1, 2, 3]);
97
});
98
99
test('replaces some bad characters', () => {
100
assertCharacterReplacement('a\0b', 4, 'a&#00;b', [0, 1, 2, 3]);
101
assertCharacterReplacement('a' + String.fromCharCode(CharCode.UTF8_BOM) + 'b', 4, 'a\ufffdb', [0, 1, 2, 3]);
102
assertCharacterReplacement('a\u2028b', 4, 'a\ufffdb', [0, 1, 2, 3]);
103
});
104
105
test('handles tabs', () => {
106
assertCharacterReplacement('\t', 4, '\u00a0\u00a0\u00a0\u00a0', [0, 4]);
107
assertCharacterReplacement('x\t', 4, 'x\u00a0\u00a0\u00a0', [0, 1, 4]);
108
assertCharacterReplacement('xx\t', 4, 'xx\u00a0\u00a0', [0, 1, 2, 4]);
109
assertCharacterReplacement('xxx\t', 4, 'xxx\u00a0', [0, 1, 2, 3, 4]);
110
assertCharacterReplacement('xxxx\t', 4, 'xxxx\u00a0\u00a0\u00a0\u00a0', [0, 1, 2, 3, 4, 8]);
111
});
112
113
function assertParts(lineContent: string, tabSize: number, parts: TestLineToken[], expected: string, info: CharacterMappingInfo[]): void {
114
const _actual = renderViewLine(new RenderLineInput(
115
false,
116
true,
117
lineContent,
118
false,
119
true,
120
false,
121
0,
122
createViewLineTokens(parts),
123
[],
124
tabSize,
125
0,
126
0,
127
0,
128
0,
129
-1,
130
'none',
131
false,
132
false,
133
null,
134
null,
135
14
136
));
137
138
assert.strictEqual(_actual.html, '<span>' + expected + '</span>');
139
assertCharacterMapping3(_actual.characterMapping, info);
140
}
141
142
test('empty line', () => {
143
assertParts('', 4, [], '<span></span>', []);
144
});
145
146
test('uses part type', () => {
147
assertParts('x', 4, [createPart(1, 10)], '<span class="mtk10">x</span>', [[0, [0, 0]], [1, [0, 1]]]);
148
assertParts('x', 4, [createPart(1, 20)], '<span class="mtk20">x</span>', [[0, [0, 0]], [1, [0, 1]]]);
149
assertParts('x', 4, [createPart(1, 30)], '<span class="mtk30">x</span>', [[0, [0, 0]], [1, [0, 1]]]);
150
});
151
152
test('two parts', () => {
153
assertParts('xy', 4, [createPart(1, 1), createPart(2, 2)], '<span class="mtk1">x</span><span class="mtk2">y</span>', [[0, [0, 0]], [1, [1, 0]], [2, [1, 1]]]);
154
assertParts('xyz', 4, [createPart(1, 1), createPart(3, 2)], '<span class="mtk1">x</span><span class="mtk2">yz</span>', [[0, [0, 0]], [1, [1, 0]], [2, [1, 1]], [3, [1, 2]]]);
155
assertParts('xyz', 4, [createPart(2, 1), createPart(3, 2)], '<span class="mtk1">xy</span><span class="mtk2">z</span>', [[0, [0, 0]], [1, [0, 1]], [2, [1, 0]], [3, [1, 1]]]);
156
});
157
158
test('overflow', () => {
159
const _actual = renderViewLine(new RenderLineInput(
160
false,
161
true,
162
'Hello world!',
163
false,
164
true,
165
false,
166
0,
167
createViewLineTokens([
168
createPart(1, 0),
169
createPart(2, 1),
170
createPart(3, 2),
171
createPart(4, 3),
172
createPart(5, 4),
173
createPart(6, 5),
174
createPart(7, 6),
175
createPart(8, 7),
176
createPart(9, 8),
177
createPart(10, 9),
178
createPart(11, 10),
179
createPart(12, 11),
180
]),
181
[],
182
4,
183
0,
184
10,
185
10,
186
10,
187
6,
188
'boundary',
189
false,
190
false,
191
null,
192
null,
193
14
194
));
195
196
assert.deepStrictEqual(inflateRenderLineOutput(_actual), {
197
html: [
198
'<span class="mtk0">H</span>',
199
'<span class="mtk1">e</span>',
200
'<span class="mtk2">l</span>',
201
'<span class="mtk3">l</span>',
202
'<span class="mtk4">o</span>',
203
'<span class="mtk5">\u00a0</span>',
204
'<span class="mtkoverflow">Show more (6 chars)</span>'
205
],
206
mapping: [
207
[0, 0, 0],
208
[1, 0, 1],
209
[2, 0, 2],
210
[3, 0, 3],
211
[4, 0, 4],
212
[5, 0, 5],
213
[5, 1, 6],
214
]
215
});
216
});
217
218
test('typical line', () => {
219
const lineText = '\t export class Game { // http://test.com ';
220
const lineParts = createViewLineTokens([
221
createPart(5, 1),
222
createPart(11, 2),
223
createPart(12, 3),
224
createPart(17, 4),
225
createPart(18, 5),
226
createPart(22, 6),
227
createPart(23, 7),
228
createPart(24, 8),
229
createPart(25, 9),
230
createPart(28, 10),
231
createPart(43, 11),
232
createPart(48, 12),
233
]);
234
const _actual = renderViewLine(new RenderLineInput(
235
false,
236
true,
237
lineText,
238
false,
239
true,
240
false,
241
0,
242
lineParts,
243
[],
244
4,
245
0,
246
10,
247
10,
248
10,
249
-1,
250
'boundary',
251
false,
252
false,
253
null,
254
null,
255
14
256
));
257
258
assert.deepStrictEqual(inflateRenderLineOutput(_actual), {
259
html: [
260
'<span class="mtkz" style="width:40px">\u2192\u00a0\u00a0\u00a0</span>',
261
'<span class="mtkz" style="width:40px">\u00b7\u200c\u00b7\u200c\u00b7\u200c\u00b7\u200c</span>',
262
'<span class="mtk2">export</span>',
263
'<span class="mtk3">\u00a0</span>',
264
'<span class="mtk4">class</span>',
265
'<span class="mtk5">\u00a0</span>',
266
'<span class="mtk6">Game</span>',
267
'<span class="mtk7">\u00a0</span>',
268
'<span class="mtk8">{</span>',
269
'<span class="mtk9">\u00a0</span>',
270
'<span class="mtk10">//\u00a0</span>',
271
'<span class="mtk11">http://test.com</span>',
272
'<span class="mtkz" style="width:20px">\u00b7\u200c\u00b7\u200c</span>',
273
'<span class="mtkz" style="width:30px">\u00b7\u200c\u00b7\u200c\u00b7\u200c</span>'
274
],
275
mapping: [
276
[0, 0, 0],
277
[1, 0, 4], [1, 2, 5], [1, 4, 6], [1, 6, 7],
278
[2, 0, 8], [2, 1, 9], [2, 2, 10], [2, 3, 11], [2, 4, 12], [2, 5, 13],
279
[3, 0, 14],
280
[4, 0, 15], [4, 1, 16], [4, 2, 17], [4, 3, 18], [4, 4, 19],
281
[5, 0, 20],
282
[6, 0, 21], [6, 1, 22], [6, 2, 23], [6, 3, 24],
283
[7, 0, 25],
284
[8, 0, 26],
285
[9, 0, 27],
286
[10, 0, 28], [10, 1, 29], [10, 2, 30],
287
[11, 0, 31], [11, 1, 32], [11, 2, 33], [11, 3, 34], [11, 4, 35], [11, 5, 36], [11, 6, 37], [11, 7, 38], [11, 8, 39], [11, 9, 40], [11, 10, 41], [11, 11, 42], [11, 12, 43], [11, 13, 44], [11, 14, 45],
288
[12, 0, 46], [12, 2, 47],
289
[13, 0, 48], [13, 2, 49], [13, 4, 50], [13, 6, 51],
290
]
291
});
292
});
293
294
test('issue #2255: Weird line rendering part 1', () => {
295
const lineText = '\t\t\tcursorStyle:\t\t\t\t\t\t(prevOpts.cursorStyle !== newOpts.cursorStyle),';
296
const lineParts = createViewLineTokens([
297
createPart(3, 1), // 3 chars
298
createPart(15, 2), // 12 chars
299
createPart(21, 3), // 6 chars
300
createPart(22, 4), // 1 char
301
createPart(43, 5), // 21 chars
302
createPart(45, 6), // 2 chars
303
createPart(46, 7), // 1 char
304
createPart(66, 8), // 20 chars
305
createPart(67, 9), // 1 char
306
createPart(68, 10), // 2 chars
307
]);
308
const _actual = renderViewLine(new RenderLineInput(
309
false,
310
true,
311
lineText,
312
false,
313
true,
314
false,
315
0,
316
lineParts,
317
[],
318
4,
319
0,
320
10,
321
10,
322
10,
323
-1,
324
'none',
325
false,
326
false,
327
null,
328
null,
329
14
330
));
331
332
assert.deepStrictEqual(inflateRenderLineOutput(_actual), {
333
html: [
334
'<span class="mtk1">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0</span>',
335
'<span class="mtk2">cursorStyle:</span>',
336
'<span class="mtk3">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0</span>',
337
'<span class="mtk4">(</span>',
338
'<span class="mtk5">prevOpts.cursorStyle\u00a0</span>',
339
'<span class="mtk6">!=</span>',
340
'<span class="mtk7">=</span>',
341
'<span class="mtk8">\u00a0newOpts.cursorStyle</span>',
342
'<span class="mtk9">)</span>',
343
'<span class="mtk10">,</span>',
344
],
345
mapping: [
346
[0, 0, 0], [0, 4, 4], [0, 8, 8],
347
[1, 0, 12], [1, 1, 13], [1, 2, 14], [1, 3, 15], [1, 4, 16], [1, 5, 17], [1, 6, 18], [1, 7, 19], [1, 8, 20], [1, 9, 21], [1, 10, 22], [1, 11, 23],
348
[2, 0, 24], [2, 4, 28], [2, 8, 32], [2, 12, 36], [2, 16, 40], [2, 20, 44],
349
[3, 0, 48],
350
[4, 0, 49], [4, 1, 50], [4, 2, 51], [4, 3, 52], [4, 4, 53], [4, 5, 54], [4, 6, 55], [4, 7, 56], [4, 8, 57], [4, 9, 58], [4, 10, 59], [4, 11, 60], [4, 12, 61], [4, 13, 62], [4, 14, 63], [4, 15, 64], [4, 16, 65], [4, 17, 66], [4, 18, 67], [4, 19, 68], [4, 20, 69],
351
[5, 0, 70], [5, 1, 71],
352
[6, 0, 72],
353
[7, 0, 73], [7, 1, 74], [7, 2, 75], [7, 3, 76], [7, 4, 77], [7, 5, 78], [7, 6, 79], [7, 7, 80], [7, 8, 81], [7, 9, 82], [7, 10, 83], [7, 11, 84], [7, 12, 85], [7, 13, 86], [7, 14, 87], [7, 15, 88], [7, 16, 89], [7, 17, 90], [7, 18, 91], [7, 19, 92],
354
[8, 0, 93],
355
[9, 0, 94], [9, 1, 95],
356
]
357
});
358
});
359
360
test('issue #2255: Weird line rendering part 2', () => {
361
const lineText = ' \t\t\tcursorStyle:\t\t\t\t\t\t(prevOpts.cursorStyle !== newOpts.cursorStyle),';
362
363
const lineParts = createViewLineTokens([
364
createPart(4, 1), // 4 chars
365
createPart(16, 2), // 12 chars
366
createPart(22, 3), // 6 chars
367
createPart(23, 4), // 1 char
368
createPart(44, 5), // 21 chars
369
createPart(46, 6), // 2 chars
370
createPart(47, 7), // 1 char
371
createPart(67, 8), // 20 chars
372
createPart(68, 9), // 1 char
373
createPart(69, 10), // 2 chars
374
]);
375
const _actual = renderViewLine(new RenderLineInput(
376
false,
377
true,
378
lineText,
379
false,
380
true,
381
false,
382
0,
383
lineParts,
384
[],
385
4,
386
0,
387
10,
388
10,
389
10,
390
-1,
391
'none',
392
false,
393
false,
394
null,
395
null,
396
14
397
));
398
399
assert.deepStrictEqual(inflateRenderLineOutput(_actual), {
400
html: [
401
'<span class="mtk1">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0</span>',
402
'<span class="mtk2">cursorStyle:</span>',
403
'<span class="mtk3">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0</span>',
404
'<span class="mtk4">(</span>',
405
'<span class="mtk5">prevOpts.cursorStyle\u00a0</span>',
406
'<span class="mtk6">!=</span>',
407
'<span class="mtk7">=</span>',
408
'<span class="mtk8">\u00a0newOpts.cursorStyle</span>',
409
'<span class="mtk9">)</span>',
410
'<span class="mtk10">,</span>',
411
],
412
mapping: [
413
[0, 0, 0], [0, 1, 1], [0, 4, 4], [0, 8, 8],
414
[1, 0, 12], [1, 1, 13], [1, 2, 14], [1, 3, 15], [1, 4, 16], [1, 5, 17], [1, 6, 18], [1, 7, 19], [1, 8, 20], [1, 9, 21], [1, 10, 22], [1, 11, 23],
415
[2, 0, 24], [2, 4, 28], [2, 8, 32], [2, 12, 36], [2, 16, 40], [2, 20, 44],
416
[3, 0, 48], [4, 0, 49], [4, 1, 50], [4, 2, 51], [4, 3, 52], [4, 4, 53], [4, 5, 54], [4, 6, 55], [4, 7, 56], [4, 8, 57], [4, 9, 58], [4, 10, 59], [4, 11, 60], [4, 12, 61], [4, 13, 62], [4, 14, 63], [4, 15, 64], [4, 16, 65], [4, 17, 66], [4, 18, 67], [4, 19, 68], [4, 20, 69],
417
[5, 0, 70], [5, 1, 71],
418
[6, 0, 72],
419
[7, 0, 73], [7, 1, 74], [7, 2, 75], [7, 3, 76], [7, 4, 77], [7, 5, 78], [7, 6, 79], [7, 7, 80], [7, 8, 81], [7, 9, 82], [7, 10, 83], [7, 11, 84], [7, 12, 85], [7, 13, 86], [7, 14, 87], [7, 15, 88], [7, 16, 89], [7, 17, 90], [7, 18, 91], [7, 19, 92],
420
[8, 0, 93],
421
[9, 0, 94], [9, 1, 95],
422
],
423
});
424
});
425
426
test('issue #91178: after decoration type shown before cursor', () => {
427
const lineText = '//just a comment';
428
const lineParts = createViewLineTokens([
429
createPart(16, 1)
430
]);
431
const actual = renderViewLine(new RenderLineInput(
432
true,
433
false,
434
lineText,
435
false,
436
true,
437
false,
438
0,
439
lineParts,
440
[
441
new LineDecoration(13, 13, 'dec1', InlineDecorationType.After),
442
new LineDecoration(13, 13, 'dec2', InlineDecorationType.Before),
443
],
444
4,
445
0,
446
10,
447
10,
448
10,
449
-1,
450
'none',
451
false,
452
false,
453
null,
454
null,
455
14
456
));
457
458
assert.deepStrictEqual(inflateRenderLineOutput(actual), ({
459
html: [
460
'<span class="mtk1">//just\u00a0a\u00a0com</span>',
461
'<span class="mtk1 dec2"></span>',
462
'<span class="mtk1 dec1"></span>',
463
'<span class="mtk1">ment</span>',
464
],
465
mapping: [
466
[0, 0, 0], [0, 1, 1], [0, 2, 2], [0, 3, 3], [0, 4, 4], [0, 5, 5], [0, 6, 6], [0, 7, 7], [0, 8, 8], [0, 9, 9], [0, 10, 10], [0, 11, 11],
467
[2, 0, 12],
468
[3, 1, 13], [3, 2, 14], [3, 3, 15], [3, 4, 16]
469
]
470
}));
471
});
472
473
test('issue microsoft/monaco-editor#280: Improved source code rendering for RTL languages', () => {
474
const lineText = 'var קודמות = \"מיותר קודמות צ\'ט של, אם לשון העברית שינויים ויש, אם\";';
475
const lineParts = createViewLineTokens([
476
createPart(3, 6),
477
createPart(13, 1),
478
createPart(66, 20),
479
createPart(67, 1),
480
]);
481
const _actual = renderViewLine(new RenderLineInput(
482
false,
483
true,
484
lineText,
485
false,
486
false,
487
true,
488
0,
489
lineParts,
490
[],
491
4,
492
0,
493
10,
494
10,
495
10,
496
-1,
497
'none',
498
false,
499
false,
500
null,
501
null,
502
14
503
));
504
505
assert.deepStrictEqual(inflateRenderLineOutput(_actual), ({
506
html: [
507
'<span class="mtk6">var</span>',
508
'<span style="unicode-bidi:isolate" class="mtk1">\u00a0קודמות\u00a0=\u00a0</span>',
509
'<span style="unicode-bidi:isolate" class="mtk20">"מיותר\u00a0קודמות\u00a0צ\'ט\u00a0של,\u00a0אם\u00a0לשון\u00a0העברית\u00a0שינויים\u00a0ויש,\u00a0אם"</span>',
510
'<span class="mtk1">;</span>',
511
],
512
mapping: [
513
[0, 0, 0], [0, 1, 1], [0, 2, 2],
514
[1, 0, 3], [1, 1, 4], [1, 2, 5], [1, 3, 6], [1, 4, 7], [1, 5, 8], [1, 6, 9], [1, 7, 10], [1, 8, 11], [1, 9, 12],
515
[2, 0, 13], [2, 1, 14], [2, 2, 15], [2, 3, 16], [2, 4, 17], [2, 5, 18], [2, 6, 19], [2, 7, 20], [2, 8, 21], [2, 9, 22], [2, 10, 23], [2, 11, 24], [2, 12, 25], [2, 13, 26], [2, 14, 27], [2, 15, 28], [2, 16, 29], [2, 17, 30], [2, 18, 31], [2, 19, 32], [2, 20, 33], [2, 21, 34], [2, 22, 35], [2, 23, 36], [2, 24, 37], [2, 25, 38], [2, 26, 39], [2, 27, 40], [2, 28, 41], [2, 29, 42], [2, 30, 43], [2, 31, 44], [2, 32, 45], [2, 33, 46], [2, 34, 47], [2, 35, 48], [2, 36, 49], [2, 37, 50], [2, 38, 51], [2, 39, 52], [2, 40, 53], [2, 41, 54], [2, 42, 55], [2, 43, 56], [2, 44, 57], [2, 45, 58], [2, 46, 59], [2, 47, 60], [2, 48, 61], [2, 49, 62], [2, 50, 63], [2, 51, 64], [2, 52, 65],
516
[3, 0, 66], [3, 1, 67]
517
]
518
}));
519
});
520
521
test('issue #137036: Issue in RTL languages in recent versions', () => {
522
const lineText = '<option value=\"العربية\">العربية</option>';
523
const lineParts = createViewLineTokens([
524
createPart(1, 2),
525
createPart(7, 3),
526
createPart(8, 4),
527
createPart(13, 5),
528
createPart(14, 4),
529
createPart(23, 6),
530
createPart(24, 2),
531
createPart(31, 4),
532
createPart(33, 2),
533
createPart(39, 3),
534
createPart(40, 2),
535
]);
536
const _actual = renderViewLine(new RenderLineInput(
537
false,
538
true,
539
lineText,
540
false,
541
false,
542
true,
543
0,
544
lineParts,
545
[],
546
4,
547
0,
548
10,
549
10,
550
10,
551
-1,
552
'none',
553
false,
554
false,
555
null,
556
null,
557
14
558
));
559
560
assert.deepStrictEqual(inflateRenderLineOutput(_actual), ({
561
html: [
562
'<span class="mtk2">&lt;</span>',
563
'<span class="mtk3">option</span>',
564
'<span class="mtk4">\u00a0</span>',
565
'<span class="mtk5">value</span>',
566
'<span class="mtk4">=</span>',
567
'<span style="unicode-bidi:isolate" class="mtk6">"العربية"</span>',
568
'<span class="mtk2">&gt;</span>',
569
'<span style="unicode-bidi:isolate" class="mtk4">العربية</span>',
570
'<span class="mtk2">&lt;/</span>',
571
'<span class="mtk3">option</span>',
572
'<span class="mtk2">&gt;</span>',
573
],
574
mapping: [
575
[0, 0, 0],
576
[1, 0, 1], [1, 1, 2], [1, 2, 3], [1, 3, 4], [1, 4, 5], [1, 5, 6],
577
[2, 0, 7],
578
[3, 0, 8], [3, 1, 9], [3, 2, 10], [3, 3, 11], [3, 4, 12],
579
[4, 0, 13],
580
[5, 0, 14], [5, 1, 15], [5, 2, 16], [5, 3, 17], [5, 4, 18], [5, 5, 19], [5, 6, 20], [5, 7, 21], [5, 8, 22],
581
[6, 0, 23],
582
[7, 0, 24], [7, 1, 25], [7, 2, 26], [7, 3, 27], [7, 4, 28], [7, 5, 29], [7, 6, 30],
583
[8, 0, 31], [8, 1, 32],
584
[9, 0, 33], [9, 1, 34], [9, 2, 35], [9, 3, 36], [9, 4, 37], [9, 5, 38],
585
[10, 0, 39], [10, 1, 40]
586
]
587
}));
588
});
589
590
test('issue #99589: Rendering whitespace influences bidi layout', () => {
591
const lineText = ' [\"🖨️ چاپ فاکتور\",\"🎨 تنظیمات\"]';
592
const lineParts = createViewLineTokens([
593
createPart(5, 2),
594
createPart(21, 3),
595
createPart(22, 2),
596
createPart(34, 3),
597
createPart(35, 2),
598
]);
599
const _actual = renderViewLine(new RenderLineInput(
600
true,
601
true,
602
lineText,
603
false,
604
false,
605
true,
606
0,
607
lineParts,
608
[],
609
4,
610
0,
611
10,
612
10,
613
10,
614
-1,
615
'all',
616
false,
617
false,
618
null,
619
null,
620
14
621
));
622
623
assert.deepStrictEqual(inflateRenderLineOutput(_actual), ({
624
html: [
625
'<span class="mtkw">\u00b7\u200c\u00b7\u200c\u00b7\u200c\u00b7\u200c</span>',
626
'<span class="mtk2">[</span>',
627
'<span style="unicode-bidi:isolate" class="mtk3">"🖨️\u00a0چاپ\u00a0فاکتور"</span>',
628
'<span class="mtk2">,</span>',
629
'<span style="unicode-bidi:isolate" class="mtk3">"🎨\u00a0تنظیمات"</span>',
630
'<span class="mtk2">]</span>',
631
],
632
mapping: [
633
[0, 0, 0], [0, 2, 1], [0, 4, 2], [0, 6, 3],
634
[1, 0, 4],
635
[2, 0, 5], [2, 1, 6], [2, 2, 7], [2, 3, 8], [2, 4, 9], [2, 5, 10], [2, 6, 11], [2, 7, 12], [2, 8, 13], [2, 9, 14], [2, 10, 15], [2, 11, 16], [2, 12, 17], [2, 13, 18], [2, 14, 19], [2, 15, 20],
636
[3, 0, 21],
637
[4, 0, 22], [4, 1, 23], [4, 2, 24], [4, 3, 25], [4, 4, 26], [4, 5, 27], [4, 6, 28], [4, 7, 29], [4, 8, 30], [4, 9, 31], [4, 10, 32], [4, 11, 33],
638
[5, 0, 34], [5, 1, 35]
639
]
640
}));
641
});
642
643
test('issue #6885: Splits large tokens', () => {
644
// 1 1 1
645
// 1 2 3 4 5 6 7 8 9 0 1 2
646
// 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234
647
const _lineText = 'This is just a long line that contains very interesting text. This is just a long line that contains very interesting text.';
648
649
function assertSplitsTokens(message: string, lineText: string, expectedOutput: string[]): void {
650
const lineParts = createViewLineTokens([createPart(lineText.length, 1)]);
651
const actual = renderViewLine(new RenderLineInput(
652
false,
653
true,
654
lineText,
655
false,
656
true,
657
false,
658
0,
659
lineParts,
660
[],
661
4,
662
0,
663
10,
664
10,
665
10,
666
-1,
667
'none',
668
false,
669
false,
670
null,
671
null,
672
14
673
));
674
assert.strictEqual(actual.html, '<span>' + expectedOutput.join('') + '</span>', message);
675
}
676
677
// A token with 49 chars
678
{
679
assertSplitsTokens(
680
'49 chars',
681
_lineText.substr(0, 49),
682
[
683
'<span class="mtk1">This\u00a0is\u00a0just\u00a0a\u00a0long\u00a0line\u00a0that\u00a0contains\u00a0very\u00a0inter</span>',
684
]
685
);
686
}
687
688
// A token with 50 chars
689
{
690
assertSplitsTokens(
691
'50 chars',
692
_lineText.substr(0, 50),
693
[
694
'<span class="mtk1">This\u00a0is\u00a0just\u00a0a\u00a0long\u00a0line\u00a0that\u00a0contains\u00a0very\u00a0intere</span>',
695
]
696
);
697
}
698
699
// A token with 51 chars
700
{
701
assertSplitsTokens(
702
'51 chars',
703
_lineText.substr(0, 51),
704
[
705
'<span class="mtk1">This\u00a0is\u00a0just\u00a0a\u00a0long\u00a0line\u00a0that\u00a0contains\u00a0very\u00a0intere</span>',
706
'<span class="mtk1">s</span>',
707
]
708
);
709
}
710
711
// A token with 99 chars
712
{
713
assertSplitsTokens(
714
'99 chars',
715
_lineText.substr(0, 99),
716
[
717
'<span class="mtk1">This\u00a0is\u00a0just\u00a0a\u00a0long\u00a0line\u00a0that\u00a0contains\u00a0very\u00a0intere</span>',
718
'<span class="mtk1">sting\u00a0text.\u00a0This\u00a0is\u00a0just\u00a0a\u00a0long\u00a0line\u00a0that\u00a0contain</span>',
719
]
720
);
721
}
722
723
// A token with 100 chars
724
{
725
assertSplitsTokens(
726
'100 chars',
727
_lineText.substr(0, 100),
728
[
729
'<span class="mtk1">This\u00a0is\u00a0just\u00a0a\u00a0long\u00a0line\u00a0that\u00a0contains\u00a0very\u00a0intere</span>',
730
'<span class="mtk1">sting\u00a0text.\u00a0This\u00a0is\u00a0just\u00a0a\u00a0long\u00a0line\u00a0that\u00a0contains</span>',
731
]
732
);
733
}
734
735
// A token with 101 chars
736
{
737
assertSplitsTokens(
738
'101 chars',
739
_lineText.substr(0, 101),
740
[
741
'<span class="mtk1">This\u00a0is\u00a0just\u00a0a\u00a0long\u00a0line\u00a0that\u00a0contains\u00a0very\u00a0intere</span>',
742
'<span class="mtk1">sting\u00a0text.\u00a0This\u00a0is\u00a0just\u00a0a\u00a0long\u00a0line\u00a0that\u00a0contains</span>',
743
'<span class="mtk1">\u00a0</span>',
744
]
745
);
746
}
747
});
748
749
test('issue #21476: Does not split large tokens when ligatures are on', () => {
750
// 1 1 1
751
// 1 2 3 4 5 6 7 8 9 0 1 2
752
// 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234
753
const _lineText = 'This is just a long line that contains very interesting text. This is just a long line that contains very interesting text.';
754
755
function assertSplitsTokens(message: string, lineText: string, expectedOutput: string[]): void {
756
const lineParts = createViewLineTokens([createPart(lineText.length, 1)]);
757
const actual = renderViewLine(new RenderLineInput(
758
false,
759
true,
760
lineText,
761
false,
762
true,
763
false,
764
0,
765
lineParts,
766
[],
767
4,
768
0,
769
10,
770
10,
771
10,
772
-1,
773
'none',
774
false,
775
true,
776
null,
777
null,
778
14
779
));
780
assert.strictEqual(actual.html, '<span>' + expectedOutput.join('') + '</span>', message);
781
}
782
783
// A token with 101 chars
784
{
785
assertSplitsTokens(
786
'101 chars',
787
_lineText.substr(0, 101),
788
[
789
'<span class="mtk1">This\u00a0is\u00a0just\u00a0a\u00a0long\u00a0line\u00a0that\u00a0contains\u00a0very\u00a0</span>',
790
'<span class="mtk1">interesting\u00a0text.\u00a0This\u00a0is\u00a0just\u00a0a\u00a0long\u00a0line\u00a0that\u00a0</span>',
791
'<span class="mtk1">contains\u00a0</span>',
792
]
793
);
794
}
795
});
796
797
test('issue #20624: Unaligned surrogate pairs are corrupted at multiples of 50 columns', () => {
798
const lineText = 'a𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷';
799
const lineParts = createViewLineTokens([createPart(lineText.length, 1)]);
800
const actual = renderViewLine(new RenderLineInput(
801
false,
802
true,
803
lineText,
804
false,
805
false,
806
false,
807
0,
808
lineParts,
809
[],
810
4,
811
0,
812
10,
813
10,
814
10,
815
-1,
816
'none',
817
false,
818
false,
819
null,
820
null,
821
14
822
));
823
824
assert.deepStrictEqual(inflateRenderLineOutput(actual).html, [
825
'<span class="mtk1">a𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷</span>',
826
]);
827
});
828
829
test('issue #6885: Does not split large tokens in RTL text', () => {
830
const lineText = 'את גרמנית בהתייחסות שמו, שנתי המשפט אל חפש, אם כתב אחרים ולחבר. של התוכן אודות בויקיפדיה כלל, של עזרה כימיה היא. על עמוד יוצרים מיתולוגיה סדר, אם שכל שתפו לעברית שינויים, אם שאלות אנגלית עזה. שמות בקלות מה סדר.';
831
const lineParts = createViewLineTokens([createPart(lineText.length, 1)]);
832
const actual = renderViewLine(new RenderLineInput(
833
false,
834
true,
835
lineText,
836
false,
837
false,
838
true,
839
0,
840
lineParts,
841
[],
842
4,
843
0,
844
10,
845
10,
846
10,
847
-1,
848
'none',
849
false,
850
false,
851
null,
852
null,
853
14
854
));
855
856
assert.deepStrictEqual(actual.html, [
857
'<span>',
858
'<span style="unicode-bidi:isolate" class="mtk1">את\u00a0גרמנית\u00a0בהתייחסות\u00a0שמו,\u00a0שנתי\u00a0המשפט\u00a0אל\u00a0חפש,\u00a0אם\u00a0כתב\u00a0אחרים\u00a0ולחבר.\u00a0של\u00a0התוכן\u00a0אודות\u00a0בויקיפדיה\u00a0כלל,\u00a0של\u00a0עזרה\u00a0כימיה\u00a0היא.\u00a0על\u00a0עמוד\u00a0יוצרים\u00a0מיתולוגיה\u00a0סדר,\u00a0אם\u00a0שכל\u00a0שתפו\u00a0לעברית\u00a0שינויים,\u00a0אם\u00a0שאלות\u00a0אנגלית\u00a0עזה.\u00a0שמות\u00a0בקלות\u00a0מה\u00a0סדר.</span>',
859
'</span>'
860
].join(''));
861
});
862
863
test('issue #95685: Uses unicode replacement character for Paragraph Separator', () => {
864
const lineText = 'var ftext = [\u2029"Und", "dann", "eines"];';
865
const lineParts = createViewLineTokens([createPart(lineText.length, 1)]);
866
const actual = renderViewLine(new RenderLineInput(
867
false,
868
true,
869
lineText,
870
false,
871
false,
872
false,
873
0,
874
lineParts,
875
[],
876
4,
877
0,
878
10,
879
10,
880
10,
881
-1,
882
'none',
883
false,
884
false,
885
null,
886
null,
887
14
888
));
889
assert.deepStrictEqual(inflateRenderLineOutput(actual), ({
890
html: [
891
'<span class="mtk1">var\u00a0ftext\u00a0=\u00a0[\uFFFD"Und",\u00a0"dann",\u00a0"eines"];</span>'
892
],
893
mapping: [
894
[0, 0, 0], [0, 1, 1], [0, 2, 2], [0, 3, 3], [0, 4, 4], [0, 5, 5], [0, 6, 6], [0, 7, 7],
895
[0, 8, 8], [0, 9, 9], [0, 10, 10], [0, 11, 11], [0, 12, 12], [0, 13, 13], [0, 14, 14],
896
[0, 15, 15], [0, 16, 16], [0, 17, 17], [0, 18, 18], [0, 19, 19], [0, 20, 20], [0, 21, 21],
897
[0, 22, 22], [0, 23, 23], [0, 24, 24], [0, 25, 25], [0, 26, 26], [0, 27, 27], [0, 28, 28],
898
[0, 29, 29], [0, 30, 30], [0, 31, 31], [0, 32, 32], [0, 33, 33], [0, 34, 34], [0, 35, 35],
899
[0, 36, 36], [0, 37, 37], [0, 38, 38]
900
]
901
}));
902
});
903
904
test('issue #19673: Monokai Theme bad-highlighting in line wrap', () => {
905
const lineText = ' MongoCallback<string>): void {';
906
const lineParts = createViewLineTokens([
907
createPart(17, 1),
908
createPart(18, 2),
909
createPart(24, 3),
910
createPart(26, 4),
911
createPart(27, 5),
912
createPart(28, 6),
913
createPart(32, 7),
914
createPart(34, 8),
915
]);
916
const _actual = renderViewLine(new RenderLineInput(
917
true,
918
true,
919
lineText,
920
false,
921
true,
922
false,
923
4,
924
lineParts,
925
[],
926
4,
927
0,
928
10,
929
10,
930
10,
931
-1,
932
'none',
933
false,
934
false,
935
null,
936
null,
937
14
938
));
939
940
assert.deepStrictEqual(inflateRenderLineOutput(_actual), ({
941
html: [
942
'<span class="">\u00a0\u00a0\u00a0\u00a0</span>',
943
'<span class="mtk1">MongoCallback</span>',
944
'<span class="mtk2">&lt;</span>',
945
'<span class="mtk3">string</span>',
946
'<span class="mtk4">&gt;)</span>',
947
'<span class="mtk5">:</span>',
948
'<span class="mtk6">\u00a0</span>',
949
'<span class="mtk7">void</span>',
950
'<span class="mtk8">\u00a0{</span>'
951
],
952
mapping: [
953
[0, 0, 0], [0, 1, 1], [0, 2, 2], [0, 3, 3],
954
[1, 0, 4], [1, 1, 5], [1, 2, 6], [1, 3, 7], [1, 4, 8], [1, 5, 9], [1, 6, 10], [1, 7, 11], [1, 8, 12], [1, 9, 13], [1, 10, 14], [1, 11, 15], [1, 12, 16],
955
[2, 0, 17],
956
[3, 0, 18], [3, 1, 19], [3, 2, 20], [3, 3, 21], [3, 4, 22], [3, 5, 23],
957
[4, 0, 24], [4, 1, 25],
958
[5, 0, 26],
959
[6, 0, 27],
960
[7, 0, 28], [7, 1, 29], [7, 2, 30], [7, 3, 31],
961
[8, 0, 32], [8, 1, 33], [8, 2, 34]
962
]
963
}));
964
});
965
});
966
967
type CharacterMappingInfo = [number, [number, number]];
968
969
function assertCharacterMapping3(actual: CharacterMapping, expectedInfo: CharacterMappingInfo[]): void {
970
for (let i = 0; i < expectedInfo.length; i++) {
971
const [horizontalOffset, [partIndex, charIndex]] = expectedInfo[i];
972
973
const actualDomPosition = actual.getDomPosition(i + 1);
974
assert.deepStrictEqual(actualDomPosition, new DomPosition(partIndex, charIndex), `getDomPosition(${i + 1})`);
975
976
let partLength = charIndex + 1;
977
for (let j = i + 1; j < expectedInfo.length; j++) {
978
const [, [nextPartIndex, nextCharIndex]] = expectedInfo[j];
979
if (nextPartIndex === partIndex) {
980
partLength = nextCharIndex + 1;
981
} else {
982
break;
983
}
984
}
985
986
const actualColumn = actual.getColumn(new DomPosition(partIndex, charIndex), partLength);
987
assert.strictEqual(actualColumn, i + 1, `actual.getColumn(${partIndex}, ${charIndex})`);
988
989
const actualHorizontalOffset = actual.getHorizontalOffset(i + 1);
990
assert.strictEqual(actualHorizontalOffset, horizontalOffset, `actual.getHorizontalOffset(${i + 1})`);
991
}
992
993
assert.strictEqual(actual.length, expectedInfo.length, `length mismatch`);
994
}
995
996
suite('viewLineRenderer.renderLine 2', () => {
997
998
ensureNoDisposablesAreLeakedInTestSuite();
999
1000
function testCreateLineParts(fontIsMonospace: boolean, lineContent: string, tokens: TestLineToken[], fauxIndentLength: number, renderWhitespace: 'none' | 'boundary' | 'selection' | 'trailing' | 'all', selections: OffsetRange[] | null) {
1001
const actual = renderViewLine(new RenderLineInput(
1002
fontIsMonospace,
1003
true,
1004
lineContent,
1005
false,
1006
true,
1007
false,
1008
fauxIndentLength,
1009
createViewLineTokens(tokens),
1010
[],
1011
4,
1012
0,
1013
10,
1014
10,
1015
10,
1016
-1,
1017
renderWhitespace,
1018
false,
1019
false,
1020
selections,
1021
null,
1022
14
1023
));
1024
return inflateRenderLineOutput(actual);
1025
}
1026
1027
test('issue #18616: Inline decorations ending at the text length are no longer rendered', () => {
1028
const lineContent = 'https://microsoft.com';
1029
const actual = renderViewLine(new RenderLineInput(
1030
false,
1031
true,
1032
lineContent,
1033
false,
1034
true,
1035
false,
1036
0,
1037
createViewLineTokens([createPart(21, 3)]),
1038
[new LineDecoration(1, 22, 'link', InlineDecorationType.Regular)],
1039
4,
1040
0,
1041
10,
1042
10,
1043
10,
1044
-1,
1045
'none',
1046
false,
1047
false,
1048
null,
1049
null,
1050
14
1051
));
1052
1053
assert.deepStrictEqual(inflateRenderLineOutput(actual), ({
1054
html: [
1055
'<span class="mtk3 link">https://microsoft.com</span>'
1056
],
1057
mapping: [
1058
[0, 0, 0], [0, 1, 1], [0, 2, 2], [0, 3, 3], [0, 4, 4], [0, 5, 5], [0, 6, 6], [0, 7, 7],
1059
[0, 8, 8], [0, 9, 9], [0, 10, 10], [0, 11, 11], [0, 12, 12], [0, 13, 13], [0, 14, 14],
1060
[0, 15, 15], [0, 16, 16], [0, 17, 17], [0, 18, 18], [0, 19, 19], [0, 20, 20], [0, 21, 21]
1061
]
1062
}));
1063
});
1064
1065
test('issue #19207: Link in Monokai is not rendered correctly', () => {
1066
const lineContent = '\'let url = `http://***/_api/web/lists/GetByTitle(\\\'Teambuildingaanvragen\\\')/items`;\'';
1067
const actual = renderViewLine(new RenderLineInput(
1068
true,
1069
true,
1070
lineContent,
1071
false,
1072
true,
1073
false,
1074
0,
1075
createViewLineTokens([
1076
createPart(49, 6),
1077
createPart(51, 4),
1078
createPart(72, 6),
1079
createPart(74, 4),
1080
createPart(84, 6),
1081
]),
1082
[
1083
new LineDecoration(13, 51, 'detected-link', InlineDecorationType.Regular)
1084
],
1085
4,
1086
0,
1087
10,
1088
10,
1089
10,
1090
-1,
1091
'none',
1092
false,
1093
false,
1094
null,
1095
null,
1096
14
1097
));
1098
1099
assert.deepStrictEqual(inflateRenderLineOutput(actual), ({
1100
html: [
1101
'<span class="mtk6">\'let\u00a0url\u00a0=\u00a0`</span>',
1102
'<span class="mtk6 detected-link">http://***/_api/web/lists/GetByTitle(</span>',
1103
'<span class="mtk4 detected-link">\\</span>',
1104
'<span class="mtk4">\'</span>',
1105
'<span class="mtk6">Teambuildingaanvragen</span>',
1106
'<span class="mtk4">\\\'</span>',
1107
'<span class="mtk6">)/items`;\'</span>',
1108
],
1109
mapping: [
1110
[0, 0, 0], [0, 1, 1], [0, 2, 2], [0, 3, 3], [0, 4, 4], [0, 5, 5], [0, 6, 6], [0, 7, 7], [0, 8, 8], [0, 9, 9], [0, 10, 10], [0, 11, 11],
1111
[1, 0, 12], [1, 1, 13], [1, 2, 14], [1, 3, 15], [1, 4, 16], [1, 5, 17], [1, 6, 18], [1, 7, 19], [1, 8, 20], [1, 9, 21], [1, 10, 22], [1, 11, 23], [1, 12, 24], [1, 13, 25], [1, 14, 26], [1, 15, 27], [1, 16, 28], [1, 17, 29], [1, 18, 30], [1, 19, 31], [1, 20, 32], [1, 21, 33], [1, 22, 34], [1, 23, 35], [1, 24, 36], [1, 25, 37], [1, 26, 38], [1, 27, 39], [1, 28, 40], [1, 29, 41], [1, 30, 42], [1, 31, 43], [1, 32, 44], [1, 33, 45], [1, 34, 46], [1, 35, 47], [1, 36, 48],
1112
[2, 0, 49],
1113
[3, 0, 50],
1114
[4, 0, 51], [4, 1, 52], [4, 2, 53], [4, 3, 54], [4, 4, 55], [4, 5, 56], [4, 6, 57], [4, 7, 58], [4, 8, 59], [4, 9, 60], [4, 10, 61], [4, 11, 62], [4, 12, 63], [4, 13, 64], [4, 14, 65], [4, 15, 66], [4, 16, 67], [4, 17, 68], [4, 18, 69], [4, 19, 70], [4, 20, 71],
1115
[5, 0, 72], [5, 1, 73],
1116
[6, 0, 74], [6, 1, 75], [6, 2, 76], [6, 3, 77], [6, 4, 78], [6, 5, 79], [6, 6, 80], [6, 7, 81], [6, 8, 82], [6, 9, 83], [6, 10, 84]
1117
]
1118
}));
1119
});
1120
1121
test('createLineParts simple', () => {
1122
assert.deepStrictEqual(
1123
testCreateLineParts(
1124
false,
1125
'Hello world!',
1126
[
1127
createPart(12, 1)
1128
],
1129
0,
1130
'none',
1131
null
1132
),
1133
{
1134
html: [
1135
'<span class="mtk1">Hello\u00a0world!</span>'
1136
],
1137
mapping: [
1138
[0, 0, 0], [0, 1, 1], [0, 2, 2], [0, 3, 3], [0, 4, 4], [0, 5, 5], [0, 6, 6], [0, 7, 7], [0, 8, 8], [0, 9, 9], [0, 10, 10], [0, 11, 11], [0, 12, 12]
1139
]
1140
}
1141
);
1142
});
1143
1144
test('createLineParts simple two tokens', () => {
1145
assert.deepStrictEqual(
1146
testCreateLineParts(
1147
false,
1148
'Hello world!',
1149
[
1150
createPart(6, 1),
1151
createPart(12, 2)
1152
],
1153
0,
1154
'none',
1155
null
1156
),
1157
{
1158
html: [
1159
'<span class="mtk1">Hello\u00a0</span>',
1160
'<span class="mtk2">world!</span>',
1161
],
1162
mapping: [
1163
[0, 0, 0], [0, 1, 1], [0, 2, 2], [0, 3, 3], [0, 4, 4], [0, 5, 5],
1164
[1, 0, 6], [1, 1, 7], [1, 2, 8], [1, 3, 9], [1, 4, 10], [1, 5, 11], [1, 6, 12]
1165
]
1166
}
1167
);
1168
});
1169
1170
test('createLineParts render whitespace - 4 leading spaces', () => {
1171
assert.deepStrictEqual(
1172
testCreateLineParts(
1173
false,
1174
' Hello world! ',
1175
[
1176
createPart(4, 1),
1177
createPart(6, 2),
1178
createPart(20, 3)
1179
],
1180
0,
1181
'boundary',
1182
null
1183
),
1184
{
1185
html: [
1186
'<span class="mtkz" style="width:40px">\u00b7\u200c\u00b7\u200c\u00b7\u200c\u00b7\u200c</span>',
1187
'<span class="mtk2">He</span>',
1188
'<span class="mtk3">llo\u00a0world!</span>',
1189
'<span class="mtkz" style="width:40px">\u00b7\u200c\u00b7\u200c\u00b7\u200c\u00b7\u200c</span>',
1190
],
1191
mapping: [
1192
[0, 0, 0], [0, 2, 1], [0, 4, 2], [0, 6, 3],
1193
[1, 0, 4], [1, 1, 5],
1194
[2, 0, 6], [2, 1, 7], [2, 2, 8], [2, 3, 9], [2, 4, 10], [2, 5, 11], [2, 6, 12], [2, 7, 13], [2, 8, 14], [2, 9, 15],
1195
[3, 0, 16], [3, 2, 17], [3, 4, 18], [3, 6, 19], [3, 8, 20]
1196
]
1197
}
1198
);
1199
});
1200
1201
test('createLineParts render whitespace - 8 leading spaces', () => {
1202
assert.deepStrictEqual(
1203
testCreateLineParts(
1204
false,
1205
' Hello world! ',
1206
[
1207
createPart(8, 1),
1208
createPart(10, 2),
1209
createPart(28, 3)
1210
],
1211
0,
1212
'boundary',
1213
null
1214
),
1215
{
1216
html: [
1217
'<span class="mtkz" style="width:40px">\u00b7\u200c\u00b7\u200c\u00b7\u200c\u00b7\u200c</span>',
1218
'<span class="mtkz" style="width:40px">\u00b7\u200c\u00b7\u200c\u00b7\u200c\u00b7\u200c</span>',
1219
'<span class="mtk2">He</span>',
1220
'<span class="mtk3">llo\u00a0world!</span>',
1221
'<span class="mtkz" style="width:40px">\u00b7\u200c\u00b7\u200c\u00b7\u200c\u00b7\u200c</span>',
1222
'<span class="mtkz" style="width:40px">\u00b7\u200c\u00b7\u200c\u00b7\u200c\u00b7\u200c</span>',
1223
],
1224
mapping: [
1225
[0, 0, 0], [0, 2, 1], [0, 4, 2], [0, 6, 3],
1226
[1, 0, 4], [1, 2, 5], [1, 4, 6], [1, 6, 7],
1227
[2, 0, 8], [2, 1, 9],
1228
[3, 0, 10], [3, 1, 11], [3, 2, 12], [3, 3, 13], [3, 4, 14], [3, 5, 15], [3, 6, 16], [3, 7, 17], [3, 8, 18], [3, 9, 19],
1229
[4, 0, 20], [4, 2, 21], [4, 4, 22], [4, 6, 23],
1230
[5, 0, 24], [5, 2, 25], [5, 4, 26], [5, 6, 27], [5, 8, 28]
1231
]
1232
}
1233
);
1234
});
1235
1236
test('createLineParts render whitespace - 2 leading tabs', () => {
1237
assert.deepStrictEqual(
1238
testCreateLineParts(
1239
false,
1240
'\t\tHello world!\t',
1241
[
1242
createPart(2, 1),
1243
createPart(4, 2),
1244
createPart(15, 3)
1245
],
1246
0,
1247
'boundary',
1248
null
1249
),
1250
{
1251
html: [
1252
'<span class="mtkz" style="width:40px">\u2192\u00a0\u00a0\u00a0</span>',
1253
'<span class="mtkz" style="width:40px">\u2192\u00a0\u00a0\u00a0</span>',
1254
'<span class="mtk2">He</span>',
1255
'<span class="mtk3">llo\u00a0world!</span>',
1256
'<span class="mtkz" style="width:40px">\u2192\u00a0\u00a0\u00a0</span>',
1257
],
1258
mapping: [
1259
[0, 0, 0],
1260
[1, 0, 4],
1261
[2, 0, 8], [2, 1, 9],
1262
[3, 0, 10], [3, 1, 11], [3, 2, 12], [3, 3, 13], [3, 4, 14], [3, 5, 15], [3, 6, 16], [3, 7, 17], [3, 8, 18], [3, 9, 19],
1263
[4, 0, 20], [4, 4, 24]
1264
]
1265
}
1266
);
1267
});
1268
1269
test('createLineParts render whitespace - mixed leading spaces and tabs', () => {
1270
assert.deepStrictEqual(
1271
testCreateLineParts(
1272
false,
1273
' \t\t Hello world! \t \t \t ',
1274
[
1275
createPart(6, 1),
1276
createPart(8, 2),
1277
createPart(31, 3)
1278
],
1279
0,
1280
'boundary',
1281
null
1282
),
1283
{
1284
html: [
1285
'<span class="mtkz" style="width:40px">\u00b7\u200c\u00b7\u200c\u2192\u00a0</span>',
1286
'<span class="mtkz" style="width:40px">\u2192\u00a0\u00a0\u00a0</span>',
1287
'<span class="mtkz" style="width:20px">\u00b7\u200c\u00b7\u200c</span>',
1288
'<span class="mtk2">He</span>',
1289
'<span class="mtk3">llo\u00a0world!</span>',
1290
'<span class="mtkz" style="width:20px">\u00b7\u200c\uffeb</span>',
1291
'<span class="mtkz" style="width:40px">\u00b7\u200c\u00b7\u200c\u2192\u00a0</span>',
1292
'<span class="mtkz" style="width:40px">\u00b7\u200c\u00b7\u200c\u00b7\u200c\uffeb</span>',
1293
'<span class="mtkz" style="width:40px">\u00b7\u200c\u00b7\u200c\u00b7\u200c\u00b7\u200c</span>',
1294
],
1295
mapping: [
1296
[0, 0, 0], [0, 2, 1], [0, 4, 2],
1297
[1, 0, 4],
1298
[2, 0, 8], [2, 2, 9],
1299
[3, 0, 10], [3, 1, 11],
1300
[4, 0, 12], [4, 1, 13], [4, 2, 14], [4, 3, 15], [4, 4, 16], [4, 5, 17], [4, 6, 18], [4, 7, 19], [4, 8, 20], [4, 9, 21],
1301
[5, 0, 22], [5, 2, 23],
1302
[6, 0, 24], [6, 2, 25], [6, 4, 26],
1303
[7, 0, 28], [7, 2, 29], [7, 4, 30], [7, 6, 31],
1304
[8, 0, 32], [8, 2, 33], [8, 4, 34], [8, 6, 35], [8, 8, 36]
1305
]
1306
}
1307
);
1308
});
1309
1310
test('createLineParts render whitespace skips faux indent', () => {
1311
assert.deepStrictEqual(
1312
testCreateLineParts(
1313
false,
1314
'\t\t Hello world! \t \t \t ',
1315
[
1316
createPart(4, 1),
1317
createPart(6, 2),
1318
createPart(29, 3)
1319
],
1320
2,
1321
'boundary',
1322
null
1323
),
1324
{
1325
html: [
1326
'<span class="">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0</span>',
1327
'<span class="mtkz" style="width:20px">\u00b7\u200c\u00b7\u200c</span>',
1328
'<span class="mtk2">He</span>',
1329
'<span class="mtk3">llo\u00a0world!</span>',
1330
'<span class="mtkz" style="width:20px">\u00b7\u200c\uffeb</span>',
1331
'<span class="mtkz" style="width:40px">\u00b7\u200c\u00b7\u200c\u2192\u00a0</span>',
1332
'<span class="mtkz" style="width:40px">\u00b7\u200c\u00b7\u200c\u00b7\u200c\uffeb</span>',
1333
'<span class="mtkz" style="width:40px">\u00b7\u200c\u00b7\u200c\u00b7\u200c\u00b7\u200c</span>',
1334
],
1335
mapping: [
1336
[0, 0, 0], [0, 4, 4],
1337
[1, 0, 8], [1, 2, 9],
1338
[2, 0, 10], [2, 1, 11],
1339
[3, 0, 12], [3, 1, 13], [3, 2, 14], [3, 3, 15], [3, 4, 16], [3, 5, 17], [3, 6, 18], [3, 7, 19], [3, 8, 20], [3, 9, 21],
1340
[4, 0, 22], [4, 2, 23],
1341
[5, 0, 24], [5, 2, 25], [5, 4, 26],
1342
[6, 0, 28], [6, 2, 29], [6, 4, 30], [6, 6, 31],
1343
[7, 0, 32], [7, 2, 33], [7, 4, 34], [7, 6, 35], [7, 8, 36]
1344
]
1345
}
1346
);
1347
});
1348
1349
test('createLineParts does not emit width for monospace fonts', () => {
1350
assert.deepStrictEqual(
1351
testCreateLineParts(
1352
true,
1353
'\t\t Hello world! \t \t \t ',
1354
[
1355
createPart(4, 1),
1356
createPart(6, 2),
1357
createPart(29, 3)
1358
],
1359
2,
1360
'boundary',
1361
null
1362
),
1363
{
1364
html: [
1365
'<span class="">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0</span>',
1366
'<span class="mtkw">\u00b7\u200c\u00b7\u200c</span>',
1367
'<span class="mtk2">He</span>',
1368
'<span class="mtk3">llo\u00a0world!</span>',
1369
'<span class="mtkw">\u00b7\u200c\uffeb\u00b7\u200c\u00b7\u200c\u2192\u00a0\u00b7\u200c\u00b7\u200c\u00b7\u200c\uffeb\u00b7\u200c\u00b7\u200c\u00b7\u200c\u00b7\u200c</span>',
1370
],
1371
mapping: [
1372
[0, 0, 0], [0, 4, 4],
1373
[1, 0, 8], [1, 2, 9],
1374
[2, 0, 10], [2, 1, 11],
1375
[3, 0, 12], [3, 1, 13], [3, 2, 14], [3, 3, 15], [3, 4, 16], [3, 5, 17], [3, 6, 18], [3, 7, 19], [3, 8, 20], [3, 9, 21],
1376
[4, 0, 22], [4, 2, 23], [4, 3, 24], [4, 5, 25], [4, 7, 26], [4, 9, 28], [4, 11, 29], [4, 13, 30], [4, 15, 31], [4, 16, 32], [4, 18, 33], [4, 20, 34], [4, 22, 35], [4, 24, 36]
1377
]
1378
}
1379
);
1380
});
1381
1382
test('createLineParts render whitespace in middle but not for one space', () => {
1383
assert.deepStrictEqual(
1384
testCreateLineParts(
1385
false,
1386
'it it it it',
1387
[
1388
createPart(6, 1),
1389
createPart(7, 2),
1390
createPart(13, 3)
1391
],
1392
0,
1393
'boundary',
1394
null
1395
),
1396
{
1397
html: [
1398
'<span class="mtk1">it</span>',
1399
'<span class="mtkz" style="width:20px">\u00b7\u200c\u00b7\u200c</span>',
1400
'<span class="mtk1">it</span>',
1401
'<span class="mtk2">\u00a0</span>',
1402
'<span class="mtk3">it</span>',
1403
'<span class="mtkz" style="width:20px">\u00b7\u200c\u00b7\u200c</span>',
1404
'<span class="mtk3">it</span>',
1405
],
1406
mapping: [
1407
[0, 0, 0], [0, 1, 1],
1408
[1, 0, 2], [1, 2, 3],
1409
[2, 0, 4], [2, 1, 5],
1410
[3, 0, 6],
1411
[4, 0, 7], [4, 1, 8],
1412
[5, 0, 9], [5, 2, 10],
1413
[6, 0, 11], [6, 1, 12], [6, 2, 13]
1414
]
1415
}
1416
);
1417
});
1418
1419
test('createLineParts render whitespace for all in middle', () => {
1420
assert.deepStrictEqual(
1421
testCreateLineParts(
1422
false,
1423
' Hello world!\t',
1424
[
1425
createPart(4, 0),
1426
createPart(6, 1),
1427
createPart(14, 2)
1428
],
1429
0,
1430
'all',
1431
null
1432
),
1433
{
1434
html: [
1435
'<span class="mtkz" style="width:10px">\u00b7\u200c</span>',
1436
'<span class="mtk0">Hel</span>',
1437
'<span class="mtk1">lo</span>',
1438
'<span class="mtkz" style="width:10px">\u00b7\u200c</span>',
1439
'<span class="mtk2">world!</span>',
1440
'<span class="mtkz" style="width:30px">\u2192\u00a0\u00a0</span>',
1441
],
1442
mapping: [
1443
[0, 0, 0],
1444
[1, 0, 1], [1, 1, 2], [1, 2, 3],
1445
[2, 0, 4], [2, 1, 5],
1446
[3, 0, 6],
1447
[4, 0, 7], [4, 1, 8], [4, 2, 9], [4, 3, 10], [4, 4, 11], [4, 5, 12],
1448
[5, 0, 13], [5, 3, 16]
1449
]
1450
}
1451
);
1452
});
1453
1454
test('createLineParts render whitespace for selection with no selections', () => {
1455
assert.deepStrictEqual(
1456
testCreateLineParts(
1457
false,
1458
' Hello world!\t',
1459
[
1460
createPart(4, 0),
1461
createPart(6, 1),
1462
createPart(14, 2)
1463
],
1464
0,
1465
'selection',
1466
null
1467
),
1468
{
1469
html: [
1470
'<span class="mtk0">\u00a0Hel</span>',
1471
'<span class="mtk1">lo</span>',
1472
'<span class="mtk2">\u00a0world!\u00a0\u00a0\u00a0</span>',
1473
],
1474
mapping: [
1475
[0, 0, 0], [0, 1, 1], [0, 2, 2], [0, 3, 3],
1476
[1, 0, 4], [1, 1, 5],
1477
[2, 0, 6], [2, 1, 7], [2, 2, 8], [2, 3, 9], [2, 4, 10], [2, 5, 11], [2, 6, 12], [2, 7, 13], [2, 10, 16]
1478
]
1479
}
1480
);
1481
});
1482
1483
test('createLineParts render whitespace for selection with whole line selection', () => {
1484
assert.deepStrictEqual(
1485
testCreateLineParts(
1486
false,
1487
' Hello world!\t',
1488
[
1489
createPart(4, 0),
1490
createPart(6, 1),
1491
createPart(14, 2)
1492
],
1493
0,
1494
'selection',
1495
[new OffsetRange(0, 14)]
1496
),
1497
{
1498
html: [
1499
'<span class="mtkz" style="width:10px">\u00b7\u200c</span>',
1500
'<span class="mtk0">Hel</span>',
1501
'<span class="mtk1">lo</span>',
1502
'<span class="mtkz" style="width:10px">\u00b7\u200c</span>',
1503
'<span class="mtk2">world!</span>',
1504
'<span class="mtkz" style="width:30px">\u2192\u00a0\u00a0</span>',
1505
],
1506
mapping: [
1507
[0, 0, 0],
1508
[1, 0, 1], [1, 1, 2], [1, 2, 3],
1509
[2, 0, 4], [2, 1, 5],
1510
[3, 0, 6],
1511
[4, 0, 7], [4, 1, 8], [4, 2, 9], [4, 3, 10], [4, 4, 11], [4, 5, 12],
1512
[5, 0, 13], [5, 3, 16]
1513
]
1514
}
1515
);
1516
});
1517
1518
test('createLineParts render whitespace for selection with selection spanning part of whitespace', () => {
1519
assert.deepStrictEqual(
1520
testCreateLineParts(
1521
false,
1522
' Hello world!\t',
1523
[
1524
createPart(4, 0),
1525
createPart(6, 1),
1526
createPart(14, 2)
1527
],
1528
0,
1529
'selection',
1530
[new OffsetRange(0, 5)]
1531
),
1532
{
1533
html: [
1534
'<span class="mtkz" style="width:10px">\u00b7\u200c</span>',
1535
'<span class="mtk0">Hel</span>',
1536
'<span class="mtk1">lo</span>',
1537
'<span class="mtk2">\u00a0world!\u00a0\u00a0\u00a0</span>',
1538
],
1539
mapping: [
1540
[0, 0, 0],
1541
[1, 0, 1], [1, 1, 2], [1, 2, 3],
1542
[2, 0, 4], [2, 1, 5],
1543
[3, 0, 6], [3, 1, 7], [3, 2, 8], [3, 3, 9], [3, 4, 10], [3, 5, 11], [3, 6, 12], [3, 7, 13], [3, 10, 16]
1544
]
1545
}
1546
);
1547
});
1548
1549
test('createLineParts render whitespace for selection with multiple selections', () => {
1550
assert.deepStrictEqual(
1551
testCreateLineParts(
1552
false,
1553
' Hello world!\t',
1554
[
1555
createPart(4, 0),
1556
createPart(6, 1),
1557
createPart(14, 2)
1558
],
1559
0,
1560
'selection',
1561
[new OffsetRange(0, 5), new OffsetRange(9, 14)]
1562
),
1563
{
1564
html: [
1565
'<span class="mtkz" style="width:10px">\u00b7\u200c</span>',
1566
'<span class="mtk0">Hel</span>',
1567
'<span class="mtk1">lo</span>',
1568
'<span class="mtk2">\u00a0world!</span>',
1569
'<span class="mtkz" style="width:30px">\u2192\u00a0\u00a0</span>',
1570
],
1571
mapping: [
1572
[0, 0, 0],
1573
[1, 0, 1], [1, 1, 2], [1, 2, 3],
1574
[2, 0, 4], [2, 1, 5],
1575
[3, 0, 6], [3, 1, 7], [3, 2, 8], [3, 3, 9], [3, 4, 10], [3, 5, 11], [3, 6, 12],
1576
[4, 0, 13], [4, 3, 16]
1577
]
1578
}
1579
);
1580
});
1581
1582
test('createLineParts render whitespace for selection with multiple, initially unsorted selections', () => {
1583
assert.deepStrictEqual(
1584
testCreateLineParts(
1585
false,
1586
' Hello world!\t',
1587
[
1588
createPart(4, 0),
1589
createPart(6, 1),
1590
createPart(14, 2)
1591
],
1592
0,
1593
'selection',
1594
[new OffsetRange(9, 14), new OffsetRange(0, 5)]
1595
),
1596
{
1597
html: [
1598
'<span class="mtkz" style="width:10px">\u00b7\u200c</span>',
1599
'<span class="mtk0">Hel</span>',
1600
'<span class="mtk1">lo</span>',
1601
'<span class="mtk2">\u00a0world!</span>',
1602
'<span class="mtkz" style="width:30px">\u2192\u00a0\u00a0</span>',
1603
],
1604
mapping: [
1605
[0, 0, 0],
1606
[1, 0, 1], [1, 1, 2], [1, 2, 3],
1607
[2, 0, 4], [2, 1, 5],
1608
[3, 0, 6], [3, 1, 7], [3, 2, 8], [3, 3, 9], [3, 4, 10], [3, 5, 11], [3, 6, 12],
1609
[4, 0, 13], [4, 3, 16]
1610
]
1611
}
1612
);
1613
});
1614
1615
test('createLineParts render whitespace for selection with selections next to each other', () => {
1616
assert.deepStrictEqual(
1617
testCreateLineParts(
1618
false,
1619
' * S',
1620
[
1621
createPart(4, 0)
1622
],
1623
0,
1624
'selection',
1625
[new OffsetRange(0, 1), new OffsetRange(1, 2), new OffsetRange(2, 3)]
1626
),
1627
{
1628
html: [
1629
'<span class="mtkz" style="width:10px">\u00b7\u200c</span>',
1630
'<span class="mtk0">*</span>',
1631
'<span class="mtkz" style="width:10px">\u00b7\u200c</span>',
1632
'<span class="mtk0">S</span>',
1633
],
1634
mapping: [
1635
[0, 0, 0],
1636
[1, 0, 1],
1637
[2, 0, 2],
1638
[3, 0, 3], [3, 1, 4]
1639
]
1640
}
1641
);
1642
});
1643
1644
test('createLineParts render whitespace for trailing with leading, inner, and without trailing whitespace', () => {
1645
assert.deepStrictEqual(
1646
testCreateLineParts(
1647
false,
1648
' Hello world!',
1649
[
1650
createPart(4, 0),
1651
createPart(6, 1),
1652
createPart(14, 2)
1653
],
1654
0,
1655
'trailing',
1656
null
1657
),
1658
{
1659
html: [
1660
'<span class="mtk0">\u00a0Hel</span>',
1661
'<span class="mtk1">lo</span>',
1662
'<span class="mtk2">\u00a0world!</span>',
1663
],
1664
mapping: [
1665
[0, 0, 0], [0, 1, 1], [0, 2, 2], [0, 3, 3],
1666
[1, 0, 4], [1, 1, 5],
1667
[2, 0, 6], [2, 1, 7], [2, 2, 8], [2, 3, 9], [2, 4, 10], [2, 5, 11], [2, 6, 12], [2, 7, 13]
1668
]
1669
}
1670
);
1671
});
1672
1673
test('createLineParts render whitespace for trailing with leading, inner, and trailing whitespace', () => {
1674
assert.deepStrictEqual(
1675
testCreateLineParts(
1676
false,
1677
' Hello world! \t',
1678
[
1679
createPart(4, 0),
1680
createPart(6, 1),
1681
createPart(15, 2)
1682
],
1683
0,
1684
'trailing',
1685
null
1686
),
1687
{
1688
html: [
1689
'<span class="mtk0">\u00a0Hel</span>',
1690
'<span class="mtk1">lo</span>',
1691
'<span class="mtk2">\u00a0world!</span>',
1692
'<span class="mtkz" style="width:30px">\u00b7\u200c\u2192\u00a0</span>',
1693
],
1694
mapping: [
1695
[0, 0, 0], [0, 1, 1], [0, 2, 2], [0, 3, 3],
1696
[1, 0, 4], [1, 1, 5],
1697
[2, 0, 6], [2, 1, 7], [2, 2, 8], [2, 3, 9], [2, 4, 10], [2, 5, 11], [2, 6, 12],
1698
[3, 0, 13], [3, 2, 14], [3, 4, 16]
1699
]
1700
}
1701
);
1702
});
1703
1704
test('createLineParts render whitespace for trailing with 8 leading and 8 trailing whitespaces', () => {
1705
assert.deepStrictEqual(
1706
testCreateLineParts(
1707
false,
1708
' Hello world! ',
1709
[
1710
createPart(8, 1),
1711
createPart(10, 2),
1712
createPart(28, 3)
1713
],
1714
0,
1715
'trailing',
1716
null
1717
),
1718
{
1719
html: [
1720
'<span class="mtk1">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0</span>',
1721
'<span class="mtk2">He</span>',
1722
'<span class="mtk3">llo\u00a0world!</span>',
1723
'<span class="mtkz" style="width:40px">\u00b7\u200c\u00b7\u200c\u00b7\u200c\u00b7\u200c</span>',
1724
'<span class="mtkz" style="width:40px">\u00b7\u200c\u00b7\u200c\u00b7\u200c\u00b7\u200c</span>',
1725
],
1726
mapping: [
1727
[0, 0, 0], [0, 1, 1], [0, 2, 2], [0, 3, 3], [0, 4, 4], [0, 5, 5], [0, 6, 6], [0, 7, 7],
1728
[1, 0, 8], [1, 1, 9],
1729
[2, 0, 10], [2, 1, 11], [2, 2, 12], [2, 3, 13], [2, 4, 14], [2, 5, 15], [2, 6, 16], [2, 7, 17], [2, 8, 18], [2, 9, 19],
1730
[3, 0, 20], [3, 2, 21], [3, 4, 22], [3, 6, 23],
1731
[4, 0, 24], [4, 2, 25], [4, 4, 26], [4, 6, 27], [4, 8, 28]
1732
]
1733
}
1734
);
1735
});
1736
1737
test('createLineParts render whitespace for trailing with line containing only whitespaces', () => {
1738
assert.deepStrictEqual(
1739
testCreateLineParts(
1740
false,
1741
' \t ',
1742
[
1743
createPart(2, 0),
1744
createPart(3, 1),
1745
],
1746
0,
1747
'trailing',
1748
null
1749
),
1750
{
1751
html: [
1752
'<span class="mtkz" style="width:40px">\u00b7\u200c\u2192\u00a0\u00a0</span>',
1753
'<span class="mtkz" style="width:10px">\u00b7\u200c</span>',
1754
],
1755
mapping: [
1756
[0, 0, 0], [0, 2, 1],
1757
[1, 0, 4], [1, 2, 5]
1758
]
1759
}
1760
);
1761
});
1762
1763
test('createLineParts can handle unsorted inline decorations', () => {
1764
const actual = renderViewLine(new RenderLineInput(
1765
false,
1766
true,
1767
'Hello world',
1768
false,
1769
true,
1770
false,
1771
0,
1772
createViewLineTokens([createPart(11, 0)]),
1773
[
1774
new LineDecoration(5, 7, 'a', InlineDecorationType.Regular),
1775
new LineDecoration(1, 3, 'b', InlineDecorationType.Regular),
1776
new LineDecoration(2, 8, 'c', InlineDecorationType.Regular),
1777
],
1778
4,
1779
0,
1780
10,
1781
10,
1782
10,
1783
-1,
1784
'none',
1785
false,
1786
false,
1787
null,
1788
null,
1789
14
1790
));
1791
1792
// 01234567890
1793
// Hello world
1794
// ----aa-----
1795
// bb---------
1796
// -cccccc----
1797
1798
assert.deepStrictEqual(inflateRenderLineOutput(actual), {
1799
html: [
1800
'<span class="mtk0 b">H</span>',
1801
'<span class="mtk0 b c">e</span>',
1802
'<span class="mtk0 c">ll</span>',
1803
'<span class="mtk0 a c">o\u00a0</span>',
1804
'<span class="mtk0 c">w</span>',
1805
'<span class="mtk0">orld</span>',
1806
],
1807
mapping: [
1808
[0, 0, 0],
1809
[1, 0, 1],
1810
[2, 0, 2], [2, 1, 3],
1811
[3, 0, 4], [3, 1, 5],
1812
[4, 0, 6],
1813
[5, 0, 7], [5, 1, 8], [5, 2, 9], [5, 3, 10], [5, 4, 11]
1814
]
1815
});
1816
});
1817
1818
test('issue #11485: Visible whitespace conflicts with before decorator attachment', () => {
1819
1820
const lineContent = '\tbla';
1821
1822
const actual = renderViewLine(new RenderLineInput(
1823
false,
1824
true,
1825
lineContent,
1826
false,
1827
true,
1828
false,
1829
0,
1830
createViewLineTokens([createPart(4, 3)]),
1831
[new LineDecoration(1, 2, 'before', InlineDecorationType.Before)],
1832
4,
1833
0,
1834
10,
1835
10,
1836
10,
1837
-1,
1838
'all',
1839
false,
1840
true,
1841
null,
1842
null,
1843
14
1844
));
1845
1846
assert.deepStrictEqual(inflateRenderLineOutput(actual), {
1847
html: [
1848
'<span class="mtkw before">\u2192\u00a0\u00a0\u00a0</span>',
1849
'<span class="mtk3">bla</span>',
1850
],
1851
mapping: [
1852
[0, 0, 0],
1853
[1, 0, 4], [1, 1, 5], [1, 2, 6], [1, 3, 7]
1854
]
1855
});
1856
});
1857
1858
test('issue #32436: Non-monospace font + visible whitespace + After decorator causes line to "jump"', () => {
1859
1860
const lineContent = '\tbla';
1861
1862
const actual = renderViewLine(new RenderLineInput(
1863
false,
1864
true,
1865
lineContent,
1866
false,
1867
true,
1868
false,
1869
0,
1870
createViewLineTokens([createPart(4, 3)]),
1871
[new LineDecoration(2, 3, 'before', InlineDecorationType.Before)],
1872
4,
1873
0,
1874
10,
1875
10,
1876
10,
1877
-1,
1878
'all',
1879
false,
1880
true,
1881
null,
1882
null,
1883
14
1884
));
1885
1886
assert.deepStrictEqual(inflateRenderLineOutput(actual), {
1887
html: [
1888
'<span class="mtkz" style="width:40px">\u2192\u00a0\u00a0\u00a0</span>',
1889
'<span class="mtk3 before">b</span>',
1890
'<span class="mtk3">la</span>',
1891
],
1892
mapping: [
1893
[0, 0, 0],
1894
[1, 0, 4],
1895
[2, 0, 5], [2, 1, 6], [2, 2, 7]
1896
]
1897
});
1898
});
1899
1900
test('issue #30133: Empty lines don\'t render inline decorations', () => {
1901
1902
const lineContent = '';
1903
1904
const actual = renderViewLine(new RenderLineInput(
1905
false,
1906
true,
1907
lineContent,
1908
false,
1909
true,
1910
false,
1911
0,
1912
createViewLineTokens([createPart(0, 3)]),
1913
[new LineDecoration(1, 2, 'before', InlineDecorationType.Before)],
1914
4,
1915
0,
1916
10,
1917
10,
1918
10,
1919
-1,
1920
'all',
1921
false,
1922
true,
1923
null,
1924
null,
1925
14
1926
));
1927
1928
assert.deepStrictEqual(inflateRenderLineOutput(actual), {
1929
html: [
1930
'<span class="before"></span>',
1931
],
1932
mapping: [
1933
[1, 0, 0]
1934
]
1935
});
1936
});
1937
1938
test('issue #37208: Collapsing bullet point containing emoji in Markdown document results in [??] character', () => {
1939
1940
const actual = renderViewLine(new RenderLineInput(
1941
true,
1942
true,
1943
' 1. 🙏',
1944
false,
1945
false,
1946
false,
1947
0,
1948
createViewLineTokens([createPart(7, 3)]),
1949
[new LineDecoration(7, 8, 'inline-folded', InlineDecorationType.After)],
1950
2,
1951
0,
1952
10,
1953
10,
1954
10,
1955
10000,
1956
'none',
1957
false,
1958
false,
1959
null,
1960
null,
1961
14
1962
));
1963
1964
assert.deepStrictEqual(inflateRenderLineOutput(actual), {
1965
html: [
1966
'<span class="mtk3">\u00a0\u00a01.\u00a0</span>',
1967
'<span class="mtk3 inline-folded">🙏</span>',
1968
],
1969
mapping: [
1970
[0, 0, 0], [0, 1, 1], [0, 2, 2], [0, 3, 3], [0, 4, 4],
1971
[1, 0, 5], [1, 1, 6], [1, 2, 7]
1972
]
1973
});
1974
});
1975
1976
test('issue #37401 #40127: Allow both before and after decorations on empty line', () => {
1977
1978
const actual = renderViewLine(new RenderLineInput(
1979
true,
1980
true,
1981
'',
1982
false,
1983
true,
1984
false,
1985
0,
1986
createViewLineTokens([createPart(0, 3)]),
1987
[
1988
new LineDecoration(1, 1, 'before', InlineDecorationType.Before),
1989
new LineDecoration(1, 1, 'after', InlineDecorationType.After),
1990
],
1991
2,
1992
0,
1993
10,
1994
10,
1995
10,
1996
10000,
1997
'none',
1998
false,
1999
false,
2000
null,
2001
null,
2002
14
2003
));
2004
2005
assert.deepStrictEqual(inflateRenderLineOutput(actual), {
2006
html: [
2007
'<span class="before"></span>',
2008
'<span class="after"></span>',
2009
],
2010
mapping: [
2011
[1, 0, 0]
2012
]
2013
});
2014
});
2015
2016
test('issue #118759: enable multiple text editor decorations in empty lines', () => {
2017
2018
const actual = renderViewLine(new RenderLineInput(
2019
true,
2020
true,
2021
'',
2022
false,
2023
true,
2024
false,
2025
0,
2026
createViewLineTokens([createPart(0, 3)]),
2027
[
2028
new LineDecoration(1, 1, 'after1', InlineDecorationType.After),
2029
new LineDecoration(1, 1, 'after2', InlineDecorationType.After),
2030
new LineDecoration(1, 1, 'before1', InlineDecorationType.Before),
2031
new LineDecoration(1, 1, 'before2', InlineDecorationType.Before),
2032
],
2033
2,
2034
0,
2035
10,
2036
10,
2037
10,
2038
10000,
2039
'none',
2040
false,
2041
false,
2042
null,
2043
null,
2044
14
2045
));
2046
2047
assert.deepStrictEqual(inflateRenderLineOutput(actual), {
2048
html: [
2049
'<span class="before1"></span>',
2050
'<span class="before2"></span>',
2051
'<span class="after1"></span>',
2052
'<span class="after2"></span>',
2053
],
2054
mapping: [
2055
[2, 0, 0]
2056
]
2057
});
2058
});
2059
2060
test('issue #38935: GitLens end-of-line blame no longer rendering', () => {
2061
2062
const actual = renderViewLine(new RenderLineInput(
2063
true,
2064
true,
2065
'\t}',
2066
false,
2067
true,
2068
false,
2069
0,
2070
createViewLineTokens([createPart(2, 3)]),
2071
[
2072
new LineDecoration(3, 3, 'ced-TextEditorDecorationType2-5e9b9b3f-3 ced-TextEditorDecorationType2-3', InlineDecorationType.Before),
2073
new LineDecoration(3, 3, 'ced-TextEditorDecorationType2-5e9b9b3f-4 ced-TextEditorDecorationType2-4', InlineDecorationType.After),
2074
],
2075
4,
2076
0,
2077
10,
2078
10,
2079
10,
2080
10000,
2081
'none',
2082
false,
2083
false,
2084
null,
2085
null,
2086
14
2087
));
2088
2089
assert.deepStrictEqual(inflateRenderLineOutput(actual), {
2090
html: [
2091
'<span class="mtk3">\u00a0\u00a0\u00a0\u00a0}</span>',
2092
'<span class="ced-TextEditorDecorationType2-5e9b9b3f-3 ced-TextEditorDecorationType2-3"></span>',
2093
'<span class="ced-TextEditorDecorationType2-5e9b9b3f-4 ced-TextEditorDecorationType2-4"></span>',
2094
],
2095
mapping: [
2096
[0, 0, 0], [0, 4, 4],
2097
[2, 0, 5]
2098
]
2099
});
2100
});
2101
2102
test('issue #136622: Inline decorations are not rendering on non-ASCII lines when renderControlCharacters is on', () => {
2103
2104
const actual = renderViewLine(new RenderLineInput(
2105
true,
2106
true,
2107
'some text £',
2108
false,
2109
false,
2110
false,
2111
0,
2112
createViewLineTokens([createPart(11, 3)]),
2113
[
2114
new LineDecoration(5, 5, 'inlineDec1', InlineDecorationType.After),
2115
new LineDecoration(6, 6, 'inlineDec2', InlineDecorationType.Before),
2116
],
2117
4,
2118
0,
2119
10,
2120
10,
2121
10,
2122
10000,
2123
'none',
2124
true,
2125
false,
2126
null,
2127
null,
2128
14
2129
));
2130
2131
assert.deepStrictEqual(inflateRenderLineOutput(actual), {
2132
html: [
2133
'<span class="mtk3">some</span>',
2134
'<span class="mtk3 inlineDec1"></span>',
2135
'<span class="mtk3">\u00a0</span>',
2136
'<span class="mtk3 inlineDec2"></span>',
2137
'<span class="mtk3">text\u00a0£</span>',
2138
],
2139
mapping: [
2140
[0, 0, 0], [0, 1, 1], [0, 2, 2], [0, 3, 3],
2141
[1, 0, 4],
2142
[4, 0, 5], [4, 1, 6], [4, 2, 7], [4, 3, 8], [4, 4, 9], [4, 5, 10], [4, 6, 11]
2143
]
2144
});
2145
});
2146
2147
test('issue #22832: Consider fullwidth characters when rendering tabs', () => {
2148
2149
const actual = renderViewLine(new RenderLineInput(
2150
true,
2151
true,
2152
'asd = "擦"\t\t#asd',
2153
false,
2154
false,
2155
false,
2156
0,
2157
createViewLineTokens([createPart(15, 3)]),
2158
[],
2159
4,
2160
0,
2161
10,
2162
10,
2163
10,
2164
10000,
2165
'none',
2166
false,
2167
false,
2168
null,
2169
null,
2170
14
2171
));
2172
2173
assert.deepStrictEqual(inflateRenderLineOutput(actual), {
2174
html: [
2175
'<span class="mtk3">asd\u00a0=\u00a0"擦"\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0#asd</span>',
2176
],
2177
mapping: [
2178
[0, 0, 0], [0, 1, 1], [0, 2, 2], [0, 3, 3], [0, 4, 4], [0, 5, 5], [0, 6, 6], [0, 7, 7], [0, 8, 9],
2179
[0, 9, 10], [0, 11, 12], [0, 15, 16], [0, 16, 17], [0, 17, 18], [0, 18, 19], [0, 19, 20]
2180
]
2181
});
2182
});
2183
2184
test('issue #22832: Consider fullwidth characters when rendering tabs (render whitespace)', () => {
2185
2186
const actual = renderViewLine(new RenderLineInput(
2187
true,
2188
true,
2189
'asd = "擦"\t\t#asd',
2190
false,
2191
false,
2192
false,
2193
0,
2194
createViewLineTokens([createPart(15, 3)]),
2195
[],
2196
4,
2197
0,
2198
10,
2199
10,
2200
10,
2201
10000,
2202
'all',
2203
false,
2204
false,
2205
null,
2206
null,
2207
14
2208
));
2209
2210
assert.deepStrictEqual(inflateRenderLineOutput(actual), {
2211
html: [
2212
'<span class="mtk3">asd</span>',
2213
'<span class="mtkw">\u00b7\u200c</span>',
2214
'<span class="mtk3">=</span>',
2215
'<span class="mtkw">\u00b7\u200c</span>',
2216
'<span class="mtk3">"擦"</span>',
2217
'<span class="mtkw">\u2192\u00a0\u2192\u00a0\u00a0\u00a0</span>',
2218
'<span class="mtk3">#asd</span>',
2219
],
2220
mapping: [
2221
[0, 0, 0], [0, 1, 1], [0, 2, 2],
2222
[1, 0, 3],
2223
[2, 0, 4],
2224
[3, 0, 5],
2225
[4, 0, 6], [4, 1, 7], [4, 2, 9],
2226
[5, 0, 10], [5, 2, 12],
2227
[6, 0, 16], [6, 1, 17], [6, 2, 18], [6, 3, 19], [6, 4, 20]
2228
]
2229
});
2230
});
2231
2232
test('issue #22352: COMBINING ACUTE ACCENT (U+0301)', () => {
2233
2234
const actual = renderViewLine(new RenderLineInput(
2235
true,
2236
true,
2237
'12345689012345678901234568901234567890123456890abába',
2238
false,
2239
false,
2240
false,
2241
0,
2242
createViewLineTokens([createPart(53, 3)]),
2243
[],
2244
4,
2245
0,
2246
10,
2247
10,
2248
10,
2249
10000,
2250
'none',
2251
false,
2252
false,
2253
null,
2254
null,
2255
14
2256
));
2257
2258
assert.deepStrictEqual(inflateRenderLineOutput(actual), {
2259
html: [
2260
'<span class="mtk3">12345689012345678901234568901234567890123456890abába</span>',
2261
],
2262
mapping: [
2263
[0, 0, 0], [0, 1, 1], [0, 2, 2], [0, 3, 3], [0, 4, 4], [0, 5, 5], [0, 6, 6], [0, 7, 7],
2264
[0, 8, 8], [0, 9, 9], [0, 10, 10], [0, 11, 11], [0, 12, 12], [0, 13, 13], [0, 14, 14],
2265
[0, 15, 15], [0, 16, 16], [0, 17, 17], [0, 18, 18], [0, 19, 19], [0, 20, 20], [0, 21, 21],
2266
[0, 22, 22], [0, 23, 23], [0, 24, 24], [0, 25, 25], [0, 26, 26], [0, 27, 27], [0, 28, 28],
2267
[0, 29, 29], [0, 30, 30], [0, 31, 31], [0, 32, 32], [0, 33, 33], [0, 34, 34], [0, 35, 35],
2268
[0, 36, 36], [0, 37, 37], [0, 38, 38], [0, 39, 39], [0, 40, 40], [0, 41, 41], [0, 42, 42],
2269
[0, 43, 43], [0, 44, 44], [0, 45, 45], [0, 46, 46], [0, 47, 47], [0, 48, 48], [0, 49, 49],
2270
[0, 50, 50], [0, 51, 51], [0, 52, 52], [0, 53, 53]
2271
]
2272
});
2273
});
2274
2275
test('issue #22352: Partially Broken Complex Script Rendering of Tamil', () => {
2276
2277
const actual = renderViewLine(new RenderLineInput(
2278
true,
2279
true,
2280
' JoyShareல் பின்தொடர்ந்து, விடீயோ, ஜோக்குகள், அனிமேசன், நகைச்சுவை படங்கள் மற்றும் செய்திகளை பெறுவீர்',
2281
false,
2282
false,
2283
false,
2284
0,
2285
createViewLineTokens([createPart(100, 3)]),
2286
[],
2287
4,
2288
0,
2289
10,
2290
10,
2291
10,
2292
10000,
2293
'none',
2294
false,
2295
false,
2296
null,
2297
null,
2298
14
2299
));
2300
2301
assert.deepStrictEqual(inflateRenderLineOutput(actual), {
2302
html: [
2303
'<span class="mtk3">\u00a0JoyShareல்\u00a0பின்தொடர்ந்து,\u00a0விடீயோ,\u00a0ஜோக்குகள்,\u00a0</span>',
2304
'<span class="mtk3">அனிமேசன்,\u00a0நகைச்சுவை\u00a0படங்கள்\u00a0மற்றும்\u00a0செய்திகளை\u00a0</span>',
2305
'<span class="mtk3">பெறுவீர்</span>',
2306
],
2307
mapping: [
2308
[0, 0, 0], [0, 1, 1], [0, 2, 2], [0, 3, 3], [0, 4, 4], [0, 5, 5], [0, 6, 6], [0, 7, 7],
2309
[0, 8, 8], [0, 9, 9], [0, 10, 10], [0, 11, 11], [0, 12, 12], [0, 13, 13], [0, 14, 14],
2310
[0, 15, 15], [0, 16, 16], [0, 17, 17], [0, 18, 18], [0, 19, 19], [0, 20, 20], [0, 21, 21],
2311
[0, 22, 22], [0, 23, 23], [0, 24, 24], [0, 25, 25], [0, 26, 26], [0, 27, 27], [0, 28, 28],
2312
[0, 29, 29], [0, 30, 30], [0, 31, 31], [0, 32, 32], [0, 33, 33], [0, 34, 34], [0, 35, 35],
2313
[0, 36, 36], [0, 37, 37], [0, 38, 38], [0, 39, 39], [0, 40, 40], [0, 41, 41], [0, 42, 42],
2314
[0, 43, 43], [0, 44, 44], [0, 45, 45],
2315
[1, 0, 46], [1, 1, 47], [1, 2, 48], [1, 3, 49], [1, 4, 50], [1, 5, 51], [1, 6, 52], [1, 7, 53],
2316
[1, 8, 54], [1, 9, 55], [1, 10, 56], [1, 11, 57], [1, 12, 58], [1, 13, 59], [1, 14, 60], [1, 15, 61],
2317
[1, 16, 62], [1, 17, 63], [1, 18, 64], [1, 19, 65], [1, 20, 66], [1, 21, 67], [1, 22, 68], [1, 23, 69],
2318
[1, 24, 70], [1, 25, 71], [1, 26, 72], [1, 27, 73], [1, 28, 74], [1, 29, 75], [1, 30, 76], [1, 31, 77],
2319
[1, 32, 78], [1, 33, 79], [1, 34, 80], [1, 35, 81], [1, 36, 82], [1, 37, 83], [1, 38, 84], [1, 39, 85],
2320
[1, 40, 86], [1, 41, 87], [1, 42, 88], [1, 43, 89], [1, 44, 90], [1, 45, 91],
2321
[2, 0, 92], [2, 1, 93], [2, 2, 94], [2, 3, 95], [2, 4, 96], [2, 5, 97], [2, 6, 98], [2, 7, 99], [2, 8, 100]
2322
]
2323
});
2324
});
2325
2326
test('issue #42700: Hindi characters are not being rendered properly', () => {
2327
2328
const actual = renderViewLine(new RenderLineInput(
2329
true,
2330
true,
2331
' वो ऐसा क्या है जो हमारे अंदर भी है और बाहर भी है। जिसकी वजह से हम सब हैं। जिसने इस सृष्टि की रचना की है।',
2332
false,
2333
false,
2334
false,
2335
0,
2336
createViewLineTokens([createPart(105, 3)]),
2337
[],
2338
4,
2339
0,
2340
10,
2341
10,
2342
10,
2343
10000,
2344
'none',
2345
false,
2346
false,
2347
null,
2348
null,
2349
14
2350
));
2351
2352
assert.deepStrictEqual(inflateRenderLineOutput(actual), {
2353
html: [
2354
'<span class="mtk3">\u00a0वो\u00a0ऐसा\u00a0क्या\u00a0है\u00a0जो\u00a0हमारे\u00a0अंदर\u00a0भी\u00a0है\u00a0और\u00a0बाहर\u00a0भी\u00a0है।\u00a0</span>',
2355
'<span class="mtk3">जिसकी\u00a0वजह\u00a0से\u00a0हम\u00a0सब\u00a0हैं।\u00a0जिसने\u00a0इस\u00a0सृष्टि\u00a0की\u00a0रचना\u00a0की\u00a0</span>',
2356
'<span class="mtk3">है।</span>',
2357
],
2358
mapping: [
2359
[0, 0, 0], [0, 1, 1], [0, 2, 2], [0, 3, 3], [0, 4, 4], [0, 5, 5], [0, 6, 6], [0, 7, 7],
2360
[0, 8, 8], [0, 9, 9], [0, 10, 10], [0, 11, 11], [0, 12, 12], [0, 13, 13], [0, 14, 14],
2361
[0, 15, 15], [0, 16, 16], [0, 17, 17], [0, 18, 18], [0, 19, 19], [0, 20, 20], [0, 21, 21],
2362
[0, 22, 22], [0, 23, 23], [0, 24, 24], [0, 25, 25], [0, 26, 26], [0, 27, 27], [0, 28, 28],
2363
[0, 29, 29], [0, 30, 30], [0, 31, 31], [0, 32, 32], [0, 33, 33], [0, 34, 34], [0, 35, 35],
2364
[0, 36, 36], [0, 37, 37], [0, 38, 38], [0, 39, 39], [0, 40, 40], [0, 41, 41], [0, 42, 42],
2365
[0, 43, 43], [0, 44, 44], [0, 45, 45], [0, 46, 46], [0, 47, 47], [0, 48, 48], [0, 49, 49],
2366
[0, 50, 50],
2367
[1, 0, 51], [1, 1, 52], [1, 2, 53], [1, 3, 54], [1, 4, 55], [1, 5, 56], [1, 6, 57], [1, 7, 58],
2368
[1, 8, 59], [1, 9, 60], [1, 10, 61], [1, 11, 62], [1, 12, 63], [1, 13, 64], [1, 14, 65],
2369
[1, 15, 66], [1, 16, 67], [1, 17, 68], [1, 18, 69], [1, 19, 70], [1, 20, 71], [1, 21, 72],
2370
[1, 22, 73], [1, 23, 74], [1, 24, 75], [1, 25, 76], [1, 26, 77], [1, 27, 78], [1, 28, 79],
2371
[1, 29, 80], [1, 30, 81], [1, 31, 82], [1, 32, 83], [1, 33, 84], [1, 34, 85], [1, 35, 86],
2372
[1, 36, 87], [1, 37, 88], [1, 38, 89], [1, 39, 90], [1, 40, 91], [1, 41, 92], [1, 42, 93],
2373
[1, 43, 94], [1, 44, 95], [1, 45, 96], [1, 46, 97], [1, 47, 98], [1, 48, 99], [1, 49, 100],
2374
[1, 50, 101], [2, 0, 102], [2, 1, 103], [2, 2, 104], [2, 3, 105]
2375
]
2376
});
2377
});
2378
2379
test('issue #38123: editor.renderWhitespace: "boundary" renders whitespace at line wrap point when line is wrapped', () => {
2380
const actual = renderViewLine(new RenderLineInput(
2381
true,
2382
true,
2383
'This is a long line which never uses more than two spaces. ',
2384
true,
2385
true,
2386
false,
2387
0,
2388
createViewLineTokens([createPart(59, 3)]),
2389
[],
2390
4,
2391
0,
2392
10,
2393
10,
2394
10,
2395
10000,
2396
'boundary',
2397
false,
2398
false,
2399
null,
2400
null,
2401
14
2402
));
2403
2404
assert.deepStrictEqual(inflateRenderLineOutput(actual), {
2405
html: [
2406
'<span class="mtk3">This\u00a0is\u00a0a\u00a0long\u00a0line\u00a0which\u00a0never\u00a0uses\u00a0more\u00a0than\u00a0two</span>',
2407
'<span class="mtk3">\u00a0spaces.</span>',
2408
'<span class="mtk3">\u00a0</span>',
2409
],
2410
mapping: [
2411
[0, 0, 0], [0, 1, 1], [0, 2, 2], [0, 3, 3], [0, 4, 4], [0, 5, 5], [0, 6, 6], [0, 7, 7],
2412
[0, 8, 8], [0, 9, 9], [0, 10, 10], [0, 11, 11], [0, 12, 12], [0, 13, 13], [0, 14, 14],
2413
[0, 15, 15], [0, 16, 16], [0, 17, 17], [0, 18, 18], [0, 19, 19], [0, 20, 20], [0, 21, 21],
2414
[0, 22, 22], [0, 23, 23], [0, 24, 24], [0, 25, 25], [0, 26, 26], [0, 27, 27], [0, 28, 28],
2415
[0, 29, 29], [0, 30, 30], [0, 31, 31], [0, 32, 32], [0, 33, 33], [0, 34, 34], [0, 35, 35],
2416
[0, 36, 36], [0, 37, 37], [0, 38, 38], [0, 39, 39], [0, 40, 40], [0, 41, 41], [0, 42, 42],
2417
[0, 43, 43], [0, 44, 44], [0, 45, 45], [0, 46, 46], [0, 47, 47], [0, 48, 48], [0, 49, 49],
2418
[1, 0, 50], [1, 1, 51], [1, 2, 52], [1, 3, 53], [1, 4, 54], [1, 5, 55], [1, 6, 56], [1, 7, 57],
2419
[2, 0, 58], [2, 1, 59]
2420
]
2421
});
2422
});
2423
2424
test('issue #33525: Long line with ligatures takes a long time to paint decorations', () => {
2425
const actual = renderViewLine(new RenderLineInput(
2426
false,
2427
false,
2428
'append data to append data to append data to append data to append data to append data to append data to append data to append data to append data to append data to append data to append data to',
2429
false,
2430
true,
2431
false,
2432
0,
2433
createViewLineTokens([createPart(194, 3)]),
2434
[],
2435
4,
2436
0,
2437
10,
2438
10,
2439
10,
2440
10000,
2441
'none',
2442
false,
2443
true,
2444
null,
2445
null,
2446
14
2447
));
2448
2449
assert.deepStrictEqual(inflateRenderLineOutput(actual), {
2450
html: [
2451
'<span class="mtk3">append\u00a0data\u00a0to\u00a0append\u00a0data\u00a0to\u00a0append\u00a0data\u00a0to\u00a0</span>',
2452
'<span class="mtk3">append\u00a0data\u00a0to\u00a0append\u00a0data\u00a0to\u00a0append\u00a0data\u00a0to\u00a0</span>',
2453
'<span class="mtk3">append\u00a0data\u00a0to\u00a0append\u00a0data\u00a0to\u00a0append\u00a0data\u00a0to\u00a0</span>',
2454
'<span class="mtk3">append\u00a0data\u00a0to\u00a0append\u00a0data\u00a0to\u00a0append\u00a0data\u00a0to\u00a0</span>',
2455
'<span class="mtk3">append\u00a0data\u00a0to</span>',
2456
],
2457
mapping: [
2458
[0, 0, 0], [0, 1, 1], [0, 2, 2], [0, 3, 3], [0, 4, 4], [0, 5, 5], [0, 6, 6], [0, 7, 7],
2459
[0, 8, 8], [0, 9, 9], [0, 10, 10], [0, 11, 11], [0, 12, 12], [0, 13, 13], [0, 14, 14],
2460
[0, 15, 15], [0, 16, 16], [0, 17, 17], [0, 18, 18], [0, 19, 19], [0, 20, 20], [0, 21, 21],
2461
[0, 22, 22], [0, 23, 23], [0, 24, 24], [0, 25, 25], [0, 26, 26], [0, 27, 27], [0, 28, 28],
2462
[0, 29, 29], [0, 30, 30], [0, 31, 31], [0, 32, 32], [0, 33, 33], [0, 34, 34], [0, 35, 35],
2463
[0, 36, 36], [0, 37, 37], [0, 38, 38], [0, 39, 39], [0, 40, 40], [0, 41, 41], [0, 42, 42],
2464
[0, 43, 43], [0, 44, 44],
2465
[1, 0, 45], [1, 1, 46], [1, 2, 47], [1, 3, 48], [1, 4, 49], [1, 5, 50], [1, 6, 51],
2466
[1, 7, 52], [1, 8, 53], [1, 9, 54], [1, 10, 55], [1, 11, 56], [1, 12, 57], [1, 13, 58],
2467
[1, 14, 59], [1, 15, 60], [1, 16, 61], [1, 17, 62], [1, 18, 63], [1, 19, 64], [1, 20, 65],
2468
[1, 21, 66], [1, 22, 67], [1, 23, 68], [1, 24, 69], [1, 25, 70], [1, 26, 71], [1, 27, 72],
2469
[1, 28, 73], [1, 29, 74], [1, 30, 75], [1, 31, 76], [1, 32, 77], [1, 33, 78], [1, 34, 79],
2470
[1, 35, 80], [1, 36, 81], [1, 37, 82], [1, 38, 83], [1, 39, 84], [1, 40, 85], [1, 41, 86],
2471
[1, 42, 87], [1, 43, 88], [1, 44, 89],
2472
[2, 0, 90], [2, 1, 91], [2, 2, 92], [2, 3, 93], [2, 4, 94], [2, 5, 95], [2, 6, 96],
2473
[2, 7, 97], [2, 8, 98], [2, 9, 99], [2, 10, 100], [2, 11, 101], [2, 12, 102],
2474
[2, 13, 103], [2, 14, 104], [2, 15, 105], [2, 16, 106], [2, 17, 107], [2, 18, 108],
2475
[2, 19, 109], [2, 20, 110], [2, 21, 111], [2, 22, 112], [2, 23, 113], [2, 24, 114],
2476
[2, 25, 115], [2, 26, 116], [2, 27, 117], [2, 28, 118], [2, 29, 119], [2, 30, 120],
2477
[2, 31, 121], [2, 32, 122], [2, 33, 123], [2, 34, 124], [2, 35, 125], [2, 36, 126],
2478
[2, 37, 127], [2, 38, 128], [2, 39, 129], [2, 40, 130], [2, 41, 131], [2, 42, 132],
2479
[2, 43, 133], [2, 44, 134],
2480
[3, 0, 135], [3, 1, 136], [3, 2, 137], [3, 3, 138], [3, 4, 139], [3, 5, 140], [3, 6, 141],
2481
[3, 7, 142], [3, 8, 143], [3, 9, 144], [3, 10, 145], [3, 11, 146], [3, 12, 147], [3, 13, 148],
2482
[3, 14, 149], [3, 15, 150], [3, 16, 151], [3, 17, 152], [3, 18, 153], [3, 19, 154], [3, 20, 155],
2483
[3, 21, 156], [3, 22, 157], [3, 23, 158], [3, 24, 159], [3, 25, 160], [3, 26, 161], [3, 27, 162],
2484
[3, 28, 163], [3, 29, 164], [3, 30, 165], [3, 31, 166], [3, 32, 167], [3, 33, 168], [3, 34, 169],
2485
[3, 35, 170], [3, 36, 171], [3, 37, 172], [3, 38, 173], [3, 39, 174], [3, 40, 175], [3, 41, 176],
2486
[3, 42, 177], [3, 43, 178], [3, 44, 179],
2487
[4, 0, 180], [4, 1, 181], [4, 2, 182], [4, 3, 183], [4, 4, 184], [4, 5, 185], [4, 6, 186],
2488
[4, 7, 187], [4, 8, 188], [4, 9, 189], [4, 10, 190], [4, 11, 191], [4, 12, 192], [4, 13, 193],
2489
[4, 14, 194]
2490
]
2491
});
2492
});
2493
2494
test('issue #33525: Long line with ligatures takes a long time to paint decorations - not possible', () => {
2495
const actual = renderViewLine(new RenderLineInput(
2496
false,
2497
false,
2498
'appenddatatoappenddatatoappenddatatoappenddatatoappenddatatoappenddatatoappenddatatoappenddatatoappenddatatoappenddatatoappenddatatoappenddatatoappenddatato',
2499
false,
2500
true,
2501
false,
2502
0,
2503
createViewLineTokens([createPart(194, 3)]),
2504
[],
2505
4,
2506
0,
2507
10,
2508
10,
2509
10,
2510
10000,
2511
'none',
2512
false,
2513
true,
2514
null,
2515
null,
2516
14
2517
));
2518
2519
assert.deepStrictEqual(inflateRenderLineOutput(actual), {
2520
html: [
2521
'<span class="mtk3">appenddatatoappenddatatoappenddatatoappenddatatoappenddatatoappenddatatoappenddatatoappenddatatoappenddatatoappenddatatoappenddatatoappenddatatoappenddatato</span>',
2522
],
2523
mapping: [
2524
[0, 0, 0], [0, 1, 1], [0, 2, 2], [0, 3, 3], [0, 4, 4], [0, 5, 5], [0, 6, 6], [0, 7, 7],
2525
[0, 8, 8], [0, 9, 9], [0, 10, 10], [0, 11, 11], [0, 12, 12], [0, 13, 13], [0, 14, 14],
2526
[0, 15, 15], [0, 16, 16], [0, 17, 17], [0, 18, 18], [0, 19, 19], [0, 20, 20], [0, 21, 21],
2527
[0, 22, 22], [0, 23, 23], [0, 24, 24], [0, 25, 25], [0, 26, 26], [0, 27, 27], [0, 28, 28],
2528
[0, 29, 29], [0, 30, 30], [0, 31, 31], [0, 32, 32], [0, 33, 33], [0, 34, 34], [0, 35, 35],
2529
[0, 36, 36], [0, 37, 37], [0, 38, 38], [0, 39, 39], [0, 40, 40], [0, 41, 41], [0, 42, 42],
2530
[0, 43, 43], [0, 44, 44], [0, 45, 45], [0, 46, 46], [0, 47, 47], [0, 48, 48], [0, 49, 49],
2531
[0, 50, 50], [0, 51, 51], [0, 52, 52], [0, 53, 53], [0, 54, 54], [0, 55, 55], [0, 56, 56],
2532
[0, 57, 57], [0, 58, 58], [0, 59, 59], [0, 60, 60], [0, 61, 61], [0, 62, 62], [0, 63, 63],
2533
[0, 64, 64], [0, 65, 65], [0, 66, 66], [0, 67, 67], [0, 68, 68], [0, 69, 69], [0, 70, 70],
2534
[0, 71, 71], [0, 72, 72], [0, 73, 73], [0, 74, 74], [0, 75, 75], [0, 76, 76], [0, 77, 77],
2535
[0, 78, 78], [0, 79, 79], [0, 80, 80], [0, 81, 81], [0, 82, 82], [0, 83, 83], [0, 84, 84],
2536
[0, 85, 85], [0, 86, 86], [0, 87, 87], [0, 88, 88], [0, 89, 89], [0, 90, 90], [0, 91, 91],
2537
[0, 92, 92], [0, 93, 93], [0, 94, 94], [0, 95, 95], [0, 96, 96], [0, 97, 97], [0, 98, 98],
2538
[0, 99, 99], [0, 100, 100], [0, 101, 101], [0, 102, 102], [0, 103, 103], [0, 104, 104],
2539
[0, 105, 105], [0, 106, 106], [0, 107, 107], [0, 108, 108], [0, 109, 109], [0, 110, 110],
2540
[0, 111, 111], [0, 112, 112], [0, 113, 113], [0, 114, 114], [0, 115, 115], [0, 116, 116],
2541
[0, 117, 117], [0, 118, 118], [0, 119, 119], [0, 120, 120], [0, 121, 121], [0, 122, 122],
2542
[0, 123, 123], [0, 124, 124], [0, 125, 125], [0, 126, 126], [0, 127, 127], [0, 128, 128],
2543
[0, 129, 129], [0, 130, 130], [0, 131, 131], [0, 132, 132], [0, 133, 133], [0, 134, 134],
2544
[0, 135, 135], [0, 136, 136], [0, 137, 137], [0, 138, 138], [0, 139, 139], [0, 140, 140],
2545
[0, 141, 141], [0, 142, 142], [0, 143, 143], [0, 144, 144], [0, 145, 145], [0, 146, 146],
2546
[0, 147, 147], [0, 148, 148], [0, 149, 149], [0, 150, 150], [0, 151, 151], [0, 152, 152],
2547
[0, 153, 153], [0, 154, 154], [0, 155, 155], [0, 156, 156]
2548
]
2549
});
2550
});
2551
2552
test('issue #91936: Semantic token color highlighting fails on line with selected text', () => {
2553
const actual = renderViewLine(new RenderLineInput(
2554
false,
2555
true,
2556
' else if ($s = 08) then \'\\b\'',
2557
false,
2558
true,
2559
false,
2560
0,
2561
createViewLineTokens([
2562
createPart(20, 1),
2563
createPart(24, 15),
2564
createPart(25, 1),
2565
createPart(27, 15),
2566
createPart(28, 1),
2567
createPart(29, 1),
2568
createPart(29, 1),
2569
createPart(31, 16),
2570
createPart(32, 1),
2571
createPart(33, 1),
2572
createPart(34, 1),
2573
createPart(36, 6),
2574
createPart(36, 1),
2575
createPart(37, 1),
2576
createPart(38, 1),
2577
createPart(42, 15),
2578
createPart(43, 1),
2579
createPart(47, 11)
2580
]),
2581
[],
2582
4,
2583
0,
2584
10,
2585
11,
2586
11,
2587
10000,
2588
'selection',
2589
false,
2590
false,
2591
[new OffsetRange(0, 47)],
2592
null,
2593
14
2594
));
2595
2596
assert.deepStrictEqual(inflateRenderLineOutput(actual), {
2597
html: [
2598
'<span class="mtkz" style="width:10px">\u00b7\u200c</span>',
2599
'<span class="mtkz" style="width:10px">\u00b7\u200c</span>',
2600
'<span class="mtkz" style="width:10px">\u00b7\u200c</span>',
2601
'<span class="mtkz" style="width:10px">\u00b7\u200c</span>',
2602
'<span class="mtkz" style="width:10px">\u00b7\u200c</span>',
2603
'<span class="mtkz" style="width:10px">\u00b7\u200c</span>',
2604
'<span class="mtkz" style="width:10px">\u00b7\u200c</span>',
2605
'<span class="mtkz" style="width:10px">\u00b7\u200c</span>',
2606
'<span class="mtkz" style="width:10px">\u00b7\u200c</span>',
2607
'<span class="mtkz" style="width:10px">\u00b7\u200c</span>',
2608
'<span class="mtkz" style="width:10px">\u00b7\u200c</span>',
2609
'<span class="mtkz" style="width:10px">\u00b7\u200c</span>',
2610
'<span class="mtkz" style="width:10px">\u00b7\u200c</span>',
2611
'<span class="mtkz" style="width:10px">\u00b7\u200c</span>',
2612
'<span class="mtkz" style="width:10px">\u00b7\u200c</span>',
2613
'<span class="mtkz" style="width:10px">\u00b7\u200c</span>',
2614
'<span class="mtkz" style="width:10px">\u00b7\u200c</span>',
2615
'<span class="mtkz" style="width:10px">\u00b7\u200c</span>',
2616
'<span class="mtkz" style="width:10px">\u00b7\u200c</span>',
2617
'<span class="mtkz" style="width:10px">\u00b7\u200c</span>',
2618
'<span class="mtk15">else</span>',
2619
'<span class="mtkz" style="width:10px">\u00b7\u200c</span>',
2620
'<span class="mtk15">if</span>',
2621
'<span class="mtkz" style="width:10px">\u00b7\u200c</span>',
2622
'<span class="mtk1">(</span>',
2623
'<span class="mtk16">$s</span>',
2624
'<span class="mtkz" style="width:10px">\u00b7\u200c</span>',
2625
'<span class="mtk1">=</span>',
2626
'<span class="mtkz" style="width:10px">\u00b7\u200c</span>',
2627
'<span class="mtk6">08</span>',
2628
'<span class="mtk1">)</span>',
2629
'<span class="mtkz" style="width:10px">\u00b7\u200c</span>',
2630
'<span class="mtk15">then</span>',
2631
'<span class="mtkz" style="width:10px">\u00b7\u200c</span>',
2632
'<span class="mtk11">\'\\b\'</span>',
2633
],
2634
mapping: [
2635
[0, 0, 0],
2636
[1, 0, 1],
2637
[2, 0, 2],
2638
[3, 0, 3],
2639
[4, 0, 4],
2640
[5, 0, 5],
2641
[6, 0, 6],
2642
[7, 0, 7],
2643
[8, 0, 8],
2644
[9, 0, 9],
2645
[10, 0, 10],
2646
[11, 0, 11],
2647
[12, 0, 12],
2648
[13, 0, 13],
2649
[14, 0, 14],
2650
[15, 0, 15],
2651
[16, 0, 16],
2652
[17, 0, 17],
2653
[18, 0, 18],
2654
[19, 0, 19],
2655
[20, 0, 20], [20, 1, 21], [20, 2, 22], [20, 3, 23],
2656
[21, 0, 24],
2657
[22, 0, 25], [22, 1, 26],
2658
[23, 0, 27],
2659
[24, 0, 28],
2660
[25, 0, 29], [25, 1, 30],
2661
[26, 0, 31],
2662
[27, 0, 32],
2663
[28, 0, 33],
2664
[29, 0, 34], [29, 1, 35],
2665
[30, 0, 36],
2666
[31, 0, 37],
2667
[32, 0, 38], [32, 1, 39], [32, 2, 40], [32, 3, 41],
2668
[33, 0, 42],
2669
[34, 0, 43], [34, 1, 44], [34, 2, 45], [34, 3, 46], [34, 4, 47]
2670
]
2671
});
2672
});
2673
2674
test('issue #119416: Delete Control Character (U+007F / &#127;) displayed as space', () => {
2675
const actual = renderViewLine(new RenderLineInput(
2676
false,
2677
false,
2678
'[' + String.fromCharCode(127) + '] [' + String.fromCharCode(0) + ']',
2679
false,
2680
true,
2681
false,
2682
0,
2683
createViewLineTokens([createPart(7, 3)]),
2684
[],
2685
4,
2686
0,
2687
10,
2688
10,
2689
10,
2690
10000,
2691
'none',
2692
true,
2693
true,
2694
null,
2695
null,
2696
14
2697
));
2698
2699
assert.deepStrictEqual(inflateRenderLineOutput(actual), {
2700
html: [
2701
'<span class="mtk3">[\u2421]\u00a0[\u2400]</span>',
2702
],
2703
mapping: [
2704
[0, 0, 0], [0, 1, 1], [0, 2, 2], [0, 3, 3], [0, 4, 4], [0, 5, 5], [0, 6, 6], [0, 7, 7]
2705
]
2706
});
2707
});
2708
2709
test('issue #116939: Important control characters aren\'t rendered', () => {
2710
const actual = renderViewLine(new RenderLineInput(
2711
false,
2712
false,
2713
`transferBalance(5678,${String.fromCharCode(0x202E)}6776,4321${String.fromCharCode(0x202C)},"USD");`,
2714
false,
2715
false,
2716
false,
2717
0,
2718
createViewLineTokens([createPart(42, 3)]),
2719
[],
2720
4,
2721
0,
2722
10,
2723
10,
2724
10,
2725
10000,
2726
'none',
2727
true,
2728
false,
2729
null,
2730
null,
2731
14
2732
));
2733
2734
assert.deepStrictEqual(inflateRenderLineOutput(actual), {
2735
html: [
2736
'<span class="mtk3">transferBalance(5678,</span>',
2737
'<span class="mtkcontrol">[U+202E]</span>',
2738
'<span class="mtk3">6776,4321</span>',
2739
'<span class="mtkcontrol">[U+202C]</span>',
2740
'<span class="mtk3">,"USD");</span>',
2741
],
2742
mapping: [
2743
[0, 0, 0], [0, 1, 1], [0, 2, 2], [0, 3, 3], [0, 4, 4], [0, 5, 5], [0, 6, 6], [0, 7, 7],
2744
[0, 8, 8], [0, 9, 9], [0, 10, 10], [0, 11, 11], [0, 12, 12], [0, 13, 13], [0, 14, 14],
2745
[0, 15, 15], [0, 16, 16], [0, 17, 17], [0, 18, 18], [0, 19, 19], [0, 20, 20],
2746
[1, 0, 21],
2747
[2, 0, 29], [2, 1, 30], [2, 2, 31], [2, 3, 32], [2, 4, 33], [2, 5, 34], [2, 6, 35],
2748
[2, 7, 36], [2, 8, 37],
2749
[3, 0, 38],
2750
[4, 0, 46], [4, 1, 47], [4, 2, 48], [4, 3, 49], [4, 4, 50], [4, 5, 51], [4, 6, 52], [4, 7, 53], [4, 8, 54]
2751
]
2752
});
2753
});
2754
2755
test('issue #124038: Multiple end-of-line text decorations get merged', () => {
2756
const actual = renderViewLine(new RenderLineInput(
2757
true,
2758
false,
2759
' if',
2760
false,
2761
true,
2762
false,
2763
0,
2764
createViewLineTokens([createPart(4, 1), createPart(6, 2)]),
2765
[
2766
new LineDecoration(7, 7, 'ced-1-TextEditorDecorationType2-17c14d98-3 ced-1-TextEditorDecorationType2-3', InlineDecorationType.Before),
2767
new LineDecoration(7, 7, 'ced-1-TextEditorDecorationType2-17c14d98-4 ced-1-TextEditorDecorationType2-4', InlineDecorationType.After),
2768
new LineDecoration(7, 7, 'ced-ghost-text-1-4', InlineDecorationType.After),
2769
],
2770
4,
2771
0,
2772
10,
2773
10,
2774
10,
2775
10000,
2776
'all',
2777
false,
2778
false,
2779
null,
2780
null,
2781
14
2782
));
2783
2784
assert.deepStrictEqual(inflateRenderLineOutput(actual), {
2785
html: [
2786
'<span class="mtkw">\u00b7\u200c\u00b7\u200c\u00b7\u200c\u00b7\u200c</span>',
2787
'<span class="mtk2">if</span>',
2788
'<span class="ced-1-TextEditorDecorationType2-17c14d98-3 ced-1-TextEditorDecorationType2-3"></span>',
2789
'<span class="ced-1-TextEditorDecorationType2-17c14d98-4 ced-1-TextEditorDecorationType2-4"></span>',
2790
'<span class="ced-ghost-text-1-4"></span>',
2791
],
2792
mapping: [
2793
[0, 0, 0], [0, 2, 1], [0, 4, 2], [0, 6, 3],
2794
[1, 0, 4], [1, 1, 5],
2795
[3, 0, 6]
2796
]
2797
});
2798
});
2799
2800
function createTestGetColumnOfLinePartOffset(lineContent: string, tabSize: number, parts: TestLineToken[], expectedPartLengths: number[]): (partIndex: number, partLength: number, offset: number, expected: number) => void {
2801
const renderLineOutput = renderViewLine(new RenderLineInput(
2802
false,
2803
true,
2804
lineContent,
2805
false,
2806
true,
2807
false,
2808
0,
2809
createViewLineTokens(parts),
2810
[],
2811
tabSize,
2812
0,
2813
10,
2814
10,
2815
10,
2816
-1,
2817
'none',
2818
false,
2819
false,
2820
null,
2821
null,
2822
14
2823
));
2824
2825
return (partIndex: number, partLength: number, offset: number, expected: number) => {
2826
const actualColumn = renderLineOutput.characterMapping.getColumn(new DomPosition(partIndex, offset), partLength);
2827
assert.strictEqual(actualColumn, expected, 'getColumn for ' + partIndex + ', ' + offset);
2828
};
2829
}
2830
2831
test('getColumnOfLinePartOffset 1 - simple text', () => {
2832
const testGetColumnOfLinePartOffset = createTestGetColumnOfLinePartOffset(
2833
'hello world',
2834
4,
2835
[
2836
createPart(11, 1)
2837
],
2838
[11]
2839
);
2840
testGetColumnOfLinePartOffset(0, 11, 0, 1);
2841
testGetColumnOfLinePartOffset(0, 11, 1, 2);
2842
testGetColumnOfLinePartOffset(0, 11, 2, 3);
2843
testGetColumnOfLinePartOffset(0, 11, 3, 4);
2844
testGetColumnOfLinePartOffset(0, 11, 4, 5);
2845
testGetColumnOfLinePartOffset(0, 11, 5, 6);
2846
testGetColumnOfLinePartOffset(0, 11, 6, 7);
2847
testGetColumnOfLinePartOffset(0, 11, 7, 8);
2848
testGetColumnOfLinePartOffset(0, 11, 8, 9);
2849
testGetColumnOfLinePartOffset(0, 11, 9, 10);
2850
testGetColumnOfLinePartOffset(0, 11, 10, 11);
2851
testGetColumnOfLinePartOffset(0, 11, 11, 12);
2852
});
2853
2854
test('getColumnOfLinePartOffset 2 - regular JS', () => {
2855
const testGetColumnOfLinePartOffset = createTestGetColumnOfLinePartOffset(
2856
'var x = 3;',
2857
4,
2858
[
2859
createPart(3, 1),
2860
createPart(4, 2),
2861
createPart(5, 3),
2862
createPart(8, 4),
2863
createPart(9, 5),
2864
createPart(10, 6),
2865
],
2866
[3, 1, 1, 3, 1, 1]
2867
);
2868
testGetColumnOfLinePartOffset(0, 3, 0, 1);
2869
testGetColumnOfLinePartOffset(0, 3, 1, 2);
2870
testGetColumnOfLinePartOffset(0, 3, 2, 3);
2871
testGetColumnOfLinePartOffset(0, 3, 3, 4);
2872
testGetColumnOfLinePartOffset(1, 1, 0, 4);
2873
testGetColumnOfLinePartOffset(1, 1, 1, 5);
2874
testGetColumnOfLinePartOffset(2, 1, 0, 5);
2875
testGetColumnOfLinePartOffset(2, 1, 1, 6);
2876
testGetColumnOfLinePartOffset(3, 3, 0, 6);
2877
testGetColumnOfLinePartOffset(3, 3, 1, 7);
2878
testGetColumnOfLinePartOffset(3, 3, 2, 8);
2879
testGetColumnOfLinePartOffset(3, 3, 3, 9);
2880
testGetColumnOfLinePartOffset(4, 1, 0, 9);
2881
testGetColumnOfLinePartOffset(4, 1, 1, 10);
2882
testGetColumnOfLinePartOffset(5, 1, 0, 10);
2883
testGetColumnOfLinePartOffset(5, 1, 1, 11);
2884
});
2885
2886
test('getColumnOfLinePartOffset 3 - tab with tab size 6', () => {
2887
const testGetColumnOfLinePartOffset = createTestGetColumnOfLinePartOffset(
2888
'\t',
2889
6,
2890
[
2891
createPart(1, 1)
2892
],
2893
[6]
2894
);
2895
testGetColumnOfLinePartOffset(0, 6, 0, 1);
2896
testGetColumnOfLinePartOffset(0, 6, 1, 1);
2897
testGetColumnOfLinePartOffset(0, 6, 2, 1);
2898
testGetColumnOfLinePartOffset(0, 6, 3, 1);
2899
testGetColumnOfLinePartOffset(0, 6, 4, 2);
2900
testGetColumnOfLinePartOffset(0, 6, 5, 2);
2901
testGetColumnOfLinePartOffset(0, 6, 6, 2);
2902
});
2903
2904
test('getColumnOfLinePartOffset 4 - once indented line, tab size 4', () => {
2905
const testGetColumnOfLinePartOffset = createTestGetColumnOfLinePartOffset(
2906
'\tfunction',
2907
4,
2908
[
2909
createPart(1, 1),
2910
createPart(9, 2),
2911
],
2912
[4, 8]
2913
);
2914
testGetColumnOfLinePartOffset(0, 4, 0, 1);
2915
testGetColumnOfLinePartOffset(0, 4, 1, 1);
2916
testGetColumnOfLinePartOffset(0, 4, 2, 1);
2917
testGetColumnOfLinePartOffset(0, 4, 3, 2);
2918
testGetColumnOfLinePartOffset(0, 4, 4, 2);
2919
testGetColumnOfLinePartOffset(1, 8, 0, 2);
2920
testGetColumnOfLinePartOffset(1, 8, 1, 3);
2921
testGetColumnOfLinePartOffset(1, 8, 2, 4);
2922
testGetColumnOfLinePartOffset(1, 8, 3, 5);
2923
testGetColumnOfLinePartOffset(1, 8, 4, 6);
2924
testGetColumnOfLinePartOffset(1, 8, 5, 7);
2925
testGetColumnOfLinePartOffset(1, 8, 6, 8);
2926
testGetColumnOfLinePartOffset(1, 8, 7, 9);
2927
testGetColumnOfLinePartOffset(1, 8, 8, 10);
2928
});
2929
2930
test('getColumnOfLinePartOffset 5 - twice indented line, tab size 4', () => {
2931
const testGetColumnOfLinePartOffset = createTestGetColumnOfLinePartOffset(
2932
'\t\tfunction',
2933
4,
2934
[
2935
createPart(2, 1),
2936
createPart(10, 2),
2937
],
2938
[8, 8]
2939
);
2940
testGetColumnOfLinePartOffset(0, 8, 0, 1);
2941
testGetColumnOfLinePartOffset(0, 8, 1, 1);
2942
testGetColumnOfLinePartOffset(0, 8, 2, 1);
2943
testGetColumnOfLinePartOffset(0, 8, 3, 2);
2944
testGetColumnOfLinePartOffset(0, 8, 4, 2);
2945
testGetColumnOfLinePartOffset(0, 8, 5, 2);
2946
testGetColumnOfLinePartOffset(0, 8, 6, 2);
2947
testGetColumnOfLinePartOffset(0, 8, 7, 3);
2948
testGetColumnOfLinePartOffset(0, 8, 8, 3);
2949
testGetColumnOfLinePartOffset(1, 8, 0, 3);
2950
testGetColumnOfLinePartOffset(1, 8, 1, 4);
2951
testGetColumnOfLinePartOffset(1, 8, 2, 5);
2952
testGetColumnOfLinePartOffset(1, 8, 3, 6);
2953
testGetColumnOfLinePartOffset(1, 8, 4, 7);
2954
testGetColumnOfLinePartOffset(1, 8, 5, 8);
2955
testGetColumnOfLinePartOffset(1, 8, 6, 9);
2956
testGetColumnOfLinePartOffset(1, 8, 7, 10);
2957
testGetColumnOfLinePartOffset(1, 8, 8, 11);
2958
});
2959
});
2960
2961