Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/editor/contrib/linesOperations/test/browser/linesOperations.test.ts
4780 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
import assert from 'assert';
6
import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/test/common/utils.js';
7
import { CoreEditingCommands } from '../../../../browser/coreCommands.js';
8
import type { ICodeEditor } from '../../../../browser/editorBrowser.js';
9
import { EditorAction } from '../../../../browser/editorExtensions.js';
10
import { Position } from '../../../../common/core/position.js';
11
import { Selection } from '../../../../common/core/selection.js';
12
import { Handler } from '../../../../common/editorCommon.js';
13
import { ITextModel } from '../../../../common/model.js';
14
import { ViewModel } from '../../../../common/viewModel/viewModelImpl.js';
15
import { CamelCaseAction, PascalCaseAction, DeleteAllLeftAction, DeleteAllRightAction, DeleteDuplicateLinesAction, DeleteLinesAction, IndentLinesAction, InsertLineAfterAction, InsertLineBeforeAction, JoinLinesAction, KebabCaseAction, LowerCaseAction, SnakeCaseAction, SortLinesAscendingAction, SortLinesDescendingAction, TitleCaseAction, TransposeAction, UpperCaseAction, ReverseLinesAction } from '../../browser/linesOperations.js';
16
import { withTestCodeEditor } from '../../../../test/browser/testCodeEditor.js';
17
import { createTextModel } from '../../../../test/common/testTextModel.js';
18
19
function assertSelection(editor: ICodeEditor, expected: Selection | Selection[]): void {
20
if (!Array.isArray(expected)) {
21
expected = [expected];
22
}
23
assert.deepStrictEqual(editor.getSelections(), expected);
24
}
25
26
function executeAction(action: EditorAction, editor: ICodeEditor): void {
27
action.run(null!, editor, undefined);
28
}
29
30
suite('Editor Contrib - Line Operations', () => {
31
32
ensureNoDisposablesAreLeakedInTestSuite();
33
34
suite('SortLinesAscendingAction', () => {
35
test('should sort selected lines in ascending order', function () {
36
withTestCodeEditor(
37
[
38
'omicron',
39
'beta',
40
'alpha'
41
], {}, (editor) => {
42
const model = editor.getModel()!;
43
const sortLinesAscendingAction = new SortLinesAscendingAction();
44
45
editor.setSelection(new Selection(1, 1, 3, 5));
46
executeAction(sortLinesAscendingAction, editor);
47
assert.deepStrictEqual(model.getLinesContent(), [
48
'alpha',
49
'beta',
50
'omicron'
51
]);
52
assertSelection(editor, new Selection(1, 1, 3, 7));
53
});
54
});
55
56
test('should sort lines in ascending order', function () {
57
withTestCodeEditor(
58
[
59
'omicron',
60
'beta',
61
'alpha'
62
], {}, (editor) => {
63
const model = editor.getModel()!;
64
const sortLinesAscendingAction = new SortLinesAscendingAction();
65
66
executeAction(sortLinesAscendingAction, editor);
67
assert.deepStrictEqual(model.getLinesContent(), [
68
'alpha',
69
'beta',
70
'omicron'
71
]);
72
});
73
});
74
75
test('should sort multiple selections in ascending order', function () {
76
withTestCodeEditor(
77
[
78
'omicron',
79
'beta',
80
'alpha',
81
'',
82
'omicron',
83
'beta',
84
'alpha'
85
], {}, (editor) => {
86
const model = editor.getModel()!;
87
const sortLinesAscendingAction = new SortLinesAscendingAction();
88
89
editor.setSelections([new Selection(1, 1, 3, 5), new Selection(5, 1, 7, 5)]);
90
executeAction(sortLinesAscendingAction, editor);
91
assert.deepStrictEqual(model.getLinesContent(), [
92
'alpha',
93
'beta',
94
'omicron',
95
'',
96
'alpha',
97
'beta',
98
'omicron'
99
]);
100
const expectedSelections = [
101
new Selection(1, 1, 3, 7),
102
new Selection(5, 1, 7, 7)
103
];
104
editor.getSelections()!.forEach((actualSelection, index) => {
105
assert.deepStrictEqual(actualSelection.toString(), expectedSelections[index].toString());
106
});
107
});
108
});
109
110
test('applies to whole document when selection is single line', function () {
111
withTestCodeEditor(
112
[
113
'omicron',
114
'beta',
115
'alpha'
116
], {}, (editor) => {
117
const model = editor.getModel()!;
118
const sortLinesAscendingAction = new SortLinesAscendingAction();
119
120
editor.setSelection(new Selection(2, 1, 2, 4));
121
executeAction(sortLinesAscendingAction, editor);
122
assert.deepStrictEqual(model.getLinesContent(), [
123
'alpha',
124
'beta',
125
'omicron'
126
]);
127
});
128
});
129
});
130
131
suite('SortLinesDescendingAction', () => {
132
test('should sort selected lines in descending order', function () {
133
withTestCodeEditor(
134
[
135
'alpha',
136
'beta',
137
'omicron'
138
], {}, (editor) => {
139
const model = editor.getModel()!;
140
const sortLinesDescendingAction = new SortLinesDescendingAction();
141
142
editor.setSelection(new Selection(1, 1, 3, 7));
143
executeAction(sortLinesDescendingAction, editor);
144
assert.deepStrictEqual(model.getLinesContent(), [
145
'omicron',
146
'beta',
147
'alpha'
148
]);
149
assertSelection(editor, new Selection(1, 1, 3, 5));
150
});
151
});
152
153
test('should sort multiple selections in descending order', function () {
154
withTestCodeEditor(
155
[
156
'alpha',
157
'beta',
158
'omicron',
159
'',
160
'alpha',
161
'beta',
162
'omicron'
163
], {}, (editor) => {
164
const model = editor.getModel()!;
165
const sortLinesDescendingAction = new SortLinesDescendingAction();
166
167
editor.setSelections([new Selection(1, 1, 3, 7), new Selection(5, 1, 7, 7)]);
168
executeAction(sortLinesDescendingAction, editor);
169
assert.deepStrictEqual(model.getLinesContent(), [
170
'omicron',
171
'beta',
172
'alpha',
173
'',
174
'omicron',
175
'beta',
176
'alpha'
177
]);
178
const expectedSelections = [
179
new Selection(1, 1, 3, 5),
180
new Selection(5, 1, 7, 5)
181
];
182
editor.getSelections()!.forEach((actualSelection, index) => {
183
assert.deepStrictEqual(actualSelection.toString(), expectedSelections[index].toString());
184
});
185
});
186
});
187
});
188
189
suite('DeleteDuplicateLinesAction', () => {
190
test('should remove duplicate lines within selection', function () {
191
withTestCodeEditor(
192
[
193
'alpha',
194
'beta',
195
'beta',
196
'beta',
197
'alpha',
198
'omicron',
199
], {}, (editor) => {
200
const model = editor.getModel()!;
201
const deleteDuplicateLinesAction = new DeleteDuplicateLinesAction();
202
203
editor.setSelection(new Selection(1, 3, 6, 4));
204
executeAction(deleteDuplicateLinesAction, editor);
205
assert.deepStrictEqual(model.getLinesContent(), [
206
'alpha',
207
'beta',
208
'omicron',
209
]);
210
assertSelection(editor, new Selection(1, 1, 3, 8));
211
});
212
});
213
214
test('should remove duplicate lines', function () {
215
withTestCodeEditor(
216
[
217
'alpha',
218
'beta',
219
'beta',
220
'beta',
221
'alpha',
222
'omicron',
223
], {}, (editor) => {
224
const model = editor.getModel()!;
225
const deleteDuplicateLinesAction = new DeleteDuplicateLinesAction();
226
227
executeAction(deleteDuplicateLinesAction, editor);
228
assert.deepStrictEqual(model.getLinesContent(), [
229
'alpha',
230
'beta',
231
'omicron',
232
]);
233
assert.ok(editor.getSelection().isEmpty());
234
});
235
});
236
237
test('should remove duplicate lines in multiple selections', function () {
238
withTestCodeEditor(
239
[
240
'alpha',
241
'beta',
242
'beta',
243
'omicron',
244
'',
245
'alpha',
246
'alpha',
247
'beta'
248
], {}, (editor) => {
249
const model = editor.getModel()!;
250
const deleteDuplicateLinesAction = new DeleteDuplicateLinesAction();
251
252
editor.setSelections([new Selection(1, 2, 4, 3), new Selection(6, 2, 8, 3)]);
253
executeAction(deleteDuplicateLinesAction, editor);
254
assert.deepStrictEqual(model.getLinesContent(), [
255
'alpha',
256
'beta',
257
'omicron',
258
'',
259
'alpha',
260
'beta'
261
]);
262
const expectedSelections = [
263
new Selection(1, 1, 3, 8),
264
new Selection(5, 1, 6, 5)
265
];
266
editor.getSelections()!.forEach((actualSelection, index) => {
267
assert.deepStrictEqual(actualSelection.toString(), expectedSelections[index].toString());
268
});
269
});
270
});
271
272
test('applies to whole document when selection is single line', function () {
273
withTestCodeEditor(
274
[
275
'alpha',
276
'beta',
277
'alpha',
278
'omicron'
279
], {}, (editor) => {
280
const model = editor.getModel()!;
281
const deleteDuplicateLinesAction = new DeleteDuplicateLinesAction();
282
283
editor.setSelection(new Selection(2, 1, 2, 2));
284
executeAction(deleteDuplicateLinesAction, editor);
285
assert.deepStrictEqual(model.getLinesContent(), ['alpha', 'beta', 'omicron']);
286
});
287
});
288
});
289
290
291
suite('DeleteAllLeftAction', () => {
292
test('should delete to the left of the cursor', function () {
293
withTestCodeEditor(
294
[
295
'one',
296
'two',
297
'three'
298
], {}, (editor) => {
299
const model = editor.getModel()!;
300
const deleteAllLeftAction = new DeleteAllLeftAction();
301
302
editor.setSelection(new Selection(1, 2, 1, 2));
303
executeAction(deleteAllLeftAction, editor);
304
assert.strictEqual(model.getLineContent(1), 'ne');
305
306
editor.setSelections([new Selection(2, 2, 2, 2), new Selection(3, 2, 3, 2)]);
307
executeAction(deleteAllLeftAction, editor);
308
assert.strictEqual(model.getLineContent(2), 'wo');
309
assert.strictEqual(model.getLineContent(3), 'hree');
310
});
311
});
312
313
test('should jump to the previous line when on first column', function () {
314
withTestCodeEditor(
315
[
316
'one',
317
'two',
318
'three'
319
], {}, (editor) => {
320
const model = editor.getModel()!;
321
const deleteAllLeftAction = new DeleteAllLeftAction();
322
323
editor.setSelection(new Selection(2, 1, 2, 1));
324
executeAction(deleteAllLeftAction, editor);
325
assert.strictEqual(model.getLineContent(1), 'onetwo');
326
327
editor.setSelections([new Selection(1, 1, 1, 1), new Selection(2, 1, 2, 1)]);
328
executeAction(deleteAllLeftAction, editor);
329
assert.strictEqual(model.getLinesContent()[0], 'onetwothree');
330
assert.strictEqual(model.getLinesContent().length, 1);
331
332
editor.setSelection(new Selection(1, 1, 1, 1));
333
executeAction(deleteAllLeftAction, editor);
334
assert.strictEqual(model.getLinesContent()[0], 'onetwothree');
335
});
336
});
337
338
test('should keep deleting lines in multi cursor mode', function () {
339
withTestCodeEditor(
340
[
341
'hi my name is Carlos Matos',
342
'BCC',
343
'waso waso waso',
344
'my wife doesnt believe in me',
345
'nonononono',
346
'bitconneeeect'
347
], {}, (editor) => {
348
const model = editor.getModel()!;
349
const deleteAllLeftAction = new DeleteAllLeftAction();
350
351
const beforeSecondWasoSelection = new Selection(3, 5, 3, 5);
352
const endOfBCCSelection = new Selection(2, 4, 2, 4);
353
const endOfNonono = new Selection(5, 11, 5, 11);
354
355
editor.setSelections([beforeSecondWasoSelection, endOfBCCSelection, endOfNonono]);
356
357
executeAction(deleteAllLeftAction, editor);
358
let selections = editor.getSelections()!;
359
360
assert.strictEqual(model.getLineContent(2), '');
361
assert.strictEqual(model.getLineContent(3), ' waso waso');
362
assert.strictEqual(model.getLineContent(5), '');
363
364
assert.deepStrictEqual([
365
selections[0].startLineNumber,
366
selections[0].startColumn,
367
selections[0].endLineNumber,
368
selections[0].endColumn
369
], [3, 1, 3, 1]);
370
371
assert.deepStrictEqual([
372
selections[1].startLineNumber,
373
selections[1].startColumn,
374
selections[1].endLineNumber,
375
selections[1].endColumn
376
], [2, 1, 2, 1]);
377
378
assert.deepStrictEqual([
379
selections[2].startLineNumber,
380
selections[2].startColumn,
381
selections[2].endLineNumber,
382
selections[2].endColumn
383
], [5, 1, 5, 1]);
384
385
executeAction(deleteAllLeftAction, editor);
386
selections = editor.getSelections()!;
387
388
assert.strictEqual(model.getLineContent(1), 'hi my name is Carlos Matos waso waso');
389
assert.strictEqual(selections.length, 2);
390
391
assert.deepStrictEqual([
392
selections[0].startLineNumber,
393
selections[0].startColumn,
394
selections[0].endLineNumber,
395
selections[0].endColumn
396
], [1, 27, 1, 27]);
397
398
assert.deepStrictEqual([
399
selections[1].startLineNumber,
400
selections[1].startColumn,
401
selections[1].endLineNumber,
402
selections[1].endColumn
403
], [2, 29, 2, 29]);
404
});
405
});
406
407
test('should work in multi cursor mode', function () {
408
withTestCodeEditor(
409
[
410
'hello',
411
'world',
412
'hello world',
413
'hello',
414
'bonjour',
415
'hola',
416
'world',
417
'hello world',
418
], {}, (editor) => {
419
const model = editor.getModel()!;
420
const deleteAllLeftAction = new DeleteAllLeftAction();
421
422
editor.setSelections([new Selection(1, 2, 1, 2), new Selection(1, 4, 1, 4)]);
423
executeAction(deleteAllLeftAction, editor);
424
assert.strictEqual(model.getLineContent(1), 'lo');
425
426
editor.setSelections([new Selection(2, 2, 2, 2), new Selection(2, 4, 2, 5)]);
427
executeAction(deleteAllLeftAction, editor);
428
assert.strictEqual(model.getLineContent(2), 'd');
429
430
editor.setSelections([new Selection(3, 2, 3, 5), new Selection(3, 7, 3, 7)]);
431
executeAction(deleteAllLeftAction, editor);
432
assert.strictEqual(model.getLineContent(3), 'world');
433
434
editor.setSelections([new Selection(4, 3, 4, 3), new Selection(4, 5, 5, 4)]);
435
executeAction(deleteAllLeftAction, editor);
436
assert.strictEqual(model.getLineContent(4), 'jour');
437
438
editor.setSelections([new Selection(5, 3, 6, 3), new Selection(6, 5, 7, 5), new Selection(7, 7, 7, 7)]);
439
executeAction(deleteAllLeftAction, editor);
440
assert.strictEqual(model.getLineContent(5), 'world');
441
});
442
});
443
444
test('issue #36234: should push undo stop', () => {
445
withTestCodeEditor(
446
[
447
'one',
448
'two',
449
'three'
450
], {}, (editor) => {
451
const model = editor.getModel()!;
452
const deleteAllLeftAction = new DeleteAllLeftAction();
453
454
editor.setSelection(new Selection(1, 1, 1, 1));
455
456
editor.trigger('keyboard', Handler.Type, { text: 'Typing some text here on line ' });
457
assert.strictEqual(model.getLineContent(1), 'Typing some text here on line one');
458
assert.deepStrictEqual(editor.getSelection(), new Selection(1, 31, 1, 31));
459
460
executeAction(deleteAllLeftAction, editor);
461
assert.strictEqual(model.getLineContent(1), 'one');
462
assert.deepStrictEqual(editor.getSelection(), new Selection(1, 1, 1, 1));
463
464
editor.runCommand(CoreEditingCommands.Undo, null);
465
assert.strictEqual(model.getLineContent(1), 'Typing some text here on line one');
466
assert.deepStrictEqual(editor.getSelection(), new Selection(1, 31, 1, 31));
467
});
468
});
469
});
470
471
suite('JoinLinesAction', () => {
472
test('should join lines and insert space if necessary', function () {
473
withTestCodeEditor(
474
[
475
'hello',
476
'world',
477
'hello ',
478
'world',
479
'hello ',
480
' world',
481
'hello ',
482
' world',
483
'',
484
'',
485
'hello world'
486
], {}, (editor) => {
487
const model = editor.getModel()!;
488
const joinLinesAction = new JoinLinesAction();
489
490
editor.setSelection(new Selection(1, 2, 1, 2));
491
executeAction(joinLinesAction, editor);
492
assert.strictEqual(model.getLineContent(1), 'hello world');
493
assertSelection(editor, new Selection(1, 6, 1, 6));
494
495
editor.setSelection(new Selection(2, 2, 2, 2));
496
executeAction(joinLinesAction, editor);
497
assert.strictEqual(model.getLineContent(2), 'hello world');
498
assertSelection(editor, new Selection(2, 7, 2, 7));
499
500
editor.setSelection(new Selection(3, 2, 3, 2));
501
executeAction(joinLinesAction, editor);
502
assert.strictEqual(model.getLineContent(3), 'hello world');
503
assertSelection(editor, new Selection(3, 7, 3, 7));
504
505
editor.setSelection(new Selection(4, 2, 5, 3));
506
executeAction(joinLinesAction, editor);
507
assert.strictEqual(model.getLineContent(4), 'hello world');
508
assertSelection(editor, new Selection(4, 2, 4, 8));
509
510
editor.setSelection(new Selection(5, 1, 7, 3));
511
executeAction(joinLinesAction, editor);
512
assert.strictEqual(model.getLineContent(5), 'hello world');
513
assertSelection(editor, new Selection(5, 1, 5, 3));
514
});
515
});
516
517
test('#50471 Join lines at the end of document', function () {
518
withTestCodeEditor(
519
[
520
'hello',
521
'world'
522
], {}, (editor) => {
523
const model = editor.getModel()!;
524
const joinLinesAction = new JoinLinesAction();
525
526
editor.setSelection(new Selection(2, 1, 2, 1));
527
executeAction(joinLinesAction, editor);
528
assert.strictEqual(model.getLineContent(1), 'hello');
529
assert.strictEqual(model.getLineContent(2), 'world');
530
assertSelection(editor, new Selection(2, 6, 2, 6));
531
});
532
});
533
534
test('should work in multi cursor mode', function () {
535
withTestCodeEditor(
536
[
537
'hello',
538
'world',
539
'hello ',
540
'world',
541
'hello ',
542
' world',
543
'hello ',
544
' world',
545
'',
546
'',
547
'hello world'
548
], {}, (editor) => {
549
const model = editor.getModel()!;
550
const joinLinesAction = new JoinLinesAction();
551
552
editor.setSelections([
553
/** primary cursor */
554
new Selection(5, 2, 5, 2),
555
new Selection(1, 2, 1, 2),
556
new Selection(3, 2, 4, 2),
557
new Selection(5, 4, 6, 3),
558
new Selection(7, 5, 8, 4),
559
new Selection(10, 1, 10, 1)
560
]);
561
562
executeAction(joinLinesAction, editor);
563
assert.strictEqual(model.getLinesContent().join('\n'), 'hello world\nhello world\nhello world\nhello world\n\nhello world');
564
assertSelection(editor, [
565
/** primary cursor */
566
new Selection(3, 4, 3, 8),
567
new Selection(1, 6, 1, 6),
568
new Selection(2, 2, 2, 8),
569
new Selection(4, 5, 4, 9),
570
new Selection(6, 1, 6, 1)
571
]);
572
});
573
});
574
575
test('should push undo stop', function () {
576
withTestCodeEditor(
577
[
578
'hello',
579
'world'
580
], {}, (editor) => {
581
const model = editor.getModel()!;
582
const joinLinesAction = new JoinLinesAction();
583
584
editor.setSelection(new Selection(1, 6, 1, 6));
585
586
editor.trigger('keyboard', Handler.Type, { text: ' my dear' });
587
assert.strictEqual(model.getLineContent(1), 'hello my dear');
588
assert.deepStrictEqual(editor.getSelection(), new Selection(1, 14, 1, 14));
589
590
executeAction(joinLinesAction, editor);
591
assert.strictEqual(model.getLineContent(1), 'hello my dear world');
592
assert.deepStrictEqual(editor.getSelection(), new Selection(1, 14, 1, 14));
593
594
editor.runCommand(CoreEditingCommands.Undo, null);
595
assert.strictEqual(model.getLineContent(1), 'hello my dear');
596
assert.deepStrictEqual(editor.getSelection(), new Selection(1, 14, 1, 14));
597
});
598
});
599
});
600
601
suite('ReverseLinesAction', () => {
602
test('reverses lines', function () {
603
withTestCodeEditor(
604
[
605
'alice',
606
'bob',
607
'charlie',
608
], {}, (editor) => {
609
const model = editor.getModel()!;
610
const reverseLinesAction = new ReverseLinesAction();
611
612
executeAction(reverseLinesAction, editor);
613
assert.deepStrictEqual(model.getLinesContent(), ['charlie', 'bob', 'alice']);
614
});
615
});
616
617
test('excludes empty last line', function () {
618
withTestCodeEditor(
619
[
620
'alice',
621
'bob',
622
'charlie',
623
'',
624
], {}, (editor) => {
625
const model = editor.getModel()!;
626
const reverseLinesAction = new ReverseLinesAction();
627
628
executeAction(reverseLinesAction, editor);
629
assert.deepStrictEqual(model.getLinesContent(), ['charlie', 'bob', 'alice', '']);
630
});
631
});
632
633
test('updates cursor', function () {
634
withTestCodeEditor(
635
[
636
'alice',
637
'bob',
638
'charlie',
639
], {}, (editor) => {
640
const reverseLinesAction = new ReverseLinesAction();
641
// cursor at third column of third line 'charlie'
642
editor.setPosition(new Position(3, 3));
643
644
executeAction(reverseLinesAction, editor);
645
// cursor at third column of *first* line 'charlie'
646
assert.deepStrictEqual(editor.getPosition(), new Position(1, 3));
647
});
648
});
649
650
test('preserves cursor on empty last line', function () {
651
withTestCodeEditor(
652
[
653
'alice',
654
'bob',
655
'charlie',
656
'',
657
], {}, (editor) => {
658
const reverseLinesAction = new ReverseLinesAction();
659
editor.setPosition(new Position(4, 1));
660
661
executeAction(reverseLinesAction, editor);
662
assert.deepStrictEqual(editor.getPosition(), new Position(4, 1));
663
});
664
});
665
666
test('preserves selected text when selections do not span lines', function () {
667
withTestCodeEditor(
668
[
669
'alice',
670
'bob',
671
'charlie',
672
'',
673
], {}, (editor) => {
674
const model = editor.getModel()!;
675
const reverseLinesAction = new ReverseLinesAction();
676
editor.setSelections([new Selection(1, 1, 1, 3), new Selection(2, 1, 2, 4), new Selection(3, 1, 3, 5)]);
677
const expectedSelectedText: string[] = ['al', 'bob', 'char'];
678
assert.deepStrictEqual(editor.getSelections().map(s => model.getValueInRange(s)), expectedSelectedText);
679
680
executeAction(reverseLinesAction, editor);
681
assert.deepStrictEqual(editor.getSelections().map(s => model.getValueInRange(s)), expectedSelectedText);
682
});
683
});
684
685
test('reverses lines within selection', function () {
686
withTestCodeEditor(
687
[
688
'line1',
689
'line2',
690
'line3',
691
'line4',
692
'line5',
693
], {}, (editor) => {
694
const model = editor.getModel()!;
695
const reverseLinesAction = new ReverseLinesAction();
696
697
// Select lines 2-4
698
editor.setSelection(new Selection(2, 1, 4, 6));
699
executeAction(reverseLinesAction, editor);
700
assert.deepStrictEqual(model.getLinesContent(), ['line1', 'line4', 'line3', 'line2', 'line5']);
701
});
702
});
703
704
test('reverses lines within partial selection', function () {
705
withTestCodeEditor(
706
[
707
'line1',
708
'line2',
709
'line3',
710
'line4',
711
'line5',
712
], {}, (editor) => {
713
const model = editor.getModel()!;
714
const reverseLinesAction = new ReverseLinesAction();
715
716
// Select partial lines 2-4 (from middle of line2 to middle of line4)
717
editor.setSelection(new Selection(2, 3, 4, 3));
718
executeAction(reverseLinesAction, editor);
719
assert.deepStrictEqual(model.getLinesContent(), ['line1', 'line4', 'line3', 'line2', 'line5']);
720
});
721
});
722
723
test('reverses lines with multiple selections', function () {
724
withTestCodeEditor(
725
[
726
'line1',
727
'line2',
728
'line3',
729
'line4',
730
'line5',
731
'line6',
732
], {}, (editor) => {
733
const model = editor.getModel()!;
734
const reverseLinesAction = new ReverseLinesAction();
735
736
// Select lines 1-2 and lines 4-5
737
editor.setSelections([new Selection(1, 1, 2, 6), new Selection(4, 1, 5, 6)]);
738
executeAction(reverseLinesAction, editor);
739
assert.deepStrictEqual(model.getLinesContent(), ['line2', 'line1', 'line3', 'line5', 'line4', 'line6']);
740
});
741
});
742
743
test('updates selection positions after reversal', function () {
744
withTestCodeEditor(
745
[
746
'line1',
747
'line2',
748
'line3',
749
'line4',
750
], {}, (editor) => {
751
const reverseLinesAction = new ReverseLinesAction();
752
753
// Select lines 1-3
754
editor.setSelection(new Selection(1, 2, 3, 3));
755
executeAction(reverseLinesAction, editor);
756
757
// After reversal, selection should be updated to maintain relative position
758
// Originally line 1 col 2 -> line 3 col 3, so after reversal should be line 3 col 2 -> line 1 col 3
759
const selection = editor.getSelection()!;
760
// The selection should cover the same logical text after reversal
761
// Range normalization ensures startLineNumber <= endLineNumber
762
assert.strictEqual(selection.startLineNumber, 1);
763
assert.strictEqual(selection.startColumn, 3);
764
assert.strictEqual(selection.endLineNumber, 3);
765
assert.strictEqual(selection.endColumn, 2);
766
});
767
});
768
769
test('applies to whole document when selection is single line', function () {
770
withTestCodeEditor(
771
[
772
'line1',
773
'line2',
774
'line3',
775
], {}, (editor) => {
776
const model = editor.getModel()!;
777
const reverseLinesAction = new ReverseLinesAction();
778
779
// Select only line 2
780
editor.setSelection(new Selection(2, 1, 2, 6));
781
executeAction(reverseLinesAction, editor);
782
assert.deepStrictEqual(model.getLinesContent(), ['line3', 'line2', 'line1']);
783
});
784
});
785
786
test('excludes end line when selection ends at column 1', function () {
787
withTestCodeEditor(
788
[
789
'line1',
790
'line2',
791
'line3',
792
'line4',
793
'line5',
794
], {}, (editor) => {
795
const model = editor.getModel()!;
796
const reverseLinesAction = new ReverseLinesAction();
797
798
// Select from line 2 to line 4 column 1 (should exclude line 4)
799
editor.setSelection(new Selection(2, 1, 4, 1));
800
executeAction(reverseLinesAction, editor);
801
assert.deepStrictEqual(model.getLinesContent(), ['line1', 'line3', 'line2', 'line4', 'line5']);
802
});
803
});
804
805
test('applies to whole document when selection is single line', function () {
806
withTestCodeEditor(
807
[
808
'omicron',
809
'beta',
810
'alpha'
811
], {}, (editor) => {
812
const model = editor.getModel()!;
813
const reverseLinesAction = new ReverseLinesAction();
814
815
editor.setSelection(new Selection(2, 1, 2, 4));
816
executeAction(reverseLinesAction, editor);
817
assert.deepStrictEqual(model.getLinesContent(), [
818
'alpha',
819
'beta',
820
'omicron'
821
]);
822
});
823
});
824
});
825
826
test('transpose', () => {
827
withTestCodeEditor(
828
[
829
'hello world',
830
'',
831
'',
832
' ',
833
], {}, (editor) => {
834
const model = editor.getModel()!;
835
const transposeAction = new TransposeAction();
836
837
editor.setSelection(new Selection(1, 1, 1, 1));
838
executeAction(transposeAction, editor);
839
assert.strictEqual(model.getLineContent(1), 'hello world');
840
assertSelection(editor, new Selection(1, 2, 1, 2));
841
842
editor.setSelection(new Selection(1, 6, 1, 6));
843
executeAction(transposeAction, editor);
844
assert.strictEqual(model.getLineContent(1), 'hell oworld');
845
assertSelection(editor, new Selection(1, 7, 1, 7));
846
847
editor.setSelection(new Selection(1, 12, 1, 12));
848
executeAction(transposeAction, editor);
849
assert.strictEqual(model.getLineContent(1), 'hell oworl');
850
assertSelection(editor, new Selection(2, 2, 2, 2));
851
852
editor.setSelection(new Selection(3, 1, 3, 1));
853
executeAction(transposeAction, editor);
854
assert.strictEqual(model.getLineContent(3), '');
855
assertSelection(editor, new Selection(4, 1, 4, 1));
856
857
editor.setSelection(new Selection(4, 2, 4, 2));
858
executeAction(transposeAction, editor);
859
assert.strictEqual(model.getLineContent(4), ' ');
860
assertSelection(editor, new Selection(4, 3, 4, 3));
861
}
862
);
863
864
// fix #16633
865
withTestCodeEditor(
866
[
867
'',
868
'',
869
'hello',
870
'world',
871
'',
872
'hello world',
873
'',
874
'hello world'
875
], {}, (editor) => {
876
const model = editor.getModel()!;
877
const transposeAction = new TransposeAction();
878
879
editor.setSelection(new Selection(1, 1, 1, 1));
880
executeAction(transposeAction, editor);
881
assert.strictEqual(model.getLineContent(2), '');
882
assertSelection(editor, new Selection(2, 1, 2, 1));
883
884
editor.setSelection(new Selection(3, 6, 3, 6));
885
executeAction(transposeAction, editor);
886
assert.strictEqual(model.getLineContent(4), 'oworld');
887
assertSelection(editor, new Selection(4, 2, 4, 2));
888
889
editor.setSelection(new Selection(6, 12, 6, 12));
890
executeAction(transposeAction, editor);
891
assert.strictEqual(model.getLineContent(7), 'd');
892
assertSelection(editor, new Selection(7, 2, 7, 2));
893
894
editor.setSelection(new Selection(8, 12, 8, 12));
895
executeAction(transposeAction, editor);
896
assert.strictEqual(model.getLineContent(8), 'hello world');
897
assertSelection(editor, new Selection(8, 12, 8, 12));
898
}
899
);
900
});
901
902
test('toggle case', function () {
903
withTestCodeEditor(
904
[
905
'hello world',
906
'öçşğü',
907
'parseHTMLString',
908
'getElementById',
909
'insertHTML',
910
'PascalCase',
911
'CSSSelectorsList',
912
'iD',
913
'tEST',
914
'öçşÖÇŞğüĞÜ',
915
'audioConverter.convertM4AToMP3();',
916
'snake_case',
917
'Capital_Snake_Case',
918
`function helloWorld() {
919
return someGlobalObject.printHelloWorld("en", "utf-8");
920
}
921
helloWorld();`.replace(/^\s+/gm, ''),
922
`'JavaScript'`,
923
'parseHTML4String',
924
'_accessor: ServicesAccessor'
925
], {}, (editor) => {
926
const model = editor.getModel()!;
927
const uppercaseAction = new UpperCaseAction();
928
const lowercaseAction = new LowerCaseAction();
929
const titlecaseAction = new TitleCaseAction();
930
const snakecaseAction = new SnakeCaseAction();
931
932
editor.setSelection(new Selection(1, 1, 1, 12));
933
executeAction(uppercaseAction, editor);
934
assert.strictEqual(model.getLineContent(1), 'HELLO WORLD');
935
assertSelection(editor, new Selection(1, 1, 1, 12));
936
937
editor.setSelection(new Selection(1, 1, 1, 12));
938
executeAction(lowercaseAction, editor);
939
assert.strictEqual(model.getLineContent(1), 'hello world');
940
assertSelection(editor, new Selection(1, 1, 1, 12));
941
942
editor.setSelection(new Selection(1, 3, 1, 3));
943
executeAction(uppercaseAction, editor);
944
assert.strictEqual(model.getLineContent(1), 'HELLO world');
945
assertSelection(editor, new Selection(1, 3, 1, 3));
946
947
editor.setSelection(new Selection(1, 4, 1, 4));
948
executeAction(lowercaseAction, editor);
949
assert.strictEqual(model.getLineContent(1), 'hello world');
950
assertSelection(editor, new Selection(1, 4, 1, 4));
951
952
editor.setSelection(new Selection(1, 1, 1, 12));
953
executeAction(titlecaseAction, editor);
954
assert.strictEqual(model.getLineContent(1), 'Hello World');
955
assertSelection(editor, new Selection(1, 1, 1, 12));
956
957
editor.setSelection(new Selection(2, 1, 2, 6));
958
executeAction(uppercaseAction, editor);
959
assert.strictEqual(model.getLineContent(2), 'ÖÇŞĞÜ');
960
assertSelection(editor, new Selection(2, 1, 2, 6));
961
962
editor.setSelection(new Selection(2, 1, 2, 6));
963
executeAction(lowercaseAction, editor);
964
assert.strictEqual(model.getLineContent(2), 'öçşğü');
965
assertSelection(editor, new Selection(2, 1, 2, 6));
966
967
editor.setSelection(new Selection(2, 1, 2, 6));
968
executeAction(titlecaseAction, editor);
969
assert.strictEqual(model.getLineContent(2), 'Öçşğü');
970
assertSelection(editor, new Selection(2, 1, 2, 6));
971
972
editor.setSelection(new Selection(3, 1, 3, 16));
973
executeAction(snakecaseAction, editor);
974
assert.strictEqual(model.getLineContent(3), 'parse_html_string');
975
assertSelection(editor, new Selection(3, 1, 3, 18));
976
977
editor.setSelection(new Selection(4, 1, 4, 15));
978
executeAction(snakecaseAction, editor);
979
assert.strictEqual(model.getLineContent(4), 'get_element_by_id');
980
assertSelection(editor, new Selection(4, 1, 4, 18));
981
982
editor.setSelection(new Selection(5, 1, 5, 11));
983
executeAction(snakecaseAction, editor);
984
assert.strictEqual(model.getLineContent(5), 'insert_html');
985
assertSelection(editor, new Selection(5, 1, 5, 12));
986
987
editor.setSelection(new Selection(6, 1, 6, 11));
988
executeAction(snakecaseAction, editor);
989
assert.strictEqual(model.getLineContent(6), 'pascal_case');
990
assertSelection(editor, new Selection(6, 1, 6, 12));
991
992
editor.setSelection(new Selection(7, 1, 7, 17));
993
executeAction(snakecaseAction, editor);
994
assert.strictEqual(model.getLineContent(7), 'css_selectors_list');
995
assertSelection(editor, new Selection(7, 1, 7, 19));
996
997
editor.setSelection(new Selection(8, 1, 8, 3));
998
executeAction(snakecaseAction, editor);
999
assert.strictEqual(model.getLineContent(8), 'i_d');
1000
assertSelection(editor, new Selection(8, 1, 8, 4));
1001
1002
editor.setSelection(new Selection(9, 1, 9, 5));
1003
executeAction(snakecaseAction, editor);
1004
assert.strictEqual(model.getLineContent(9), 't_est');
1005
assertSelection(editor, new Selection(9, 1, 9, 6));
1006
1007
editor.setSelection(new Selection(10, 1, 10, 11));
1008
executeAction(snakecaseAction, editor);
1009
assert.strictEqual(model.getLineContent(10), 'öçş_öç_şğü_ğü');
1010
assertSelection(editor, new Selection(10, 1, 10, 14));
1011
1012
editor.setSelection(new Selection(11, 1, 11, 34));
1013
executeAction(snakecaseAction, editor);
1014
assert.strictEqual(model.getLineContent(11), 'audio_converter.convert_m4a_to_mp3();');
1015
assertSelection(editor, new Selection(11, 1, 11, 38));
1016
1017
editor.setSelection(new Selection(12, 1, 12, 11));
1018
executeAction(snakecaseAction, editor);
1019
assert.strictEqual(model.getLineContent(12), 'snake_case');
1020
assertSelection(editor, new Selection(12, 1, 12, 11));
1021
1022
editor.setSelection(new Selection(13, 1, 13, 19));
1023
executeAction(snakecaseAction, editor);
1024
assert.strictEqual(model.getLineContent(13), 'capital_snake_case');
1025
assertSelection(editor, new Selection(13, 1, 13, 19));
1026
1027
editor.setSelection(new Selection(14, 1, 17, 14));
1028
executeAction(snakecaseAction, editor);
1029
assert.strictEqual(model.getValueInRange(new Selection(14, 1, 17, 15)), `function hello_world() {
1030
return some_global_object.print_hello_world("en", "utf-8");
1031
}
1032
hello_world();`.replace(/^\s+/gm, ''));
1033
assertSelection(editor, new Selection(14, 1, 17, 15));
1034
1035
editor.setSelection(new Selection(18, 1, 18, 13));
1036
executeAction(snakecaseAction, editor);
1037
assert.strictEqual(model.getLineContent(18), `'java_script'`);
1038
assertSelection(editor, new Selection(18, 1, 18, 14));
1039
1040
editor.setSelection(new Selection(19, 1, 19, 17));
1041
executeAction(snakecaseAction, editor);
1042
assert.strictEqual(model.getLineContent(19), 'parse_html4_string');
1043
assertSelection(editor, new Selection(19, 1, 19, 19));
1044
1045
editor.setSelection(new Selection(20, 1, 20, 28));
1046
executeAction(snakecaseAction, editor);
1047
assert.strictEqual(model.getLineContent(20), '_accessor: services_accessor');
1048
assertSelection(editor, new Selection(20, 1, 20, 29));
1049
}
1050
);
1051
1052
withTestCodeEditor(
1053
[
1054
'foO baR BaZ',
1055
'foO\'baR\'BaZ',
1056
'foO[baR]BaZ',
1057
'foO`baR~BaZ',
1058
'foO^baR%BaZ',
1059
'foO$baR!BaZ',
1060
'\'physician\'s assistant\''
1061
], {}, (editor) => {
1062
const model = editor.getModel()!;
1063
const titlecaseAction = new TitleCaseAction();
1064
1065
editor.setSelection(new Selection(1, 1, 1, 12));
1066
executeAction(titlecaseAction, editor);
1067
assert.strictEqual(model.getLineContent(1), 'Foo Bar Baz');
1068
1069
editor.setSelection(new Selection(2, 1, 2, 12));
1070
executeAction(titlecaseAction, editor);
1071
assert.strictEqual(model.getLineContent(2), 'Foo\'bar\'baz');
1072
1073
editor.setSelection(new Selection(3, 1, 3, 12));
1074
executeAction(titlecaseAction, editor);
1075
assert.strictEqual(model.getLineContent(3), 'Foo[Bar]Baz');
1076
1077
editor.setSelection(new Selection(4, 1, 4, 12));
1078
executeAction(titlecaseAction, editor);
1079
assert.strictEqual(model.getLineContent(4), 'Foo`Bar~Baz');
1080
1081
editor.setSelection(new Selection(5, 1, 5, 12));
1082
executeAction(titlecaseAction, editor);
1083
assert.strictEqual(model.getLineContent(5), 'Foo^Bar%Baz');
1084
1085
editor.setSelection(new Selection(6, 1, 6, 12));
1086
executeAction(titlecaseAction, editor);
1087
assert.strictEqual(model.getLineContent(6), 'Foo$Bar!Baz');
1088
1089
editor.setSelection(new Selection(7, 1, 7, 23));
1090
executeAction(titlecaseAction, editor);
1091
assert.strictEqual(model.getLineContent(7), '\'Physician\'s Assistant\'');
1092
}
1093
);
1094
1095
withTestCodeEditor(
1096
[
1097
'camel from words',
1098
'from_snake_case',
1099
'from-kebab-case',
1100
'alreadyCamel',
1101
'ReTain_some_CAPitalization',
1102
'my_var.test_function()',
1103
'öçş_öç_şğü_ğü',
1104
'XMLHttpRequest',
1105
'\tfunction hello_world() {',
1106
'\t\treturn some_global_object;',
1107
'\t}',
1108
], {}, (editor) => {
1109
const model = editor.getModel()!;
1110
const camelcaseAction = new CamelCaseAction();
1111
1112
editor.setSelection(new Selection(1, 1, 1, 18));
1113
executeAction(camelcaseAction, editor);
1114
assert.strictEqual(model.getLineContent(1), 'camelFromWords');
1115
1116
editor.setSelection(new Selection(2, 1, 2, 15));
1117
executeAction(camelcaseAction, editor);
1118
assert.strictEqual(model.getLineContent(2), 'fromSnakeCase');
1119
1120
editor.setSelection(new Selection(3, 1, 3, 15));
1121
executeAction(camelcaseAction, editor);
1122
assert.strictEqual(model.getLineContent(3), 'fromKebabCase');
1123
1124
editor.setSelection(new Selection(4, 1, 4, 12));
1125
executeAction(camelcaseAction, editor);
1126
assert.strictEqual(model.getLineContent(4), 'alreadyCamel');
1127
1128
editor.setSelection(new Selection(5, 1, 5, 26));
1129
executeAction(camelcaseAction, editor);
1130
assert.strictEqual(model.getLineContent(5), 'reTainSomeCAPitalization');
1131
1132
editor.setSelection(new Selection(6, 1, 6, 23));
1133
executeAction(camelcaseAction, editor);
1134
assert.strictEqual(model.getLineContent(6), 'myVar.testFunction()');
1135
1136
editor.setSelection(new Selection(7, 1, 7, 14));
1137
executeAction(camelcaseAction, editor);
1138
assert.strictEqual(model.getLineContent(7), 'öçşÖçŞğüĞü');
1139
1140
editor.setSelection(new Selection(8, 1, 8, 14));
1141
executeAction(camelcaseAction, editor);
1142
assert.strictEqual(model.getLineContent(8), 'XMLHttpRequest');
1143
1144
editor.setSelection(new Selection(9, 1, 11, 2));
1145
executeAction(camelcaseAction, editor);
1146
assert.strictEqual(model.getValueInRange(new Selection(9, 1, 11, 3)), '\tfunction helloWorld() {\n\t\treturn someGlobalObject;\n\t}');
1147
}
1148
);
1149
1150
withTestCodeEditor(
1151
[
1152
'',
1153
' '
1154
], {}, (editor) => {
1155
const model = editor.getModel()!;
1156
const uppercaseAction = new UpperCaseAction();
1157
const lowercaseAction = new LowerCaseAction();
1158
1159
editor.setSelection(new Selection(1, 1, 1, 1));
1160
executeAction(uppercaseAction, editor);
1161
assert.strictEqual(model.getLineContent(1), '');
1162
assertSelection(editor, new Selection(1, 1, 1, 1));
1163
1164
editor.setSelection(new Selection(1, 1, 1, 1));
1165
executeAction(lowercaseAction, editor);
1166
assert.strictEqual(model.getLineContent(1), '');
1167
assertSelection(editor, new Selection(1, 1, 1, 1));
1168
1169
editor.setSelection(new Selection(2, 2, 2, 2));
1170
executeAction(uppercaseAction, editor);
1171
assert.strictEqual(model.getLineContent(2), ' ');
1172
assertSelection(editor, new Selection(2, 2, 2, 2));
1173
1174
editor.setSelection(new Selection(2, 2, 2, 2));
1175
executeAction(lowercaseAction, editor);
1176
assert.strictEqual(model.getLineContent(2), ' ');
1177
assertSelection(editor, new Selection(2, 2, 2, 2));
1178
}
1179
);
1180
1181
withTestCodeEditor(
1182
[
1183
'hello world',
1184
'öçşğü',
1185
'parseHTMLString',
1186
'getElementById',
1187
'PascalCase',
1188
'öçşÖÇŞğüĞÜ',
1189
'audioConverter.convertM4AToMP3();',
1190
'Capital_Snake_Case',
1191
'parseHTML4String',
1192
'_accessor: ServicesAccessor',
1193
'Kebab-Case',
1194
], {}, (editor) => {
1195
const model = editor.getModel()!;
1196
const kebabCaseAction = new KebabCaseAction();
1197
1198
editor.setSelection(new Selection(1, 1, 1, 12));
1199
executeAction(kebabCaseAction, editor);
1200
assert.strictEqual(model.getLineContent(1), 'hello world');
1201
assertSelection(editor, new Selection(1, 1, 1, 12));
1202
1203
editor.setSelection(new Selection(2, 1, 2, 6));
1204
executeAction(kebabCaseAction, editor);
1205
assert.strictEqual(model.getLineContent(2), 'öçşğü');
1206
assertSelection(editor, new Selection(2, 1, 2, 6));
1207
1208
editor.setSelection(new Selection(3, 1, 3, 16));
1209
executeAction(kebabCaseAction, editor);
1210
assert.strictEqual(model.getLineContent(3), 'parse-html-string');
1211
assertSelection(editor, new Selection(3, 1, 3, 18));
1212
1213
editor.setSelection(new Selection(4, 1, 4, 15));
1214
executeAction(kebabCaseAction, editor);
1215
assert.strictEqual(model.getLineContent(4), 'get-element-by-id');
1216
assertSelection(editor, new Selection(4, 1, 4, 18));
1217
1218
editor.setSelection(new Selection(5, 1, 5, 11));
1219
executeAction(kebabCaseAction, editor);
1220
assert.strictEqual(model.getLineContent(5), 'pascal-case');
1221
assertSelection(editor, new Selection(5, 1, 5, 12));
1222
1223
editor.setSelection(new Selection(6, 1, 6, 11));
1224
executeAction(kebabCaseAction, editor);
1225
assert.strictEqual(model.getLineContent(6), 'öçş-öç-şğü-ğü');
1226
assertSelection(editor, new Selection(6, 1, 6, 14));
1227
1228
editor.setSelection(new Selection(7, 1, 7, 34));
1229
executeAction(kebabCaseAction, editor);
1230
assert.strictEqual(model.getLineContent(7), 'audio-converter.convert-m4a-to-mp3();');
1231
assertSelection(editor, new Selection(7, 1, 7, 38));
1232
1233
editor.setSelection(new Selection(8, 1, 8, 19));
1234
executeAction(kebabCaseAction, editor);
1235
assert.strictEqual(model.getLineContent(8), 'capital-snake-case');
1236
assertSelection(editor, new Selection(8, 1, 8, 19));
1237
1238
editor.setSelection(new Selection(9, 1, 9, 17));
1239
executeAction(kebabCaseAction, editor);
1240
assert.strictEqual(model.getLineContent(9), 'parse-html4-string');
1241
assertSelection(editor, new Selection(9, 1, 9, 19));
1242
1243
editor.setSelection(new Selection(10, 1, 10, 28));
1244
executeAction(kebabCaseAction, editor);
1245
assert.strictEqual(model.getLineContent(10), '_accessor: services-accessor');
1246
assertSelection(editor, new Selection(10, 1, 10, 29));
1247
1248
editor.setSelection(new Selection(11, 1, 11, 11));
1249
executeAction(kebabCaseAction, editor);
1250
assert.strictEqual(model.getLineContent(11), 'kebab-case');
1251
assertSelection(editor, new Selection(11, 1, 11, 11));
1252
}
1253
);
1254
1255
withTestCodeEditor(
1256
[
1257
'hello world',
1258
'öçşğü',
1259
'parseHTMLString',
1260
'getElementById',
1261
'PascalCase',
1262
'öçşÖÇŞğüĞÜ',
1263
'audioConverter.convertM4AToMP3();',
1264
'Capital_Snake_Case',
1265
'parseHTML4String',
1266
'Kebab-Case',
1267
'FOO_BAR',
1268
'FOO BAR A',
1269
'xML_HTTP-reQUEsT',
1270
'ÉCOLE',
1271
'ΩMEGA_CASE',
1272
'ДОМ_ТЕСТ',
1273
], {}, (editor) => {
1274
const model = editor.getModel()!;
1275
const pascalCaseAction = new PascalCaseAction();
1276
1277
editor.setSelection(new Selection(1, 1, 1, 12));
1278
executeAction(pascalCaseAction, editor);
1279
assert.strictEqual(model.getLineContent(1), 'HelloWorld');
1280
assertSelection(editor, new Selection(1, 1, 1, 11));
1281
1282
editor.setSelection(new Selection(2, 1, 2, 6));
1283
executeAction(pascalCaseAction, editor);
1284
assert.strictEqual(model.getLineContent(2), 'Öçşğü');
1285
assertSelection(editor, new Selection(2, 1, 2, 6));
1286
1287
editor.setSelection(new Selection(3, 1, 3, 16));
1288
executeAction(pascalCaseAction, editor);
1289
assert.strictEqual(model.getLineContent(3), 'ParseHTMLString');
1290
assertSelection(editor, new Selection(3, 1, 3, 16));
1291
1292
editor.setSelection(new Selection(4, 1, 4, 15));
1293
executeAction(pascalCaseAction, editor);
1294
assert.strictEqual(model.getLineContent(4), 'GetElementById');
1295
assertSelection(editor, new Selection(4, 1, 4, 15));
1296
1297
editor.setSelection(new Selection(5, 1, 5, 11));
1298
executeAction(pascalCaseAction, editor);
1299
assert.strictEqual(model.getLineContent(5), 'PascalCase');
1300
assertSelection(editor, new Selection(5, 1, 5, 11));
1301
1302
editor.setSelection(new Selection(6, 1, 6, 11));
1303
executeAction(pascalCaseAction, editor);
1304
assert.strictEqual(model.getLineContent(6), 'ÖçşÖÇŞğüĞÜ');
1305
assertSelection(editor, new Selection(6, 1, 6, 11));
1306
1307
editor.setSelection(new Selection(7, 1, 7, 34));
1308
executeAction(pascalCaseAction, editor);
1309
assert.strictEqual(model.getLineContent(7), 'AudioConverter.ConvertM4AToMP3();');
1310
assertSelection(editor, new Selection(7, 1, 7, 34));
1311
1312
editor.setSelection(new Selection(8, 1, 8, 19));
1313
executeAction(pascalCaseAction, editor);
1314
assert.strictEqual(model.getLineContent(8), 'CapitalSnakeCase');
1315
assertSelection(editor, new Selection(8, 1, 8, 17));
1316
1317
editor.setSelection(new Selection(9, 1, 9, 17));
1318
executeAction(pascalCaseAction, editor);
1319
assert.strictEqual(model.getLineContent(9), 'ParseHTML4String');
1320
assertSelection(editor, new Selection(9, 1, 9, 17));
1321
1322
editor.setSelection(new Selection(10, 1, 10, 11));
1323
executeAction(pascalCaseAction, editor);
1324
assert.strictEqual(model.getLineContent(10), 'KebabCase');
1325
assertSelection(editor, new Selection(10, 1, 10, 10));
1326
1327
editor.setSelection(new Selection(9, 1, 10, 11));
1328
executeAction(pascalCaseAction, editor);
1329
assert.strictEqual(model.getValueInRange(new Selection(9, 1, 10, 11)), 'ParseHTML4String\nKebabCase');
1330
assertSelection(editor, new Selection(9, 1, 10, 10));
1331
1332
editor.setSelection(new Selection(11, 1, 11, 8));
1333
executeAction(pascalCaseAction, editor);
1334
assert.strictEqual(model.getLineContent(11), 'FooBar');
1335
assertSelection(editor, new Selection(11, 1, 11, 7));
1336
1337
editor.setSelection(new Selection(12, 1, 12, 10));
1338
executeAction(pascalCaseAction, editor);
1339
assert.strictEqual(model.getLineContent(12), 'FooBarA');
1340
assertSelection(editor, new Selection(12, 1, 12, 8));
1341
1342
editor.setSelection(new Selection(13, 1, 13, 17));
1343
executeAction(pascalCaseAction, editor);
1344
assert.strictEqual(model.getLineContent(13), 'XmlHttpReQUEsT');
1345
assertSelection(editor, new Selection(13, 1, 13, 15));
1346
1347
editor.setSelection(new Selection(14, 1, 14, 6));
1348
executeAction(pascalCaseAction, editor);
1349
assert.strictEqual(model.getLineContent(14), 'École');
1350
assertSelection(editor, new Selection(14, 1, 14, 6));
1351
1352
editor.setSelection(new Selection(15, 1, 15, 11));
1353
executeAction(pascalCaseAction, editor);
1354
assert.strictEqual(model.getLineContent(15), 'ΩmegaCase');
1355
assertSelection(editor, new Selection(15, 1, 15, 10));
1356
1357
editor.setSelection(new Selection(16, 1, 16, 9));
1358
executeAction(pascalCaseAction, editor);
1359
assert.strictEqual(model.getLineContent(16), 'ДомТест');
1360
assertSelection(editor, new Selection(16, 1, 16, 8));
1361
1362
}
1363
);
1364
});
1365
1366
suite('DeleteAllRightAction', () => {
1367
test('should be noop on empty', () => {
1368
withTestCodeEditor([''], {}, (editor) => {
1369
const model = editor.getModel()!;
1370
const action = new DeleteAllRightAction();
1371
1372
executeAction(action, editor);
1373
assert.deepStrictEqual(model.getLinesContent(), ['']);
1374
assert.deepStrictEqual(editor.getSelections(), [new Selection(1, 1, 1, 1)]);
1375
1376
editor.setSelection(new Selection(1, 1, 1, 1));
1377
executeAction(action, editor);
1378
assert.deepStrictEqual(model.getLinesContent(), ['']);
1379
assert.deepStrictEqual(editor.getSelections(), [new Selection(1, 1, 1, 1)]);
1380
1381
editor.setSelections([new Selection(1, 1, 1, 1), new Selection(1, 1, 1, 1), new Selection(1, 1, 1, 1)]);
1382
executeAction(action, editor);
1383
assert.deepStrictEqual(model.getLinesContent(), ['']);
1384
assert.deepStrictEqual(editor.getSelections(), [new Selection(1, 1, 1, 1)]);
1385
});
1386
});
1387
1388
test('should delete selected range', () => {
1389
withTestCodeEditor([
1390
'hello',
1391
'world'
1392
], {}, (editor) => {
1393
const model = editor.getModel()!;
1394
const action = new DeleteAllRightAction();
1395
1396
editor.setSelection(new Selection(1, 2, 1, 5));
1397
executeAction(action, editor);
1398
assert.deepStrictEqual(model.getLinesContent(), ['ho', 'world']);
1399
assert.deepStrictEqual(editor.getSelections(), [new Selection(1, 2, 1, 2)]);
1400
1401
editor.setSelection(new Selection(1, 1, 2, 4));
1402
executeAction(action, editor);
1403
assert.deepStrictEqual(model.getLinesContent(), ['ld']);
1404
assert.deepStrictEqual(editor.getSelections(), [new Selection(1, 1, 1, 1)]);
1405
1406
editor.setSelection(new Selection(1, 1, 1, 3));
1407
executeAction(action, editor);
1408
assert.deepStrictEqual(model.getLinesContent(), ['']);
1409
assert.deepStrictEqual(editor.getSelections(), [new Selection(1, 1, 1, 1)]);
1410
});
1411
});
1412
1413
test('should delete to the right of the cursor', () => {
1414
withTestCodeEditor([
1415
'hello',
1416
'world'
1417
], {}, (editor) => {
1418
const model = editor.getModel()!;
1419
const action = new DeleteAllRightAction();
1420
1421
editor.setSelection(new Selection(1, 3, 1, 3));
1422
executeAction(action, editor);
1423
assert.deepStrictEqual(model.getLinesContent(), ['he', 'world']);
1424
assert.deepStrictEqual(editor.getSelections(), [new Selection(1, 3, 1, 3)]);
1425
1426
editor.setSelection(new Selection(2, 1, 2, 1));
1427
executeAction(action, editor);
1428
assert.deepStrictEqual(model.getLinesContent(), ['he', '']);
1429
assert.deepStrictEqual(editor.getSelections(), [new Selection(2, 1, 2, 1)]);
1430
});
1431
});
1432
1433
test('should join two lines, if at the end of the line', () => {
1434
withTestCodeEditor([
1435
'hello',
1436
'world'
1437
], {}, (editor) => {
1438
const model = editor.getModel()!;
1439
const action = new DeleteAllRightAction();
1440
1441
editor.setSelection(new Selection(1, 6, 1, 6));
1442
executeAction(action, editor);
1443
assert.deepStrictEqual(model.getLinesContent(), ['helloworld']);
1444
assert.deepStrictEqual(editor.getSelections(), [new Selection(1, 6, 1, 6)]);
1445
1446
editor.setSelection(new Selection(1, 6, 1, 6));
1447
executeAction(action, editor);
1448
assert.deepStrictEqual(model.getLinesContent(), ['hello']);
1449
assert.deepStrictEqual(editor.getSelections(), [new Selection(1, 6, 1, 6)]);
1450
1451
editor.setSelection(new Selection(1, 6, 1, 6));
1452
executeAction(action, editor);
1453
assert.deepStrictEqual(model.getLinesContent(), ['hello']);
1454
assert.deepStrictEqual(editor.getSelections(), [new Selection(1, 6, 1, 6)]);
1455
});
1456
});
1457
1458
test('should work with multiple cursors', () => {
1459
withTestCodeEditor([
1460
'hello',
1461
'there',
1462
'world'
1463
], {}, (editor) => {
1464
const model = editor.getModel()!;
1465
const action = new DeleteAllRightAction();
1466
1467
editor.setSelections([
1468
new Selection(1, 3, 1, 3),
1469
new Selection(1, 6, 1, 6),
1470
new Selection(3, 4, 3, 4),
1471
]);
1472
executeAction(action, editor);
1473
assert.deepStrictEqual(model.getLinesContent(), ['hethere', 'wor']);
1474
assert.deepStrictEqual(editor.getSelections(), [
1475
new Selection(1, 3, 1, 3),
1476
new Selection(2, 4, 2, 4)
1477
]);
1478
1479
executeAction(action, editor);
1480
assert.deepStrictEqual(model.getLinesContent(), ['he', 'wor']);
1481
assert.deepStrictEqual(editor.getSelections(), [
1482
new Selection(1, 3, 1, 3),
1483
new Selection(2, 4, 2, 4)
1484
]);
1485
1486
executeAction(action, editor);
1487
assert.deepStrictEqual(model.getLinesContent(), ['hewor']);
1488
assert.deepStrictEqual(editor.getSelections(), [
1489
new Selection(1, 3, 1, 3),
1490
new Selection(1, 6, 1, 6)
1491
]);
1492
1493
executeAction(action, editor);
1494
assert.deepStrictEqual(model.getLinesContent(), ['he']);
1495
assert.deepStrictEqual(editor.getSelections(), [
1496
new Selection(1, 3, 1, 3)
1497
]);
1498
1499
executeAction(action, editor);
1500
assert.deepStrictEqual(model.getLinesContent(), ['he']);
1501
assert.deepStrictEqual(editor.getSelections(), [
1502
new Selection(1, 3, 1, 3)
1503
]);
1504
});
1505
});
1506
1507
test('should work with undo/redo', () => {
1508
withTestCodeEditor([
1509
'hello',
1510
'there',
1511
'world'
1512
], {}, (editor) => {
1513
const model = editor.getModel()!;
1514
const action = new DeleteAllRightAction();
1515
1516
editor.setSelections([
1517
new Selection(1, 3, 1, 3),
1518
new Selection(1, 6, 1, 6),
1519
new Selection(3, 4, 3, 4),
1520
]);
1521
executeAction(action, editor);
1522
assert.deepStrictEqual(model.getLinesContent(), ['hethere', 'wor']);
1523
assert.deepStrictEqual(editor.getSelections(), [
1524
new Selection(1, 3, 1, 3),
1525
new Selection(2, 4, 2, 4)
1526
]);
1527
1528
editor.runCommand(CoreEditingCommands.Undo, null);
1529
assert.deepStrictEqual(editor.getSelections(), [
1530
new Selection(1, 3, 1, 3),
1531
new Selection(1, 6, 1, 6),
1532
new Selection(3, 4, 3, 4)
1533
]);
1534
editor.runCommand(CoreEditingCommands.Redo, null);
1535
assert.deepStrictEqual(editor.getSelections(), [
1536
new Selection(1, 3, 1, 3),
1537
new Selection(2, 4, 2, 4)
1538
]);
1539
});
1540
});
1541
});
1542
1543
test('InsertLineBeforeAction', () => {
1544
function testInsertLineBefore(lineNumber: number, column: number, callback: (model: ITextModel, viewModel: ViewModel) => void): void {
1545
const TEXT = [
1546
'First line',
1547
'Second line',
1548
'Third line'
1549
];
1550
withTestCodeEditor(TEXT, {}, (editor, viewModel) => {
1551
editor.setPosition(new Position(lineNumber, column));
1552
const insertLineBeforeAction = new InsertLineBeforeAction();
1553
1554
executeAction(insertLineBeforeAction, editor);
1555
callback(editor.getModel()!, viewModel);
1556
});
1557
}
1558
1559
testInsertLineBefore(1, 3, (model, viewModel) => {
1560
assert.deepStrictEqual(viewModel.getSelection(), new Selection(1, 1, 1, 1));
1561
assert.strictEqual(model.getLineContent(1), '');
1562
assert.strictEqual(model.getLineContent(2), 'First line');
1563
assert.strictEqual(model.getLineContent(3), 'Second line');
1564
assert.strictEqual(model.getLineContent(4), 'Third line');
1565
});
1566
1567
testInsertLineBefore(2, 3, (model, viewModel) => {
1568
assert.deepStrictEqual(viewModel.getSelection(), new Selection(2, 1, 2, 1));
1569
assert.strictEqual(model.getLineContent(1), 'First line');
1570
assert.strictEqual(model.getLineContent(2), '');
1571
assert.strictEqual(model.getLineContent(3), 'Second line');
1572
assert.strictEqual(model.getLineContent(4), 'Third line');
1573
});
1574
1575
testInsertLineBefore(3, 3, (model, viewModel) => {
1576
assert.deepStrictEqual(viewModel.getSelection(), new Selection(3, 1, 3, 1));
1577
assert.strictEqual(model.getLineContent(1), 'First line');
1578
assert.strictEqual(model.getLineContent(2), 'Second line');
1579
assert.strictEqual(model.getLineContent(3), '');
1580
assert.strictEqual(model.getLineContent(4), 'Third line');
1581
});
1582
});
1583
1584
test('InsertLineAfterAction', () => {
1585
function testInsertLineAfter(lineNumber: number, column: number, callback: (model: ITextModel, viewModel: ViewModel) => void): void {
1586
const TEXT = [
1587
'First line',
1588
'Second line',
1589
'Third line'
1590
];
1591
withTestCodeEditor(TEXT, {}, (editor, viewModel) => {
1592
editor.setPosition(new Position(lineNumber, column));
1593
const insertLineAfterAction = new InsertLineAfterAction();
1594
1595
executeAction(insertLineAfterAction, editor);
1596
callback(editor.getModel()!, viewModel);
1597
});
1598
}
1599
1600
testInsertLineAfter(1, 3, (model, viewModel) => {
1601
assert.deepStrictEqual(viewModel.getSelection(), new Selection(2, 1, 2, 1));
1602
assert.strictEqual(model.getLineContent(1), 'First line');
1603
assert.strictEqual(model.getLineContent(2), '');
1604
assert.strictEqual(model.getLineContent(3), 'Second line');
1605
assert.strictEqual(model.getLineContent(4), 'Third line');
1606
});
1607
1608
testInsertLineAfter(2, 3, (model, viewModel) => {
1609
assert.deepStrictEqual(viewModel.getSelection(), new Selection(3, 1, 3, 1));
1610
assert.strictEqual(model.getLineContent(1), 'First line');
1611
assert.strictEqual(model.getLineContent(2), 'Second line');
1612
assert.strictEqual(model.getLineContent(3), '');
1613
assert.strictEqual(model.getLineContent(4), 'Third line');
1614
});
1615
1616
testInsertLineAfter(3, 3, (model, viewModel) => {
1617
assert.deepStrictEqual(viewModel.getSelection(), new Selection(4, 1, 4, 1));
1618
assert.strictEqual(model.getLineContent(1), 'First line');
1619
assert.strictEqual(model.getLineContent(2), 'Second line');
1620
assert.strictEqual(model.getLineContent(3), 'Third line');
1621
assert.strictEqual(model.getLineContent(4), '');
1622
});
1623
});
1624
1625
test('Bug 18276:[editor] Indentation broken when selection is empty', () => {
1626
1627
const model = createTextModel(
1628
[
1629
'function baz() {'
1630
].join('\n'),
1631
undefined,
1632
{
1633
insertSpaces: false,
1634
}
1635
);
1636
1637
withTestCodeEditor(model, {}, (editor) => {
1638
const indentLinesAction = new IndentLinesAction();
1639
editor.setPosition(new Position(1, 2));
1640
1641
executeAction(indentLinesAction, editor);
1642
assert.strictEqual(model.getLineContent(1), '\tfunction baz() {');
1643
assert.deepStrictEqual(editor.getSelection(), new Selection(1, 3, 1, 3));
1644
1645
editor.runCommand(CoreEditingCommands.Tab, null);
1646
assert.strictEqual(model.getLineContent(1), '\tf\tunction baz() {');
1647
});
1648
1649
model.dispose();
1650
});
1651
1652
test('issue #80736: Indenting while the cursor is at the start of a line of text causes the added spaces or tab to be selected', () => {
1653
const model = createTextModel(
1654
[
1655
'Some text'
1656
].join('\n'),
1657
undefined,
1658
{
1659
insertSpaces: false,
1660
}
1661
);
1662
1663
withTestCodeEditor(model, {}, (editor) => {
1664
const indentLinesAction = new IndentLinesAction();
1665
editor.setPosition(new Position(1, 1));
1666
1667
executeAction(indentLinesAction, editor);
1668
assert.strictEqual(model.getLineContent(1), '\tSome text');
1669
assert.deepStrictEqual(editor.getSelection(), new Selection(1, 2, 1, 2));
1670
});
1671
1672
model.dispose();
1673
});
1674
1675
test('Indenting on empty line should move cursor', () => {
1676
const model = createTextModel(
1677
[
1678
''
1679
].join('\n')
1680
);
1681
1682
withTestCodeEditor(model, { useTabStops: false }, (editor) => {
1683
const indentLinesAction = new IndentLinesAction();
1684
editor.setPosition(new Position(1, 1));
1685
1686
executeAction(indentLinesAction, editor);
1687
assert.strictEqual(model.getLineContent(1), ' ');
1688
assert.deepStrictEqual(editor.getSelection(), new Selection(1, 5, 1, 5));
1689
});
1690
1691
model.dispose();
1692
});
1693
1694
test('issue #62112: Delete line does not work properly when multiple cursors are on line', () => {
1695
const TEXT = [
1696
'a',
1697
'foo boo',
1698
'too',
1699
'c',
1700
];
1701
withTestCodeEditor(TEXT, {}, (editor) => {
1702
editor.setSelections([
1703
new Selection(2, 4, 2, 4),
1704
new Selection(2, 8, 2, 8),
1705
new Selection(3, 4, 3, 4),
1706
]);
1707
const deleteLinesAction = new DeleteLinesAction();
1708
executeAction(deleteLinesAction, editor);
1709
1710
assert.strictEqual(editor.getValue(), 'a\nc');
1711
});
1712
});
1713
1714
function testDeleteLinesCommand(initialText: string[], _initialSelections: Selection | Selection[], resultingText: string[], _resultingSelections: Selection | Selection[]): void {
1715
const initialSelections = Array.isArray(_initialSelections) ? _initialSelections : [_initialSelections];
1716
const resultingSelections = Array.isArray(_resultingSelections) ? _resultingSelections : [_resultingSelections];
1717
withTestCodeEditor(initialText, {}, (editor) => {
1718
editor.setSelections(initialSelections);
1719
const deleteLinesAction = new DeleteLinesAction();
1720
executeAction(deleteLinesAction, editor);
1721
1722
assert.strictEqual(editor.getValue(), resultingText.join('\n'));
1723
assert.deepStrictEqual(editor.getSelections(), resultingSelections);
1724
});
1725
}
1726
1727
test('empty selection in middle of lines', function () {
1728
testDeleteLinesCommand(
1729
[
1730
'first',
1731
'second line',
1732
'third line',
1733
'fourth line',
1734
'fifth'
1735
],
1736
new Selection(2, 3, 2, 3),
1737
[
1738
'first',
1739
'third line',
1740
'fourth line',
1741
'fifth'
1742
],
1743
new Selection(2, 3, 2, 3)
1744
);
1745
});
1746
1747
test('empty selection at top of lines', function () {
1748
testDeleteLinesCommand(
1749
[
1750
'first',
1751
'second line',
1752
'third line',
1753
'fourth line',
1754
'fifth'
1755
],
1756
new Selection(1, 5, 1, 5),
1757
[
1758
'second line',
1759
'third line',
1760
'fourth line',
1761
'fifth'
1762
],
1763
new Selection(1, 5, 1, 5)
1764
);
1765
});
1766
1767
test('empty selection at end of lines', function () {
1768
testDeleteLinesCommand(
1769
[
1770
'first',
1771
'second line',
1772
'third line',
1773
'fourth line',
1774
'fifth'
1775
],
1776
new Selection(5, 2, 5, 2),
1777
[
1778
'first',
1779
'second line',
1780
'third line',
1781
'fourth line'
1782
],
1783
new Selection(4, 2, 4, 2)
1784
);
1785
});
1786
1787
test('with selection in middle of lines', function () {
1788
testDeleteLinesCommand(
1789
[
1790
'first',
1791
'second line',
1792
'third line',
1793
'fourth line',
1794
'fifth'
1795
],
1796
new Selection(3, 3, 2, 2),
1797
[
1798
'first',
1799
'fourth line',
1800
'fifth'
1801
],
1802
new Selection(2, 2, 2, 2)
1803
);
1804
});
1805
1806
test('with selection at top of lines', function () {
1807
testDeleteLinesCommand(
1808
[
1809
'first',
1810
'second line',
1811
'third line',
1812
'fourth line',
1813
'fifth'
1814
],
1815
new Selection(1, 4, 1, 5),
1816
[
1817
'second line',
1818
'third line',
1819
'fourth line',
1820
'fifth'
1821
],
1822
new Selection(1, 5, 1, 5)
1823
);
1824
});
1825
1826
test('with selection at end of lines', function () {
1827
testDeleteLinesCommand(
1828
[
1829
'first',
1830
'second line',
1831
'third line',
1832
'fourth line',
1833
'fifth'
1834
],
1835
new Selection(5, 1, 5, 2),
1836
[
1837
'first',
1838
'second line',
1839
'third line',
1840
'fourth line'
1841
],
1842
new Selection(4, 2, 4, 2)
1843
);
1844
});
1845
1846
test('with full line selection in middle of lines', function () {
1847
testDeleteLinesCommand(
1848
[
1849
'first',
1850
'second line',
1851
'third line',
1852
'fourth line',
1853
'fifth'
1854
],
1855
new Selection(4, 1, 2, 1),
1856
[
1857
'first',
1858
'fourth line',
1859
'fifth'
1860
],
1861
new Selection(2, 1, 2, 1)
1862
);
1863
});
1864
1865
test('with full line selection at top of lines', function () {
1866
testDeleteLinesCommand(
1867
[
1868
'first',
1869
'second line',
1870
'third line',
1871
'fourth line',
1872
'fifth'
1873
],
1874
new Selection(2, 1, 1, 5),
1875
[
1876
'second line',
1877
'third line',
1878
'fourth line',
1879
'fifth'
1880
],
1881
new Selection(1, 5, 1, 5)
1882
);
1883
});
1884
1885
test('with full line selection at end of lines', function () {
1886
testDeleteLinesCommand(
1887
[
1888
'first',
1889
'second line',
1890
'third line',
1891
'fourth line',
1892
'fifth'
1893
],
1894
new Selection(4, 1, 5, 2),
1895
[
1896
'first',
1897
'second line',
1898
'third line'
1899
],
1900
new Selection(3, 2, 3, 2)
1901
);
1902
});
1903
1904
test('multicursor 1', function () {
1905
testDeleteLinesCommand(
1906
[
1907
'class P {',
1908
'',
1909
' getA() {',
1910
' if (true) {',
1911
' return "a";',
1912
' }',
1913
' }',
1914
'',
1915
' getB() {',
1916
' if (true) {',
1917
' return "b";',
1918
' }',
1919
' }',
1920
'',
1921
' getC() {',
1922
' if (true) {',
1923
' return "c";',
1924
' }',
1925
' }',
1926
'}',
1927
],
1928
[
1929
new Selection(4, 1, 5, 1),
1930
new Selection(10, 1, 11, 1),
1931
new Selection(16, 1, 17, 1),
1932
],
1933
[
1934
'class P {',
1935
'',
1936
' getA() {',
1937
' return "a";',
1938
' }',
1939
' }',
1940
'',
1941
' getB() {',
1942
' return "b";',
1943
' }',
1944
' }',
1945
'',
1946
' getC() {',
1947
' return "c";',
1948
' }',
1949
' }',
1950
'}',
1951
],
1952
[
1953
new Selection(4, 1, 4, 1),
1954
new Selection(9, 1, 9, 1),
1955
new Selection(14, 1, 14, 1),
1956
]
1957
);
1958
});
1959
});
1960
1961