Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/editor/test/common/model/textModel.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 { DisposableStore } from '../../../../base/common/lifecycle.js';
8
import { UTF8_BOM_CHARACTER } from '../../../../base/common/strings.js';
9
import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../base/test/common/utils.js';
10
import { Position } from '../../../common/core/position.js';
11
import { Range } from '../../../common/core/range.js';
12
import { PLAINTEXT_LANGUAGE_ID } from '../../../common/languages/modesRegistry.js';
13
import { EndOfLinePreference } from '../../../common/model.js';
14
import { TextModel, createTextBuffer } from '../../../common/model/textModel.js';
15
import { createModelServices, createTextModel } from '../testTextModel.js';
16
import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js';
17
18
function testGuessIndentation(defaultInsertSpaces: boolean, defaultTabSize: number, expectedInsertSpaces: boolean, expectedTabSize: number, text: string[], msg?: string): void {
19
const m = createTextModel(
20
text.join('\n'),
21
undefined,
22
{
23
tabSize: defaultTabSize,
24
insertSpaces: defaultInsertSpaces,
25
detectIndentation: true
26
}
27
);
28
const r = m.getOptions();
29
m.dispose();
30
31
assert.strictEqual(r.insertSpaces, expectedInsertSpaces, msg);
32
assert.strictEqual(r.tabSize, expectedTabSize, msg);
33
}
34
35
function assertGuess(expectedInsertSpaces: boolean | undefined, expectedTabSize: number | undefined | [number], text: string[], msg?: string): void {
36
if (typeof expectedInsertSpaces === 'undefined') {
37
// cannot guess insertSpaces
38
if (typeof expectedTabSize === 'undefined') {
39
// cannot guess tabSize
40
testGuessIndentation(true, 13370, true, 13370, text, msg);
41
testGuessIndentation(false, 13371, false, 13371, text, msg);
42
} else if (typeof expectedTabSize === 'number') {
43
// can guess tabSize
44
testGuessIndentation(true, 13370, true, expectedTabSize, text, msg);
45
testGuessIndentation(false, 13371, false, expectedTabSize, text, msg);
46
} else {
47
// can only guess tabSize when insertSpaces is true
48
testGuessIndentation(true, 13370, true, expectedTabSize[0], text, msg);
49
testGuessIndentation(false, 13371, false, 13371, text, msg);
50
}
51
} else {
52
// can guess insertSpaces
53
if (typeof expectedTabSize === 'undefined') {
54
// cannot guess tabSize
55
testGuessIndentation(true, 13370, expectedInsertSpaces, 13370, text, msg);
56
testGuessIndentation(false, 13371, expectedInsertSpaces, 13371, text, msg);
57
} else if (typeof expectedTabSize === 'number') {
58
// can guess tabSize
59
testGuessIndentation(true, 13370, expectedInsertSpaces, expectedTabSize, text, msg);
60
testGuessIndentation(false, 13371, expectedInsertSpaces, expectedTabSize, text, msg);
61
} else {
62
// can only guess tabSize when insertSpaces is true
63
if (expectedInsertSpaces === true) {
64
testGuessIndentation(true, 13370, expectedInsertSpaces, expectedTabSize[0], text, msg);
65
testGuessIndentation(false, 13371, expectedInsertSpaces, expectedTabSize[0], text, msg);
66
} else {
67
testGuessIndentation(true, 13370, expectedInsertSpaces, 13370, text, msg);
68
testGuessIndentation(false, 13371, expectedInsertSpaces, 13371, text, msg);
69
}
70
}
71
}
72
}
73
74
suite('TextModelData.fromString', () => {
75
76
ensureNoDisposablesAreLeakedInTestSuite();
77
78
interface ITextBufferData {
79
EOL: string;
80
lines: string[];
81
containsRTL: boolean;
82
isBasicASCII: boolean;
83
}
84
85
function testTextModelDataFromString(text: string, expected: ITextBufferData): void {
86
const { textBuffer, disposable } = createTextBuffer(text, TextModel.DEFAULT_CREATION_OPTIONS.defaultEOL);
87
const actual: ITextBufferData = {
88
EOL: textBuffer.getEOL(),
89
lines: textBuffer.getLinesContent(),
90
containsRTL: textBuffer.mightContainRTL(),
91
isBasicASCII: !textBuffer.mightContainNonBasicASCII()
92
};
93
assert.deepStrictEqual(actual, expected);
94
disposable.dispose();
95
}
96
97
test('one line text', () => {
98
testTextModelDataFromString('Hello world!',
99
{
100
EOL: '\n',
101
lines: [
102
'Hello world!'
103
],
104
containsRTL: false,
105
isBasicASCII: true
106
}
107
);
108
});
109
110
test('multiline text', () => {
111
testTextModelDataFromString('Hello,\r\ndear friend\nHow\rare\r\nyou?',
112
{
113
EOL: '\r\n',
114
lines: [
115
'Hello,',
116
'dear friend',
117
'How',
118
'are',
119
'you?'
120
],
121
containsRTL: false,
122
isBasicASCII: true
123
}
124
);
125
});
126
127
test('Non Basic ASCII 1', () => {
128
testTextModelDataFromString('Hello,\nZürich',
129
{
130
EOL: '\n',
131
lines: [
132
'Hello,',
133
'Zürich'
134
],
135
containsRTL: false,
136
isBasicASCII: false
137
}
138
);
139
});
140
141
test('containsRTL 1', () => {
142
testTextModelDataFromString('Hello,\nזוהי עובדה מבוססת שדעתו',
143
{
144
EOL: '\n',
145
lines: [
146
'Hello,',
147
'זוהי עובדה מבוססת שדעתו'
148
],
149
containsRTL: true,
150
isBasicASCII: false
151
}
152
);
153
});
154
155
test('containsRTL 2', () => {
156
testTextModelDataFromString('Hello,\nهناك حقيقة مثبتة منذ زمن طويل',
157
{
158
EOL: '\n',
159
lines: [
160
'Hello,',
161
'هناك حقيقة مثبتة منذ زمن طويل'
162
],
163
containsRTL: true,
164
isBasicASCII: false
165
}
166
);
167
});
168
169
});
170
171
suite('Editor Model - TextModel', () => {
172
173
ensureNoDisposablesAreLeakedInTestSuite();
174
175
test('TextModel does not use events internally', () => {
176
// Make sure that all model parts receive text model events explicitly
177
// to avoid that by any chance an outside listener receives events before
178
// the parts and thus are able to access the text model in an inconsistent state.
179
//
180
// We simply check that there are no listeners attached to text model
181
// after instantiation
182
const disposables = new DisposableStore();
183
const instantiationService: IInstantiationService = createModelServices(disposables);
184
const textModel = disposables.add(instantiationService.createInstance(TextModel, '', PLAINTEXT_LANGUAGE_ID, TextModel.DEFAULT_CREATION_OPTIONS, null));
185
assert.strictEqual(textModel._hasListeners(), false);
186
disposables.dispose();
187
});
188
189
test('getValueLengthInRange', () => {
190
191
let m = createTextModel('My First Line\r\nMy Second Line\r\nMy Third Line');
192
assert.strictEqual(m.getValueLengthInRange(new Range(1, 1, 1, 1)), ''.length);
193
assert.strictEqual(m.getValueLengthInRange(new Range(1, 1, 1, 2)), 'M'.length);
194
assert.strictEqual(m.getValueLengthInRange(new Range(1, 2, 1, 3)), 'y'.length);
195
assert.strictEqual(m.getValueLengthInRange(new Range(1, 1, 1, 14)), 'My First Line'.length);
196
assert.strictEqual(m.getValueLengthInRange(new Range(1, 1, 2, 1)), 'My First Line\r\n'.length);
197
assert.strictEqual(m.getValueLengthInRange(new Range(1, 2, 2, 1)), 'y First Line\r\n'.length);
198
assert.strictEqual(m.getValueLengthInRange(new Range(1, 2, 2, 2)), 'y First Line\r\nM'.length);
199
assert.strictEqual(m.getValueLengthInRange(new Range(1, 2, 2, 1000)), 'y First Line\r\nMy Second Line'.length);
200
assert.strictEqual(m.getValueLengthInRange(new Range(1, 2, 3, 1)), 'y First Line\r\nMy Second Line\r\n'.length);
201
assert.strictEqual(m.getValueLengthInRange(new Range(1, 2, 3, 1000)), 'y First Line\r\nMy Second Line\r\nMy Third Line'.length);
202
assert.strictEqual(m.getValueLengthInRange(new Range(1, 1, 1000, 1000)), 'My First Line\r\nMy Second Line\r\nMy Third Line'.length);
203
m.dispose();
204
205
m = createTextModel('My First Line\nMy Second Line\nMy Third Line');
206
assert.strictEqual(m.getValueLengthInRange(new Range(1, 1, 1, 1)), ''.length);
207
assert.strictEqual(m.getValueLengthInRange(new Range(1, 1, 1, 2)), 'M'.length);
208
assert.strictEqual(m.getValueLengthInRange(new Range(1, 2, 1, 3)), 'y'.length);
209
assert.strictEqual(m.getValueLengthInRange(new Range(1, 1, 1, 14)), 'My First Line'.length);
210
assert.strictEqual(m.getValueLengthInRange(new Range(1, 1, 2, 1)), 'My First Line\n'.length);
211
assert.strictEqual(m.getValueLengthInRange(new Range(1, 2, 2, 1)), 'y First Line\n'.length);
212
assert.strictEqual(m.getValueLengthInRange(new Range(1, 2, 2, 2)), 'y First Line\nM'.length);
213
assert.strictEqual(m.getValueLengthInRange(new Range(1, 2, 2, 1000)), 'y First Line\nMy Second Line'.length);
214
assert.strictEqual(m.getValueLengthInRange(new Range(1, 2, 3, 1)), 'y First Line\nMy Second Line\n'.length);
215
assert.strictEqual(m.getValueLengthInRange(new Range(1, 2, 3, 1000)), 'y First Line\nMy Second Line\nMy Third Line'.length);
216
assert.strictEqual(m.getValueLengthInRange(new Range(1, 1, 1000, 1000)), 'My First Line\nMy Second Line\nMy Third Line'.length);
217
m.dispose();
218
});
219
220
test('getValueLengthInRange different EOL', () => {
221
222
let m = createTextModel('My First Line\r\nMy Second Line\r\nMy Third Line');
223
assert.strictEqual(m.getValueLengthInRange(new Range(1, 1, 2, 1), EndOfLinePreference.TextDefined), 'My First Line\r\n'.length);
224
assert.strictEqual(m.getValueLengthInRange(new Range(1, 1, 2, 1), EndOfLinePreference.CRLF), 'My First Line\r\n'.length);
225
assert.strictEqual(m.getValueLengthInRange(new Range(1, 1, 2, 1), EndOfLinePreference.LF), 'My First Line\n'.length);
226
assert.strictEqual(m.getValueLengthInRange(new Range(1, 1, 1000, 1000), EndOfLinePreference.TextDefined), 'My First Line\r\nMy Second Line\r\nMy Third Line'.length);
227
assert.strictEqual(m.getValueLengthInRange(new Range(1, 1, 1000, 1000), EndOfLinePreference.CRLF), 'My First Line\r\nMy Second Line\r\nMy Third Line'.length);
228
assert.strictEqual(m.getValueLengthInRange(new Range(1, 1, 1000, 1000), EndOfLinePreference.LF), 'My First Line\nMy Second Line\nMy Third Line'.length);
229
m.dispose();
230
231
m = createTextModel('My First Line\nMy Second Line\nMy Third Line');
232
assert.strictEqual(m.getValueLengthInRange(new Range(1, 1, 2, 1), EndOfLinePreference.TextDefined), 'My First Line\n'.length);
233
assert.strictEqual(m.getValueLengthInRange(new Range(1, 1, 2, 1), EndOfLinePreference.LF), 'My First Line\n'.length);
234
assert.strictEqual(m.getValueLengthInRange(new Range(1, 1, 2, 1), EndOfLinePreference.CRLF), 'My First Line\r\n'.length);
235
assert.strictEqual(m.getValueLengthInRange(new Range(1, 1, 1000, 1000), EndOfLinePreference.TextDefined), 'My First Line\nMy Second Line\nMy Third Line'.length);
236
assert.strictEqual(m.getValueLengthInRange(new Range(1, 1, 1000, 1000), EndOfLinePreference.LF), 'My First Line\nMy Second Line\nMy Third Line'.length);
237
assert.strictEqual(m.getValueLengthInRange(new Range(1, 1, 1000, 1000), EndOfLinePreference.CRLF), 'My First Line\r\nMy Second Line\r\nMy Third Line'.length);
238
m.dispose();
239
});
240
241
test('guess indentation 1', () => {
242
243
assertGuess(undefined, undefined, [
244
'x',
245
'x',
246
'x',
247
'x',
248
'x',
249
'x',
250
'x'
251
], 'no clues');
252
253
assertGuess(false, undefined, [
254
'\tx',
255
'x',
256
'x',
257
'x',
258
'x',
259
'x',
260
'x'
261
], 'no spaces, 1xTAB');
262
263
assertGuess(true, 2, [
264
' x',
265
'x',
266
'x',
267
'x',
268
'x',
269
'x',
270
'x'
271
], '1x2');
272
273
assertGuess(false, undefined, [
274
'\tx',
275
'\tx',
276
'\tx',
277
'\tx',
278
'\tx',
279
'\tx',
280
'\tx'
281
], '7xTAB');
282
283
assertGuess(undefined, [2], [
284
'\tx',
285
' x',
286
'\tx',
287
' x',
288
'\tx',
289
' x',
290
'\tx',
291
' x',
292
], '4x2, 4xTAB');
293
assertGuess(false, undefined, [
294
'\tx',
295
' x',
296
'\tx',
297
' x',
298
'\tx',
299
' x',
300
'\tx',
301
' x'
302
], '4x1, 4xTAB');
303
assertGuess(false, undefined, [
304
'\tx',
305
'\tx',
306
' x',
307
'\tx',
308
' x',
309
'\tx',
310
' x',
311
'\tx',
312
' x',
313
], '4x2, 5xTAB');
314
assertGuess(false, undefined, [
315
'\tx',
316
'\tx',
317
'x',
318
'\tx',
319
'x',
320
'\tx',
321
'x',
322
'\tx',
323
' x',
324
], '1x2, 5xTAB');
325
assertGuess(false, undefined, [
326
'\tx',
327
'\tx',
328
'x',
329
'\tx',
330
'x',
331
'\tx',
332
'x',
333
'\tx',
334
' x',
335
], '1x4, 5xTAB');
336
assertGuess(false, undefined, [
337
'\tx',
338
'\tx',
339
'x',
340
'\tx',
341
'x',
342
'\tx',
343
' x',
344
'\tx',
345
' x',
346
], '1x2, 1x4, 5xTAB');
347
348
assertGuess(undefined, undefined, [
349
'x',
350
' x',
351
' x',
352
' x',
353
' x',
354
' x',
355
' x',
356
' x'
357
], '7x1 - 1 space is never guessed as an indentation');
358
assertGuess(true, undefined, [
359
'x',
360
' x',
361
' x',
362
' x',
363
' x',
364
' x',
365
' x',
366
' x'
367
], '1x10, 6x1');
368
assertGuess(undefined, undefined, [
369
'',
370
' ',
371
' ',
372
' ',
373
' ',
374
' ',
375
' ',
376
' ',
377
], 'whitespace lines don\'t count');
378
assertGuess(true, 3, [
379
'x',
380
' x',
381
' x',
382
' x',
383
'x',
384
' x',
385
' x',
386
' x',
387
'x',
388
' x',
389
' x',
390
' x',
391
], '6x3, 3x4');
392
assertGuess(true, 5, [
393
'x',
394
' x',
395
' x',
396
' x',
397
'x',
398
' x',
399
' x',
400
' x',
401
'x',
402
' x',
403
' x',
404
' x',
405
], '6x5, 3x4');
406
assertGuess(true, 7, [
407
'x',
408
' x',
409
' x',
410
' x',
411
'x',
412
' x',
413
' x',
414
' x',
415
'x',
416
' x',
417
' x',
418
' x',
419
], '6x7, 1x5, 2x4');
420
assertGuess(true, 2, [
421
'x',
422
' x',
423
' x',
424
' x',
425
' x',
426
'x',
427
' x',
428
' x',
429
' x',
430
' x',
431
], '8x2');
432
433
assertGuess(true, 2, [
434
'x',
435
' x',
436
' x',
437
'x',
438
' x',
439
' x',
440
'x',
441
' x',
442
' x',
443
'x',
444
' x',
445
' x',
446
], '8x2');
447
assertGuess(true, 2, [
448
'x',
449
' x',
450
' x',
451
'x',
452
' x',
453
' x',
454
'x',
455
' x',
456
' x',
457
'x',
458
' x',
459
' x',
460
], '4x2, 4x4');
461
assertGuess(true, 2, [
462
'x',
463
' x',
464
' x',
465
' x',
466
'x',
467
' x',
468
' x',
469
' x',
470
'x',
471
' x',
472
' x',
473
' x',
474
], '6x2, 3x4');
475
assertGuess(true, 2, [
476
'x',
477
' x',
478
' x',
479
' x',
480
' x',
481
'x',
482
' x',
483
' x',
484
' x',
485
' x',
486
], '4x2, 4x4');
487
assertGuess(true, 2, [
488
'x',
489
' x',
490
' x',
491
' x',
492
'x',
493
' x',
494
' x',
495
' x',
496
], '2x2, 4x4');
497
assertGuess(true, 4, [
498
'x',
499
' x',
500
' x',
501
'x',
502
' x',
503
' x',
504
'x',
505
' x',
506
' x',
507
'x',
508
' x',
509
' x',
510
], '8x4');
511
assertGuess(true, 2, [
512
'x',
513
' x',
514
' x',
515
' x',
516
' x',
517
'x',
518
' x',
519
' x',
520
' x',
521
' x',
522
], '2x2, 4x4, 2x6');
523
assertGuess(true, 2, [
524
'x',
525
' x',
526
' x',
527
' x',
528
' x',
529
' x',
530
' x',
531
], '1x2, 2x4, 2x6, 1x8');
532
assertGuess(true, 4, [
533
'x',
534
' x',
535
' x',
536
' x',
537
' x',
538
' x',
539
'x',
540
' x',
541
' x',
542
' x',
543
' x',
544
' x',
545
], '6x4, 2x5, 2x8');
546
assertGuess(true, 4, [
547
'x',
548
' x',
549
' x',
550
' x',
551
' x',
552
' x',
553
' x',
554
], '3x4, 1x5, 2x8');
555
assertGuess(true, 4, [
556
'x',
557
'x',
558
' x',
559
' x',
560
' x',
561
' x',
562
' x',
563
'x',
564
'x',
565
' x',
566
' x',
567
' x',
568
' x',
569
' x',
570
], '6x4, 2x5, 4x8');
571
assertGuess(true, 3, [
572
'x',
573
' x',
574
' x',
575
' x',
576
' x',
577
' x',
578
'x',
579
' x',
580
' x',
581
' x',
582
], '5x1, 2x0, 1x3, 2x4');
583
assertGuess(false, undefined, [
584
'\t x',
585
' \t x',
586
'\tx'
587
], 'mixed whitespace 1');
588
assertGuess(false, undefined, [
589
'\tx',
590
'\t x'
591
], 'mixed whitespace 2');
592
});
593
594
test('issue #44991: Wrong indentation size auto-detection', () => {
595
assertGuess(true, 4, [
596
'a = 10 # 0 space indent',
597
'b = 5 # 0 space indent',
598
'if a > 10: # 0 space indent',
599
' a += 1 # 4 space indent delta 4 spaces',
600
' if b > 5: # 4 space indent',
601
' b += 1 # 8 space indent delta 4 spaces',
602
' b += 1 # 8 space indent',
603
' b += 1 # 8 space indent',
604
'# comment line 1 # 0 space indent delta 8 spaces',
605
'# comment line 2 # 0 space indent',
606
'# comment line 3 # 0 space indent',
607
' b += 1 # 8 space indent delta 8 spaces',
608
' b += 1 # 8 space indent',
609
' b += 1 # 8 space indent',
610
]);
611
});
612
613
test('issue #55818: Broken indentation detection', () => {
614
assertGuess(true, 2, [
615
'',
616
'/* REQUIRE */',
617
'',
618
'const foo = require ( \'foo\' ),',
619
' bar = require ( \'bar\' );',
620
'',
621
'/* MY FN */',
622
'',
623
'function myFn () {',
624
'',
625
' const asd = 1,',
626
' dsa = 2;',
627
'',
628
' return bar ( foo ( asd ) );',
629
'',
630
'}',
631
'',
632
'/* EXPORT */',
633
'',
634
'module.exports = myFn;',
635
'',
636
]);
637
});
638
639
test('issue #70832: Broken indentation detection', () => {
640
assertGuess(false, undefined, [
641
'x',
642
'x',
643
'x',
644
'x',
645
' x',
646
' x',
647
' x',
648
' x',
649
' x',
650
' x',
651
' x',
652
' x',
653
' x',
654
' x',
655
'x',
656
]);
657
});
658
659
test('issue #62143: Broken indentation detection', () => {
660
// works before the fix
661
assertGuess(true, 2, [
662
'x',
663
'x',
664
' x',
665
' x'
666
]);
667
668
// works before the fix
669
assertGuess(true, 2, [
670
'x',
671
' - item2',
672
' - item3'
673
]);
674
675
// works before the fix
676
testGuessIndentation(true, 2, true, 2, [
677
'x x',
678
' x',
679
' x',
680
]);
681
682
// fails before the fix
683
// empty space inline breaks the indentation guess
684
testGuessIndentation(true, 2, true, 2, [
685
'x x',
686
' x',
687
' x',
688
' x'
689
]);
690
691
testGuessIndentation(true, 2, true, 2, [
692
'<!--test1.md -->',
693
'- item1',
694
' - item2',
695
' - item3'
696
]);
697
});
698
699
test('issue #84217: Broken indentation detection', () => {
700
assertGuess(true, 4, [
701
'def main():',
702
' print(\'hello\')',
703
]);
704
assertGuess(true, 4, [
705
'def main():',
706
' with open(\'foo\') as fp:',
707
' print(fp.read())',
708
]);
709
});
710
711
test('validatePosition', () => {
712
713
const m = createTextModel('line one\nline two');
714
715
assert.deepStrictEqual(m.validatePosition(new Position(0, 0)), new Position(1, 1));
716
assert.deepStrictEqual(m.validatePosition(new Position(0, 1)), new Position(1, 1));
717
718
assert.deepStrictEqual(m.validatePosition(new Position(1, 1)), new Position(1, 1));
719
assert.deepStrictEqual(m.validatePosition(new Position(1, 2)), new Position(1, 2));
720
assert.deepStrictEqual(m.validatePosition(new Position(1, 30)), new Position(1, 9));
721
722
assert.deepStrictEqual(m.validatePosition(new Position(2, 0)), new Position(2, 1));
723
assert.deepStrictEqual(m.validatePosition(new Position(2, 1)), new Position(2, 1));
724
assert.deepStrictEqual(m.validatePosition(new Position(2, 2)), new Position(2, 2));
725
assert.deepStrictEqual(m.validatePosition(new Position(2, 30)), new Position(2, 9));
726
727
assert.deepStrictEqual(m.validatePosition(new Position(3, 0)), new Position(2, 9));
728
assert.deepStrictEqual(m.validatePosition(new Position(3, 1)), new Position(2, 9));
729
assert.deepStrictEqual(m.validatePosition(new Position(3, 30)), new Position(2, 9));
730
731
assert.deepStrictEqual(m.validatePosition(new Position(30, 30)), new Position(2, 9));
732
733
assert.deepStrictEqual(m.validatePosition(new Position(-123.123, -0.5)), new Position(1, 1));
734
assert.deepStrictEqual(m.validatePosition(new Position(Number.MIN_VALUE, Number.MIN_VALUE)), new Position(1, 1));
735
736
assert.deepStrictEqual(m.validatePosition(new Position(Number.MAX_VALUE, Number.MAX_VALUE)), new Position(2, 9));
737
assert.deepStrictEqual(m.validatePosition(new Position(123.23, 47.5)), new Position(2, 9));
738
739
m.dispose();
740
});
741
742
test('validatePosition around high-low surrogate pairs 1', () => {
743
744
const m = createTextModel('a📚b');
745
746
assert.deepStrictEqual(m.validatePosition(new Position(0, 0)), new Position(1, 1));
747
assert.deepStrictEqual(m.validatePosition(new Position(0, 1)), new Position(1, 1));
748
assert.deepStrictEqual(m.validatePosition(new Position(0, 7)), new Position(1, 1));
749
750
assert.deepStrictEqual(m.validatePosition(new Position(1, 1)), new Position(1, 1));
751
assert.deepStrictEqual(m.validatePosition(new Position(1, 2)), new Position(1, 2));
752
assert.deepStrictEqual(m.validatePosition(new Position(1, 3)), new Position(1, 2));
753
assert.deepStrictEqual(m.validatePosition(new Position(1, 4)), new Position(1, 4));
754
assert.deepStrictEqual(m.validatePosition(new Position(1, 5)), new Position(1, 5));
755
assert.deepStrictEqual(m.validatePosition(new Position(1, 30)), new Position(1, 5));
756
757
assert.deepStrictEqual(m.validatePosition(new Position(2, 0)), new Position(1, 5));
758
assert.deepStrictEqual(m.validatePosition(new Position(2, 1)), new Position(1, 5));
759
assert.deepStrictEqual(m.validatePosition(new Position(2, 2)), new Position(1, 5));
760
assert.deepStrictEqual(m.validatePosition(new Position(2, 30)), new Position(1, 5));
761
762
assert.deepStrictEqual(m.validatePosition(new Position(-123.123, -0.5)), new Position(1, 1));
763
assert.deepStrictEqual(m.validatePosition(new Position(Number.MIN_VALUE, Number.MIN_VALUE)), new Position(1, 1));
764
765
assert.deepStrictEqual(m.validatePosition(new Position(Number.MAX_VALUE, Number.MAX_VALUE)), new Position(1, 5));
766
assert.deepStrictEqual(m.validatePosition(new Position(123.23, 47.5)), new Position(1, 5));
767
768
m.dispose();
769
});
770
771
test('validatePosition around high-low surrogate pairs 2', () => {
772
773
const m = createTextModel('a📚📚b');
774
775
assert.deepStrictEqual(m.validatePosition(new Position(1, 1)), new Position(1, 1));
776
assert.deepStrictEqual(m.validatePosition(new Position(1, 2)), new Position(1, 2));
777
assert.deepStrictEqual(m.validatePosition(new Position(1, 3)), new Position(1, 2));
778
assert.deepStrictEqual(m.validatePosition(new Position(1, 4)), new Position(1, 4));
779
assert.deepStrictEqual(m.validatePosition(new Position(1, 5)), new Position(1, 4));
780
assert.deepStrictEqual(m.validatePosition(new Position(1, 6)), new Position(1, 6));
781
assert.deepStrictEqual(m.validatePosition(new Position(1, 7)), new Position(1, 7));
782
783
m.dispose();
784
785
});
786
787
test('validatePosition handle NaN.', () => {
788
789
const m = createTextModel('line one\nline two');
790
791
assert.deepStrictEqual(m.validatePosition(new Position(NaN, 1)), new Position(1, 1));
792
assert.deepStrictEqual(m.validatePosition(new Position(1, NaN)), new Position(1, 1));
793
794
assert.deepStrictEqual(m.validatePosition(new Position(NaN, NaN)), new Position(1, 1));
795
assert.deepStrictEqual(m.validatePosition(new Position(2, NaN)), new Position(2, 1));
796
assert.deepStrictEqual(m.validatePosition(new Position(NaN, 3)), new Position(1, 3));
797
798
m.dispose();
799
});
800
801
test('issue #71480: validatePosition handle floats', () => {
802
const m = createTextModel('line one\nline two');
803
804
assert.deepStrictEqual(m.validatePosition(new Position(0.2, 1)), new Position(1, 1), 'a');
805
assert.deepStrictEqual(m.validatePosition(new Position(1.2, 1)), new Position(1, 1), 'b');
806
assert.deepStrictEqual(m.validatePosition(new Position(1.5, 2)), new Position(1, 2), 'c');
807
assert.deepStrictEqual(m.validatePosition(new Position(1.8, 3)), new Position(1, 3), 'd');
808
assert.deepStrictEqual(m.validatePosition(new Position(1, 0.3)), new Position(1, 1), 'e');
809
assert.deepStrictEqual(m.validatePosition(new Position(2, 0.8)), new Position(2, 1), 'f');
810
assert.deepStrictEqual(m.validatePosition(new Position(1, 1.2)), new Position(1, 1), 'g');
811
assert.deepStrictEqual(m.validatePosition(new Position(2, 1.5)), new Position(2, 1), 'h');
812
813
m.dispose();
814
});
815
816
test('issue #71480: validateRange handle floats', () => {
817
const m = createTextModel('line one\nline two');
818
819
assert.deepStrictEqual(m.validateRange(new Range(0.2, 1.5, 0.8, 2.5)), new Range(1, 1, 1, 1));
820
assert.deepStrictEqual(m.validateRange(new Range(1.2, 1.7, 1.8, 2.2)), new Range(1, 1, 1, 2));
821
822
m.dispose();
823
});
824
825
test('validateRange around high-low surrogate pairs 1', () => {
826
827
const m = createTextModel('a📚b');
828
829
assert.deepStrictEqual(m.validateRange(new Range(0, 0, 0, 1)), new Range(1, 1, 1, 1));
830
assert.deepStrictEqual(m.validateRange(new Range(0, 0, 0, 7)), new Range(1, 1, 1, 1));
831
832
assert.deepStrictEqual(m.validateRange(new Range(1, 1, 1, 1)), new Range(1, 1, 1, 1));
833
assert.deepStrictEqual(m.validateRange(new Range(1, 1, 1, 2)), new Range(1, 1, 1, 2));
834
assert.deepStrictEqual(m.validateRange(new Range(1, 1, 1, 3)), new Range(1, 1, 1, 4));
835
assert.deepStrictEqual(m.validateRange(new Range(1, 1, 1, 4)), new Range(1, 1, 1, 4));
836
assert.deepStrictEqual(m.validateRange(new Range(1, 1, 1, 5)), new Range(1, 1, 1, 5));
837
838
assert.deepStrictEqual(m.validateRange(new Range(1, 2, 1, 2)), new Range(1, 2, 1, 2));
839
assert.deepStrictEqual(m.validateRange(new Range(1, 2, 1, 3)), new Range(1, 2, 1, 4));
840
assert.deepStrictEqual(m.validateRange(new Range(1, 2, 1, 4)), new Range(1, 2, 1, 4));
841
assert.deepStrictEqual(m.validateRange(new Range(1, 2, 1, 5)), new Range(1, 2, 1, 5));
842
843
assert.deepStrictEqual(m.validateRange(new Range(1, 3, 1, 3)), new Range(1, 2, 1, 2));
844
assert.deepStrictEqual(m.validateRange(new Range(1, 3, 1, 4)), new Range(1, 2, 1, 4));
845
assert.deepStrictEqual(m.validateRange(new Range(1, 3, 1, 5)), new Range(1, 2, 1, 5));
846
847
assert.deepStrictEqual(m.validateRange(new Range(1, 4, 1, 4)), new Range(1, 4, 1, 4));
848
assert.deepStrictEqual(m.validateRange(new Range(1, 4, 1, 5)), new Range(1, 4, 1, 5));
849
850
assert.deepStrictEqual(m.validateRange(new Range(1, 5, 1, 5)), new Range(1, 5, 1, 5));
851
852
m.dispose();
853
});
854
855
test('validateRange around high-low surrogate pairs 2', () => {
856
857
const m = createTextModel('a📚📚b');
858
859
assert.deepStrictEqual(m.validateRange(new Range(0, 0, 0, 1)), new Range(1, 1, 1, 1));
860
assert.deepStrictEqual(m.validateRange(new Range(0, 0, 0, 7)), new Range(1, 1, 1, 1));
861
862
assert.deepStrictEqual(m.validateRange(new Range(1, 1, 1, 1)), new Range(1, 1, 1, 1));
863
assert.deepStrictEqual(m.validateRange(new Range(1, 1, 1, 2)), new Range(1, 1, 1, 2));
864
assert.deepStrictEqual(m.validateRange(new Range(1, 1, 1, 3)), new Range(1, 1, 1, 4));
865
assert.deepStrictEqual(m.validateRange(new Range(1, 1, 1, 4)), new Range(1, 1, 1, 4));
866
assert.deepStrictEqual(m.validateRange(new Range(1, 1, 1, 5)), new Range(1, 1, 1, 6));
867
assert.deepStrictEqual(m.validateRange(new Range(1, 1, 1, 6)), new Range(1, 1, 1, 6));
868
assert.deepStrictEqual(m.validateRange(new Range(1, 1, 1, 7)), new Range(1, 1, 1, 7));
869
870
assert.deepStrictEqual(m.validateRange(new Range(1, 2, 1, 2)), new Range(1, 2, 1, 2));
871
assert.deepStrictEqual(m.validateRange(new Range(1, 2, 1, 3)), new Range(1, 2, 1, 4));
872
assert.deepStrictEqual(m.validateRange(new Range(1, 2, 1, 4)), new Range(1, 2, 1, 4));
873
assert.deepStrictEqual(m.validateRange(new Range(1, 2, 1, 5)), new Range(1, 2, 1, 6));
874
assert.deepStrictEqual(m.validateRange(new Range(1, 2, 1, 6)), new Range(1, 2, 1, 6));
875
assert.deepStrictEqual(m.validateRange(new Range(1, 2, 1, 7)), new Range(1, 2, 1, 7));
876
877
assert.deepStrictEqual(m.validateRange(new Range(1, 3, 1, 3)), new Range(1, 2, 1, 2));
878
assert.deepStrictEqual(m.validateRange(new Range(1, 3, 1, 4)), new Range(1, 2, 1, 4));
879
assert.deepStrictEqual(m.validateRange(new Range(1, 3, 1, 5)), new Range(1, 2, 1, 6));
880
assert.deepStrictEqual(m.validateRange(new Range(1, 3, 1, 6)), new Range(1, 2, 1, 6));
881
assert.deepStrictEqual(m.validateRange(new Range(1, 3, 1, 7)), new Range(1, 2, 1, 7));
882
883
assert.deepStrictEqual(m.validateRange(new Range(1, 4, 1, 4)), new Range(1, 4, 1, 4));
884
assert.deepStrictEqual(m.validateRange(new Range(1, 4, 1, 5)), new Range(1, 4, 1, 6));
885
assert.deepStrictEqual(m.validateRange(new Range(1, 4, 1, 6)), new Range(1, 4, 1, 6));
886
assert.deepStrictEqual(m.validateRange(new Range(1, 4, 1, 7)), new Range(1, 4, 1, 7));
887
888
assert.deepStrictEqual(m.validateRange(new Range(1, 5, 1, 5)), new Range(1, 4, 1, 4));
889
assert.deepStrictEqual(m.validateRange(new Range(1, 5, 1, 6)), new Range(1, 4, 1, 6));
890
assert.deepStrictEqual(m.validateRange(new Range(1, 5, 1, 7)), new Range(1, 4, 1, 7));
891
892
assert.deepStrictEqual(m.validateRange(new Range(1, 6, 1, 6)), new Range(1, 6, 1, 6));
893
assert.deepStrictEqual(m.validateRange(new Range(1, 6, 1, 7)), new Range(1, 6, 1, 7));
894
895
assert.deepStrictEqual(m.validateRange(new Range(1, 7, 1, 7)), new Range(1, 7, 1, 7));
896
897
m.dispose();
898
});
899
900
test('modifyPosition', () => {
901
902
const m = createTextModel('line one\nline two');
903
assert.deepStrictEqual(m.modifyPosition(new Position(1, 1), 0), new Position(1, 1));
904
assert.deepStrictEqual(m.modifyPosition(new Position(0, 0), 0), new Position(1, 1));
905
assert.deepStrictEqual(m.modifyPosition(new Position(30, 1), 0), new Position(2, 9));
906
907
assert.deepStrictEqual(m.modifyPosition(new Position(1, 1), 17), new Position(2, 9));
908
assert.deepStrictEqual(m.modifyPosition(new Position(1, 1), 1), new Position(1, 2));
909
assert.deepStrictEqual(m.modifyPosition(new Position(1, 1), 3), new Position(1, 4));
910
assert.deepStrictEqual(m.modifyPosition(new Position(1, 2), 10), new Position(2, 3));
911
assert.deepStrictEqual(m.modifyPosition(new Position(1, 5), 13), new Position(2, 9));
912
assert.deepStrictEqual(m.modifyPosition(new Position(1, 2), 16), new Position(2, 9));
913
914
assert.deepStrictEqual(m.modifyPosition(new Position(2, 9), -17), new Position(1, 1));
915
assert.deepStrictEqual(m.modifyPosition(new Position(1, 2), -1), new Position(1, 1));
916
assert.deepStrictEqual(m.modifyPosition(new Position(1, 4), -3), new Position(1, 1));
917
assert.deepStrictEqual(m.modifyPosition(new Position(2, 3), -10), new Position(1, 2));
918
assert.deepStrictEqual(m.modifyPosition(new Position(2, 9), -13), new Position(1, 5));
919
assert.deepStrictEqual(m.modifyPosition(new Position(2, 9), -16), new Position(1, 2));
920
921
assert.deepStrictEqual(m.modifyPosition(new Position(1, 2), 17), new Position(2, 9));
922
assert.deepStrictEqual(m.modifyPosition(new Position(1, 2), 100), new Position(2, 9));
923
924
assert.deepStrictEqual(m.modifyPosition(new Position(1, 2), -2), new Position(1, 1));
925
assert.deepStrictEqual(m.modifyPosition(new Position(1, 2), -100), new Position(1, 1));
926
assert.deepStrictEqual(m.modifyPosition(new Position(2, 2), -100), new Position(1, 1));
927
assert.deepStrictEqual(m.modifyPosition(new Position(2, 9), -18), new Position(1, 1));
928
929
m.dispose();
930
});
931
932
test('normalizeIndentation 1', () => {
933
const model = createTextModel('',
934
undefined,
935
{
936
insertSpaces: false
937
}
938
);
939
940
assert.strictEqual(model.normalizeIndentation('\t'), '\t');
941
assert.strictEqual(model.normalizeIndentation(' '), '\t');
942
assert.strictEqual(model.normalizeIndentation(' '), ' ');
943
assert.strictEqual(model.normalizeIndentation(' '), ' ');
944
assert.strictEqual(model.normalizeIndentation(' '), ' ');
945
assert.strictEqual(model.normalizeIndentation(''), '');
946
assert.strictEqual(model.normalizeIndentation(' \t '), '\t\t');
947
assert.strictEqual(model.normalizeIndentation(' \t '), '\t ');
948
assert.strictEqual(model.normalizeIndentation(' \t '), '\t ');
949
assert.strictEqual(model.normalizeIndentation(' \t '), '\t ');
950
assert.strictEqual(model.normalizeIndentation(' \t'), '\t');
951
952
assert.strictEqual(model.normalizeIndentation('\ta'), '\ta');
953
assert.strictEqual(model.normalizeIndentation(' a'), '\ta');
954
assert.strictEqual(model.normalizeIndentation(' a'), ' a');
955
assert.strictEqual(model.normalizeIndentation(' a'), ' a');
956
assert.strictEqual(model.normalizeIndentation(' a'), ' a');
957
assert.strictEqual(model.normalizeIndentation('a'), 'a');
958
assert.strictEqual(model.normalizeIndentation(' \t a'), '\t\ta');
959
assert.strictEqual(model.normalizeIndentation(' \t a'), '\t a');
960
assert.strictEqual(model.normalizeIndentation(' \t a'), '\t a');
961
assert.strictEqual(model.normalizeIndentation(' \t a'), '\t a');
962
assert.strictEqual(model.normalizeIndentation(' \ta'), '\ta');
963
964
model.dispose();
965
});
966
967
test('normalizeIndentation 2', () => {
968
const model = createTextModel('');
969
970
assert.strictEqual(model.normalizeIndentation('\ta'), ' a');
971
assert.strictEqual(model.normalizeIndentation(' a'), ' a');
972
assert.strictEqual(model.normalizeIndentation(' a'), ' a');
973
assert.strictEqual(model.normalizeIndentation(' a'), ' a');
974
assert.strictEqual(model.normalizeIndentation(' a'), ' a');
975
assert.strictEqual(model.normalizeIndentation('a'), 'a');
976
assert.strictEqual(model.normalizeIndentation(' \t a'), ' a');
977
assert.strictEqual(model.normalizeIndentation(' \t a'), ' a');
978
assert.strictEqual(model.normalizeIndentation(' \t a'), ' a');
979
assert.strictEqual(model.normalizeIndentation(' \t a'), ' a');
980
assert.strictEqual(model.normalizeIndentation(' \ta'), ' a');
981
982
model.dispose();
983
});
984
985
test('getLineFirstNonWhitespaceColumn', () => {
986
const model = createTextModel([
987
'asd',
988
' asd',
989
'\tasd',
990
' asd',
991
'\t\tasd',
992
' ',
993
' ',
994
'\t',
995
'\t\t',
996
' \tasd',
997
'',
998
''
999
].join('\n'));
1000
1001
assert.strictEqual(model.getLineFirstNonWhitespaceColumn(1), 1, '1');
1002
assert.strictEqual(model.getLineFirstNonWhitespaceColumn(2), 2, '2');
1003
assert.strictEqual(model.getLineFirstNonWhitespaceColumn(3), 2, '3');
1004
assert.strictEqual(model.getLineFirstNonWhitespaceColumn(4), 3, '4');
1005
assert.strictEqual(model.getLineFirstNonWhitespaceColumn(5), 3, '5');
1006
assert.strictEqual(model.getLineFirstNonWhitespaceColumn(6), 0, '6');
1007
assert.strictEqual(model.getLineFirstNonWhitespaceColumn(7), 0, '7');
1008
assert.strictEqual(model.getLineFirstNonWhitespaceColumn(8), 0, '8');
1009
assert.strictEqual(model.getLineFirstNonWhitespaceColumn(9), 0, '9');
1010
assert.strictEqual(model.getLineFirstNonWhitespaceColumn(10), 4, '10');
1011
assert.strictEqual(model.getLineFirstNonWhitespaceColumn(11), 0, '11');
1012
assert.strictEqual(model.getLineFirstNonWhitespaceColumn(12), 0, '12');
1013
1014
model.dispose();
1015
});
1016
1017
test('getLineLastNonWhitespaceColumn', () => {
1018
const model = createTextModel([
1019
'asd',
1020
'asd ',
1021
'asd\t',
1022
'asd ',
1023
'asd\t\t',
1024
' ',
1025
' ',
1026
'\t',
1027
'\t\t',
1028
'asd \t',
1029
'',
1030
''
1031
].join('\n'));
1032
1033
assert.strictEqual(model.getLineLastNonWhitespaceColumn(1), 4, '1');
1034
assert.strictEqual(model.getLineLastNonWhitespaceColumn(2), 4, '2');
1035
assert.strictEqual(model.getLineLastNonWhitespaceColumn(3), 4, '3');
1036
assert.strictEqual(model.getLineLastNonWhitespaceColumn(4), 4, '4');
1037
assert.strictEqual(model.getLineLastNonWhitespaceColumn(5), 4, '5');
1038
assert.strictEqual(model.getLineLastNonWhitespaceColumn(6), 0, '6');
1039
assert.strictEqual(model.getLineLastNonWhitespaceColumn(7), 0, '7');
1040
assert.strictEqual(model.getLineLastNonWhitespaceColumn(8), 0, '8');
1041
assert.strictEqual(model.getLineLastNonWhitespaceColumn(9), 0, '9');
1042
assert.strictEqual(model.getLineLastNonWhitespaceColumn(10), 4, '10');
1043
assert.strictEqual(model.getLineLastNonWhitespaceColumn(11), 0, '11');
1044
assert.strictEqual(model.getLineLastNonWhitespaceColumn(12), 0, '12');
1045
1046
model.dispose();
1047
});
1048
1049
test('#50471. getValueInRange with invalid range', () => {
1050
const m = createTextModel('My First Line\r\nMy Second Line\r\nMy Third Line');
1051
assert.strictEqual(m.getValueInRange(new Range(1, NaN, 1, 3)), 'My');
1052
assert.strictEqual(m.getValueInRange(new Range(NaN, NaN, NaN, NaN)), '');
1053
m.dispose();
1054
});
1055
1056
test('issue #168836: updating tabSize should also update indentSize when indentSize is set to "tabSize"', () => {
1057
const m = createTextModel('some text', null, {
1058
tabSize: 2,
1059
indentSize: 'tabSize'
1060
});
1061
assert.strictEqual(m.getOptions().tabSize, 2);
1062
assert.strictEqual(m.getOptions().indentSize, 2);
1063
assert.strictEqual(m.getOptions().originalIndentSize, 'tabSize');
1064
m.updateOptions({
1065
tabSize: 4
1066
});
1067
assert.strictEqual(m.getOptions().tabSize, 4);
1068
assert.strictEqual(m.getOptions().indentSize, 4);
1069
assert.strictEqual(m.getOptions().originalIndentSize, 'tabSize');
1070
m.dispose();
1071
});
1072
});
1073
1074
suite('TextModel.mightContainRTL', () => {
1075
1076
ensureNoDisposablesAreLeakedInTestSuite();
1077
1078
test('nope', () => {
1079
const model = createTextModel('hello world!');
1080
assert.strictEqual(model.mightContainRTL(), false);
1081
model.dispose();
1082
});
1083
1084
test('yes', () => {
1085
const model = createTextModel('Hello,\nזוהי עובדה מבוססת שדעתו');
1086
assert.strictEqual(model.mightContainRTL(), true);
1087
model.dispose();
1088
});
1089
1090
test('setValue resets 1', () => {
1091
const model = createTextModel('hello world!');
1092
assert.strictEqual(model.mightContainRTL(), false);
1093
model.setValue('Hello,\nזוהי עובדה מבוססת שדעתו');
1094
assert.strictEqual(model.mightContainRTL(), true);
1095
model.dispose();
1096
});
1097
1098
test('setValue resets 2', () => {
1099
const model = createTextModel('Hello,\nهناك حقيقة مثبتة منذ زمن طويل');
1100
assert.strictEqual(model.mightContainRTL(), true);
1101
model.setValue('hello world!');
1102
assert.strictEqual(model.mightContainRTL(), false);
1103
model.dispose();
1104
});
1105
1106
});
1107
1108
suite('TextModel.createSnapshot', () => {
1109
1110
ensureNoDisposablesAreLeakedInTestSuite();
1111
1112
test('empty file', () => {
1113
const model = createTextModel('');
1114
const snapshot = model.createSnapshot();
1115
assert.strictEqual(snapshot.read(), null);
1116
model.dispose();
1117
});
1118
1119
test('file with BOM', () => {
1120
const model = createTextModel(UTF8_BOM_CHARACTER + 'Hello');
1121
assert.strictEqual(model.getLineContent(1), 'Hello');
1122
const snapshot = model.createSnapshot(true);
1123
assert.strictEqual(snapshot.read(), UTF8_BOM_CHARACTER + 'Hello');
1124
assert.strictEqual(snapshot.read(), null);
1125
model.dispose();
1126
});
1127
1128
test('regular file', () => {
1129
const model = createTextModel('My First Line\n\t\tMy Second Line\n Third Line\n\n1');
1130
const snapshot = model.createSnapshot();
1131
assert.strictEqual(snapshot.read(), 'My First Line\n\t\tMy Second Line\n Third Line\n\n1');
1132
assert.strictEqual(snapshot.read(), null);
1133
model.dispose();
1134
});
1135
1136
test('large file', () => {
1137
const lines: string[] = [];
1138
for (let i = 0; i < 1000; i++) {
1139
lines[i] = 'Just some text that is a bit long such that it can consume some memory';
1140
}
1141
const text = lines.join('\n');
1142
1143
const model = createTextModel(text);
1144
const snapshot = model.createSnapshot();
1145
let actual = '';
1146
1147
// 70999 length => at most 2 read calls are necessary
1148
const tmp1 = snapshot.read();
1149
assert.ok(tmp1);
1150
actual += tmp1;
1151
1152
const tmp2 = snapshot.read();
1153
if (tmp2 === null) {
1154
// all good
1155
} else {
1156
actual += tmp2;
1157
assert.strictEqual(snapshot.read(), null);
1158
}
1159
1160
assert.strictEqual(actual, text);
1161
1162
model.dispose();
1163
});
1164
1165
test('issue #119632: invalid range', () => {
1166
const model = createTextModel('hello world!');
1167
const actual = model._validateRangeRelaxedNoAllocations(new Range(<any>undefined, 0, <any>undefined, 1));
1168
assert.deepStrictEqual(actual, new Range(1, 1, 1, 1));
1169
model.dispose();
1170
});
1171
1172
});
1173
1174