Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/editor/contrib/indentation/test/browser/indentation.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
6
import assert from 'assert';
7
import { DisposableStore, IDisposable } from '../../../../../base/common/lifecycle.js';
8
import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/test/common/utils.js';
9
import { ILanguageConfigurationService } from '../../../../common/languages/languageConfigurationRegistry.js';
10
import { createTextModel } from '../../../../test/common/testTextModel.js';
11
import { TestInstantiationService } from '../../../../../platform/instantiation/test/common/instantiationServiceMock.js';
12
import { Range } from '../../../../common/core/range.js';
13
import { Selection } from '../../../../common/core/selection.js';
14
import { MetadataConsts, StandardTokenType } from '../../../../common/encodedTokenAttributes.js';
15
import { EncodedTokenizationResult, IState, ITokenizationSupport, TokenizationRegistry } from '../../../../common/languages.js';
16
import { ILanguageService } from '../../../../common/languages/language.js';
17
import { NullState } from '../../../../common/languages/nullTokenize.js';
18
import { AutoIndentOnPaste, IndentationToSpacesCommand, IndentationToTabsCommand } from '../../browser/indentation.js';
19
import { withTestCodeEditor } from '../../../../test/browser/testCodeEditor.js';
20
import { testCommand } from '../../../../test/browser/testCommand.js';
21
import { goIndentationRules, htmlIndentationRules, javascriptIndentationRules, latexIndentationRules, luaIndentationRules, phpIndentationRules, rubyIndentationRules, vbIndentationRules } from '../../../../test/common/modes/supports/indentationRules.js';
22
import { cppOnEnterRules, htmlOnEnterRules, javascriptOnEnterRules, phpOnEnterRules } from '../../../../test/common/modes/supports/onEnterRules.js';
23
import { TypeOperations } from '../../../../common/cursor/cursorTypeOperations.js';
24
import { cppBracketRules, goBracketRules, htmlBracketRules, latexBracketRules, luaBracketRules, phpBracketRules, rubyBracketRules, typescriptBracketRules, vbBracketRules } from '../../../../test/common/modes/supports/bracketRules.js';
25
import { javascriptAutoClosingPairsRules, latexAutoClosingPairsRules } from '../../../../test/common/modes/supports/autoClosingPairsRules.js';
26
import { LanguageService } from '../../../../common/services/languageService.js';
27
import { ServiceCollection } from '../../../../../platform/instantiation/common/serviceCollection.js';
28
import { TestLanguageConfigurationService } from '../../../../test/common/modes/testLanguageConfigurationService.js';
29
30
export enum Language {
31
TypeScript = 'ts-test',
32
Ruby = 'ruby-test',
33
PHP = 'php-test',
34
Go = 'go-test',
35
CPP = 'cpp-test',
36
HTML = 'html-test',
37
VB = 'vb-test',
38
Latex = 'latex-test',
39
Lua = 'lua-test'
40
}
41
42
function testIndentationToSpacesCommand(lines: string[], selection: Selection, tabSize: number, expectedLines: string[], expectedSelection: Selection): void {
43
testCommand(lines, null, selection, (accessor, sel) => new IndentationToSpacesCommand(sel, tabSize), expectedLines, expectedSelection);
44
}
45
46
function testIndentationToTabsCommand(lines: string[], selection: Selection, tabSize: number, expectedLines: string[], expectedSelection: Selection): void {
47
testCommand(lines, null, selection, (accessor, sel) => new IndentationToTabsCommand(sel, tabSize), expectedLines, expectedSelection);
48
}
49
50
export function registerLanguage(languageService: ILanguageService, language: Language): IDisposable {
51
return languageService.registerLanguage({ id: language });
52
}
53
54
export function registerLanguageConfiguration(languageConfigurationService: ILanguageConfigurationService, language: Language): IDisposable {
55
switch (language) {
56
case Language.TypeScript:
57
return languageConfigurationService.register(language, {
58
brackets: typescriptBracketRules,
59
comments: {
60
lineComment: '//',
61
blockComment: ['/*', '*/']
62
},
63
autoClosingPairs: javascriptAutoClosingPairsRules,
64
indentationRules: javascriptIndentationRules,
65
onEnterRules: javascriptOnEnterRules
66
});
67
case Language.Ruby:
68
return languageConfigurationService.register(language, {
69
brackets: rubyBracketRules,
70
indentationRules: rubyIndentationRules,
71
});
72
case Language.PHP:
73
return languageConfigurationService.register(language, {
74
brackets: phpBracketRules,
75
indentationRules: phpIndentationRules,
76
onEnterRules: phpOnEnterRules
77
});
78
case Language.Go:
79
return languageConfigurationService.register(language, {
80
brackets: goBracketRules,
81
indentationRules: goIndentationRules
82
});
83
case Language.CPP:
84
return languageConfigurationService.register(language, {
85
brackets: cppBracketRules,
86
onEnterRules: cppOnEnterRules
87
});
88
case Language.HTML:
89
return languageConfigurationService.register(language, {
90
brackets: htmlBracketRules,
91
indentationRules: htmlIndentationRules,
92
onEnterRules: htmlOnEnterRules
93
});
94
case Language.VB:
95
return languageConfigurationService.register(language, {
96
brackets: vbBracketRules,
97
indentationRules: vbIndentationRules,
98
});
99
case Language.Latex:
100
return languageConfigurationService.register(language, {
101
brackets: latexBracketRules,
102
autoClosingPairs: latexAutoClosingPairsRules,
103
indentationRules: latexIndentationRules
104
});
105
case Language.Lua:
106
return languageConfigurationService.register(language, {
107
brackets: luaBracketRules,
108
indentationRules: luaIndentationRules
109
});
110
}
111
}
112
113
export interface StandardTokenTypeData {
114
startIndex: number;
115
standardTokenType: StandardTokenType;
116
}
117
118
export function registerTokenizationSupport(instantiationService: TestInstantiationService, tokens: StandardTokenTypeData[][], languageId: Language): IDisposable {
119
let lineIndex = 0;
120
const languageService = instantiationService.get(ILanguageService);
121
const tokenizationSupport: ITokenizationSupport = {
122
getInitialState: () => NullState,
123
tokenize: undefined!,
124
tokenizeEncoded: (line: string, hasEOL: boolean, state: IState): EncodedTokenizationResult => {
125
const tokensOnLine = tokens[lineIndex++];
126
const encodedLanguageId = languageService.languageIdCodec.encodeLanguageId(languageId);
127
const result = new Uint32Array(2 * tokensOnLine.length);
128
for (let i = 0; i < tokensOnLine.length; i++) {
129
result[2 * i] = tokensOnLine[i].startIndex;
130
result[2 * i + 1] =
131
(
132
(encodedLanguageId << MetadataConsts.LANGUAGEID_OFFSET)
133
| (tokensOnLine[i].standardTokenType << MetadataConsts.TOKEN_TYPE_OFFSET)
134
);
135
}
136
return new EncodedTokenizationResult(result, [], state);
137
}
138
};
139
return TokenizationRegistry.register(languageId, tokenizationSupport);
140
}
141
142
suite('Change Indentation to Spaces - TypeScript/Javascript', () => {
143
144
ensureNoDisposablesAreLeakedInTestSuite();
145
146
test('single tabs only at start of line', function () {
147
testIndentationToSpacesCommand(
148
[
149
'first',
150
'second line',
151
'third line',
152
'\tfourth line',
153
'\tfifth'
154
],
155
new Selection(2, 3, 2, 3),
156
4,
157
[
158
'first',
159
'second line',
160
'third line',
161
' fourth line',
162
' fifth'
163
],
164
new Selection(2, 3, 2, 3)
165
);
166
});
167
168
test('multiple tabs at start of line', function () {
169
testIndentationToSpacesCommand(
170
[
171
'\t\tfirst',
172
'\tsecond line',
173
'\t\t\t third line',
174
'fourth line',
175
'fifth'
176
],
177
new Selection(1, 5, 1, 5),
178
3,
179
[
180
' first',
181
' second line',
182
' third line',
183
'fourth line',
184
'fifth'
185
],
186
new Selection(1, 9, 1, 9)
187
);
188
});
189
190
test('multiple tabs', function () {
191
testIndentationToSpacesCommand(
192
[
193
'\t\tfirst\t',
194
'\tsecond \t line \t',
195
'\t\t\t third line',
196
' \tfourth line',
197
'fifth'
198
],
199
new Selection(1, 5, 1, 5),
200
2,
201
[
202
' first\t',
203
' second \t line \t',
204
' third line',
205
' fourth line',
206
'fifth'
207
],
208
new Selection(1, 7, 1, 7)
209
);
210
});
211
212
test('empty lines', function () {
213
testIndentationToSpacesCommand(
214
[
215
'\t\t\t',
216
'\t',
217
'\t\t'
218
],
219
new Selection(1, 4, 1, 4),
220
2,
221
[
222
' ',
223
' ',
224
' '
225
],
226
new Selection(1, 4, 1, 4)
227
);
228
});
229
});
230
231
suite('Change Indentation to Tabs - TypeScript/Javascript', () => {
232
233
ensureNoDisposablesAreLeakedInTestSuite();
234
235
test('spaces only at start of line', function () {
236
testIndentationToTabsCommand(
237
[
238
' first',
239
'second line',
240
' third line',
241
'fourth line',
242
'fifth'
243
],
244
new Selection(2, 3, 2, 3),
245
4,
246
[
247
'\tfirst',
248
'second line',
249
'\tthird line',
250
'fourth line',
251
'fifth'
252
],
253
new Selection(2, 3, 2, 3)
254
);
255
});
256
257
test('multiple spaces at start of line', function () {
258
testIndentationToTabsCommand(
259
[
260
'first',
261
' second line',
262
' third line',
263
'fourth line',
264
' fifth'
265
],
266
new Selection(1, 5, 1, 5),
267
3,
268
[
269
'first',
270
'\tsecond line',
271
'\t\t\t third line',
272
'fourth line',
273
'\t fifth'
274
],
275
new Selection(1, 5, 1, 5)
276
);
277
});
278
279
test('multiple spaces', function () {
280
testIndentationToTabsCommand(
281
[
282
' first ',
283
' second line \t',
284
' third line',
285
' fourth line',
286
'fifth'
287
],
288
new Selection(1, 8, 1, 8),
289
2,
290
[
291
'\t\t\tfirst ',
292
'\tsecond line \t',
293
'\t\t\t third line',
294
'\t fourth line',
295
'fifth'
296
],
297
new Selection(1, 5, 1, 5)
298
);
299
});
300
301
test('issue #45996', function () {
302
testIndentationToSpacesCommand(
303
[
304
'\tabc',
305
],
306
new Selection(1, 3, 1, 3),
307
4,
308
[
309
' abc',
310
],
311
new Selection(1, 6, 1, 6)
312
);
313
});
314
});
315
316
suite('Indent With Tab - TypeScript/JavaScript', () => {
317
318
const languageId = Language.TypeScript;
319
let disposables: DisposableStore;
320
let serviceCollection: ServiceCollection;
321
322
setup(() => {
323
disposables = new DisposableStore();
324
const languageService = new LanguageService();
325
const languageConfigurationService = new TestLanguageConfigurationService();
326
disposables.add(languageService);
327
disposables.add(languageConfigurationService);
328
disposables.add(registerLanguage(languageService, languageId));
329
disposables.add(registerLanguageConfiguration(languageConfigurationService, languageId));
330
serviceCollection = new ServiceCollection(
331
[ILanguageService, languageService],
332
[ILanguageConfigurationService, languageConfigurationService]
333
);
334
});
335
336
teardown(() => {
337
disposables.dispose();
338
});
339
340
ensureNoDisposablesAreLeakedInTestSuite();
341
342
test('temp issue because there should be at least one passing test in a suite', () => {
343
assert.ok(true);
344
});
345
346
test.skip('issue #63388: perserve correct indentation on tab 1', () => {
347
348
// https://github.com/microsoft/vscode/issues/63388
349
350
const model = createTextModel([
351
'/*',
352
' * Comment',
353
' * /',
354
].join('\n'), languageId, {});
355
disposables.add(model);
356
357
withTestCodeEditor(model, { autoIndent: 'full', serviceCollection }, (editor, viewModel, instantiationService) => {
358
editor.setSelection(new Selection(1, 1, 3, 5));
359
editor.executeCommands('editor.action.indentLines', TypeOperations.indent(viewModel.cursorConfig, editor.getModel(), editor.getSelections()));
360
assert.strictEqual(model.getValue(), [
361
' /*',
362
' * Comment',
363
' * /',
364
].join('\n'));
365
});
366
});
367
368
test.skip('issue #63388: perserve correct indentation on tab 2', () => {
369
370
// https://github.com/microsoft/vscode/issues/63388
371
372
const model = createTextModel([
373
'switch (something) {',
374
' case 1:',
375
' whatever();',
376
' break;',
377
'}',
378
].join('\n'), languageId, {});
379
disposables.add(model);
380
381
withTestCodeEditor(model, { autoIndent: 'full', serviceCollection }, (editor, viewModel, instantiationService) => {
382
editor.setSelection(new Selection(1, 1, 5, 2));
383
editor.executeCommands('editor.action.indentLines', TypeOperations.indent(viewModel.cursorConfig, editor.getModel(), editor.getSelections()));
384
assert.strictEqual(model.getValue(), [
385
' switch (something) {',
386
' case 1:',
387
' whatever();',
388
' break;',
389
' }',
390
].join('\n'));
391
});
392
});
393
});
394
395
suite('Auto Indent On Paste - TypeScript/JavaScript', () => {
396
397
const languageId = Language.TypeScript;
398
let disposables: DisposableStore;
399
let serviceCollection: ServiceCollection;
400
401
setup(() => {
402
disposables = new DisposableStore();
403
const languageService = new LanguageService();
404
const languageConfigurationService = new TestLanguageConfigurationService();
405
disposables.add(languageService);
406
disposables.add(languageConfigurationService);
407
disposables.add(registerLanguage(languageService, languageId));
408
disposables.add(registerLanguageConfiguration(languageConfigurationService, languageId));
409
serviceCollection = new ServiceCollection(
410
[ILanguageService, languageService],
411
[ILanguageConfigurationService, languageConfigurationService]
412
);
413
});
414
415
teardown(() => {
416
disposables.dispose();
417
});
418
419
ensureNoDisposablesAreLeakedInTestSuite();
420
421
test('issue #119225: Do not add extra leading space when pasting JSDoc', () => {
422
423
const model = createTextModel('', languageId, {});
424
disposables.add(model);
425
426
withTestCodeEditor(model, { autoIndent: 'full', serviceCollection }, (editor, viewModel, instantiationService) => {
427
const pasteText = [
428
'/**',
429
' * JSDoc',
430
' */',
431
'function a() {}'
432
].join('\n');
433
const tokens: StandardTokenTypeData[][] = [
434
[
435
{ startIndex: 0, standardTokenType: StandardTokenType.Comment },
436
{ startIndex: 3, standardTokenType: StandardTokenType.Comment },
437
],
438
[
439
{ startIndex: 0, standardTokenType: StandardTokenType.Comment },
440
{ startIndex: 2, standardTokenType: StandardTokenType.Comment },
441
{ startIndex: 8, standardTokenType: StandardTokenType.Comment },
442
],
443
[
444
{ startIndex: 0, standardTokenType: StandardTokenType.Comment },
445
{ startIndex: 1, standardTokenType: StandardTokenType.Comment },
446
{ startIndex: 3, standardTokenType: StandardTokenType.Other },
447
],
448
[
449
{ startIndex: 0, standardTokenType: StandardTokenType.Other },
450
{ startIndex: 8, standardTokenType: StandardTokenType.Other },
451
{ startIndex: 9, standardTokenType: StandardTokenType.Other },
452
{ startIndex: 10, standardTokenType: StandardTokenType.Other },
453
{ startIndex: 11, standardTokenType: StandardTokenType.Other },
454
{ startIndex: 12, standardTokenType: StandardTokenType.Other },
455
{ startIndex: 13, standardTokenType: StandardTokenType.Other },
456
{ startIndex: 14, standardTokenType: StandardTokenType.Other },
457
{ startIndex: 15, standardTokenType: StandardTokenType.Other },
458
]
459
];
460
disposables.add(registerTokenizationSupport(instantiationService, tokens, languageId));
461
const autoIndentOnPasteController = editor.registerAndInstantiateContribution(AutoIndentOnPaste.ID, AutoIndentOnPaste);
462
viewModel.paste(pasteText, true, undefined, 'keyboard');
463
autoIndentOnPasteController.trigger(new Range(1, 1, 4, 16));
464
assert.strictEqual(model.getValue(), pasteText);
465
});
466
});
467
468
test('issue #167299: Blank line removes indent', () => {
469
470
const model = createTextModel('', languageId, {});
471
disposables.add(model);
472
473
withTestCodeEditor(model, { autoIndent: 'full', serviceCollection }, (editor, viewModel, instantiationService) => {
474
475
// no need for tokenization because there are no comments
476
const pasteText = [
477
'',
478
'export type IncludeReference =',
479
' | BaseReference',
480
' | SelfReference',
481
' | RelativeReference;',
482
'',
483
'export const enum IncludeReferenceKind {',
484
' Base,',
485
' Self,',
486
' RelativeReference,',
487
'}'
488
].join('\n');
489
490
const autoIndentOnPasteController = editor.registerAndInstantiateContribution(AutoIndentOnPaste.ID, AutoIndentOnPaste);
491
viewModel.paste(pasteText, true, undefined, 'keyboard');
492
autoIndentOnPasteController.trigger(new Range(1, 1, 11, 2));
493
assert.strictEqual(model.getValue(), pasteText);
494
});
495
});
496
497
test('issue #29803: do not indent when pasting text with only one line', () => {
498
499
// https://github.com/microsoft/vscode/issues/29803
500
501
const model = createTextModel([
502
'const linkHandler = new Class(a, b, c,',
503
' d)'
504
].join('\n'), languageId, {});
505
disposables.add(model);
506
507
withTestCodeEditor(model, { autoIndent: 'full', serviceCollection }, (editor, viewModel, instantiationService) => {
508
editor.setSelection(new Selection(2, 6, 2, 6));
509
const text = ', null';
510
viewModel.paste(text, true, undefined, 'keyboard');
511
const autoIndentOnPasteController = editor.registerAndInstantiateContribution(AutoIndentOnPaste.ID, AutoIndentOnPaste);
512
autoIndentOnPasteController.trigger(new Range(2, 6, 2, 11));
513
assert.strictEqual(model.getValue(), [
514
'const linkHandler = new Class(a, b, c,',
515
' d, null)'
516
].join('\n'));
517
});
518
});
519
520
test('issue #29753: incorrect indentation after comment', () => {
521
522
// https://github.com/microsoft/vscode/issues/29753
523
524
const model = createTextModel([
525
'class A {',
526
' /**',
527
' * used only for debug purposes.',
528
' */',
529
' private _codeInfo: KeyMapping[];',
530
'}',
531
].join('\n'), languageId, {});
532
disposables.add(model);
533
534
withTestCodeEditor(model, { autoIndent: 'full', serviceCollection }, (editor, viewModel, instantiationService) => {
535
editor.setSelection(new Selection(5, 24, 5, 34));
536
const text = 'IMacLinuxKeyMapping';
537
viewModel.paste(text, true, undefined, 'keyboard');
538
const autoIndentOnPasteController = editor.registerAndInstantiateContribution(AutoIndentOnPaste.ID, AutoIndentOnPaste);
539
autoIndentOnPasteController.trigger(new Range(5, 24, 5, 43));
540
assert.strictEqual(model.getValue(), [
541
'class A {',
542
' /**',
543
' * used only for debug purposes.',
544
' */',
545
' private _codeInfo: IMacLinuxKeyMapping[];',
546
'}',
547
].join('\n'));
548
});
549
});
550
551
test('issue #29753: incorrect indentation of header comment', () => {
552
553
// https://github.com/microsoft/vscode/issues/29753
554
555
const model = createTextModel('', languageId, {});
556
disposables.add(model);
557
558
withTestCodeEditor(model, { autoIndent: 'full', serviceCollection }, (editor, viewModel, instantiationService) => {
559
const text = [
560
'/*----------------',
561
' * Copyright (c) ',
562
' * Licensed under ...',
563
' *-----------------*/',
564
].join('\n');
565
viewModel.paste(text, true, undefined, 'keyboard');
566
const autoIndentOnPasteController = editor.registerAndInstantiateContribution(AutoIndentOnPaste.ID, AutoIndentOnPaste);
567
autoIndentOnPasteController.trigger(new Range(1, 1, 4, 22));
568
assert.strictEqual(model.getValue(), text);
569
});
570
});
571
572
test('issue #209859: do not do change indentation when pasted inside of a string', () => {
573
574
// issue: https://github.com/microsoft/vscode/issues/209859
575
// issue: https://github.com/microsoft/vscode/issues/209418
576
577
const initialText = [
578
'const foo = "some text',
579
' which is strangely',
580
' indented"'
581
].join('\n');
582
const model = createTextModel(initialText, languageId, {});
583
disposables.add(model);
584
585
withTestCodeEditor(model, { autoIndent: 'full', serviceCollection }, (editor, viewModel, instantiationService) => {
586
const tokens: StandardTokenTypeData[][] = [
587
[
588
{ startIndex: 0, standardTokenType: StandardTokenType.Other },
589
{ startIndex: 12, standardTokenType: StandardTokenType.String },
590
],
591
[
592
{ startIndex: 0, standardTokenType: StandardTokenType.String },
593
],
594
[
595
{ startIndex: 0, standardTokenType: StandardTokenType.String },
596
]
597
];
598
disposables.add(registerTokenizationSupport(instantiationService, tokens, languageId));
599
600
editor.setSelection(new Selection(2, 10, 2, 15));
601
viewModel.paste('which', true, undefined, 'keyboard');
602
const autoIndentOnPasteController = editor.registerAndInstantiateContribution(AutoIndentOnPaste.ID, AutoIndentOnPaste);
603
autoIndentOnPasteController.trigger(new Range(2, 1, 2, 28));
604
assert.strictEqual(model.getValue(), initialText);
605
});
606
});
607
608
// Failing tests found in issues...
609
610
test.skip('issue #181065: Incorrect paste of object within comment', () => {
611
612
// https://github.com/microsoft/vscode/issues/181065
613
614
const model = createTextModel('', languageId, {});
615
disposables.add(model);
616
617
withTestCodeEditor(model, { autoIndent: 'full', serviceCollection }, (editor, viewModel, instantiationService) => {
618
const text = [
619
'/**',
620
' * @typedef {',
621
' * }',
622
' */'
623
].join('\n');
624
const tokens: StandardTokenTypeData[][] = [
625
[
626
{ startIndex: 0, standardTokenType: StandardTokenType.Comment },
627
{ startIndex: 3, standardTokenType: StandardTokenType.Comment },
628
],
629
[
630
{ startIndex: 0, standardTokenType: StandardTokenType.Comment },
631
{ startIndex: 2, standardTokenType: StandardTokenType.Comment },
632
{ startIndex: 3, standardTokenType: StandardTokenType.Comment },
633
{ startIndex: 11, standardTokenType: StandardTokenType.Comment },
634
{ startIndex: 12, standardTokenType: StandardTokenType.Other },
635
{ startIndex: 13, standardTokenType: StandardTokenType.Other },
636
],
637
[
638
{ startIndex: 0, standardTokenType: StandardTokenType.Comment },
639
{ startIndex: 2, standardTokenType: StandardTokenType.Other },
640
{ startIndex: 3, standardTokenType: StandardTokenType.Other },
641
{ startIndex: 4, standardTokenType: StandardTokenType.Other },
642
],
643
[
644
{ startIndex: 0, standardTokenType: StandardTokenType.Comment },
645
{ startIndex: 1, standardTokenType: StandardTokenType.Comment },
646
{ startIndex: 3, standardTokenType: StandardTokenType.Other },
647
]
648
];
649
disposables.add(registerTokenizationSupport(instantiationService, tokens, languageId));
650
const autoIndentOnPasteController = editor.registerAndInstantiateContribution(AutoIndentOnPaste.ID, AutoIndentOnPaste);
651
viewModel.paste(text, true, undefined, 'keyboard');
652
autoIndentOnPasteController.trigger(new Range(1, 1, 4, 4));
653
assert.strictEqual(model.getValue(), text);
654
});
655
});
656
657
test.skip('issue #86301: preserve cursor at inserted indentation level', () => {
658
659
// https://github.com/microsoft/vscode/issues/86301
660
661
const model = createTextModel([
662
'() => {',
663
'',
664
'}',
665
].join('\n'), languageId, {});
666
disposables.add(model);
667
668
withTestCodeEditor(model, { autoIndent: 'full', serviceCollection }, (editor, viewModel, instantiationService) => {
669
editor.setSelection(new Selection(2, 1, 2, 1));
670
const text = [
671
'() => {',
672
'',
673
'}',
674
''
675
].join('\n');
676
const autoIndentOnPasteController = editor.registerAndInstantiateContribution(AutoIndentOnPaste.ID, AutoIndentOnPaste);
677
viewModel.paste(text, true, undefined, 'keyboard');
678
autoIndentOnPasteController.trigger(new Range(2, 1, 5, 1));
679
680
// notes:
681
// why is line 3 not indented to the same level as line 2?
682
// looks like the indentation is inserted correctly at line 5, but the cursor does not appear at the maximum indentation level?
683
assert.strictEqual(model.getValue(), [
684
'() => {',
685
' () => {',
686
' ', // <- should also be indented
687
' }',
688
' ', // <- cursor should be at the end of the indentation
689
'}',
690
].join('\n'));
691
692
const selection = viewModel.getSelection();
693
assert.deepStrictEqual(selection, new Selection(5, 5, 5, 5));
694
});
695
});
696
697
test.skip('issue #85781: indent line with extra white space', () => {
698
699
// https://github.com/microsoft/vscode/issues/85781
700
// note: still to determine whether this is a bug or not
701
702
const model = createTextModel([
703
'() => {',
704
' console.log("a");',
705
'}',
706
].join('\n'), languageId, {});
707
disposables.add(model);
708
709
withTestCodeEditor(model, { autoIndent: 'full', serviceCollection }, (editor, viewModel, instantiationService) => {
710
editor.setSelection(new Selection(2, 5, 2, 5));
711
const text = [
712
'() => {',
713
' console.log("b")',
714
'}',
715
' '
716
].join('\n');
717
const autoIndentOnPasteController = editor.registerAndInstantiateContribution(AutoIndentOnPaste.ID, AutoIndentOnPaste);
718
viewModel.paste(text, true, undefined, 'keyboard');
719
// todo@aiday-mar, make sure range is correct, and make test work as in real life
720
autoIndentOnPasteController.trigger(new Range(2, 5, 5, 6));
721
assert.strictEqual(model.getValue(), [
722
'() => {',
723
' () => {',
724
' console.log("b")',
725
' }',
726
' console.log("a");',
727
'}',
728
].join('\n'));
729
});
730
});
731
732
test.skip('issue #29589: incorrect indentation of closing brace on paste', () => {
733
734
// https://github.com/microsoft/vscode/issues/29589
735
736
const model = createTextModel('', languageId, {});
737
disposables.add(model);
738
739
withTestCodeEditor(model, { autoIndent: 'full', serviceCollection }, (editor, viewModel, instantiationService) => {
740
editor.setSelection(new Selection(2, 5, 2, 5));
741
const text = [
742
'function makeSub(a,b) {',
743
'subsent = sent.substring(a,b);',
744
'return subsent;',
745
'}',
746
].join('\n');
747
const autoIndentOnPasteController = editor.registerAndInstantiateContribution(AutoIndentOnPaste.ID, AutoIndentOnPaste);
748
viewModel.paste(text, true, undefined, 'keyboard');
749
// todo@aiday-mar, make sure range is correct, and make test work as in real life
750
autoIndentOnPasteController.trigger(new Range(1, 1, 4, 2));
751
assert.strictEqual(model.getValue(), [
752
'function makeSub(a,b) {',
753
'subsent = sent.substring(a,b);',
754
'return subsent;',
755
'}',
756
].join('\n'));
757
});
758
});
759
760
test.skip('issue #201420: incorrect indentation when first line is comment', () => {
761
762
// https://github.com/microsoft/vscode/issues/201420
763
764
const model = createTextModel([
765
'function bar() {',
766
'',
767
'}',
768
].join('\n'), languageId, {});
769
disposables.add(model);
770
771
withTestCodeEditor(model, { autoIndent: 'full', serviceCollection }, (editor, viewModel, instantiationService) => {
772
const tokens: StandardTokenTypeData[][] = [
773
[
774
{ startIndex: 0, standardTokenType: StandardTokenType.Other },
775
{ startIndex: 8, standardTokenType: StandardTokenType.Other },
776
{ startIndex: 9, standardTokenType: StandardTokenType.Other },
777
{ startIndex: 12, standardTokenType: StandardTokenType.Other },
778
{ startIndex: 13, standardTokenType: StandardTokenType.Other },
779
{ startIndex: 14, standardTokenType: StandardTokenType.Other },
780
{ startIndex: 15, standardTokenType: StandardTokenType.Other },
781
{ startIndex: 16, standardTokenType: StandardTokenType.Other }
782
],
783
[
784
{ startIndex: 0, standardTokenType: StandardTokenType.Comment },
785
{ startIndex: 2, standardTokenType: StandardTokenType.Comment },
786
{ startIndex: 3, standardTokenType: StandardTokenType.Comment },
787
{ startIndex: 10, standardTokenType: StandardTokenType.Comment }
788
],
789
[
790
{ startIndex: 0, standardTokenType: StandardTokenType.Other },
791
{ startIndex: 5, standardTokenType: StandardTokenType.Other },
792
{ startIndex: 6, standardTokenType: StandardTokenType.Other },
793
{ startIndex: 9, standardTokenType: StandardTokenType.Other },
794
{ startIndex: 10, standardTokenType: StandardTokenType.Other },
795
{ startIndex: 11, standardTokenType: StandardTokenType.Other },
796
{ startIndex: 12, standardTokenType: StandardTokenType.Other },
797
{ startIndex: 14, standardTokenType: StandardTokenType.Other }],
798
[
799
{ startIndex: 0, standardTokenType: StandardTokenType.Other },
800
{ startIndex: 1, standardTokenType: StandardTokenType.Other }]
801
];
802
disposables.add(registerTokenizationSupport(instantiationService, tokens, languageId));
803
804
editor.setSelection(new Selection(2, 1, 2, 1));
805
const text = [
806
'// comment',
807
'const foo = 42',
808
].join('\n');
809
const autoIndentOnPasteController = editor.registerAndInstantiateContribution(AutoIndentOnPaste.ID, AutoIndentOnPaste);
810
viewModel.paste(text, true, undefined, 'keyboard');
811
autoIndentOnPasteController.trigger(new Range(2, 1, 3, 15));
812
assert.strictEqual(model.getValue(), [
813
'function bar() {',
814
' // comment',
815
' const foo = 42',
816
'}',
817
].join('\n'));
818
});
819
});
820
});
821
822
suite('Auto Indent On Type - TypeScript/JavaScript', () => {
823
824
const languageId = Language.TypeScript;
825
let disposables: DisposableStore;
826
let serviceCollection: ServiceCollection;
827
828
setup(() => {
829
disposables = new DisposableStore();
830
const languageService = new LanguageService();
831
const languageConfigurationService = new TestLanguageConfigurationService();
832
disposables.add(languageService);
833
disposables.add(languageConfigurationService);
834
disposables.add(registerLanguage(languageService, languageId));
835
disposables.add(registerLanguageConfiguration(languageConfigurationService, languageId));
836
serviceCollection = new ServiceCollection(
837
[ILanguageService, languageService],
838
[ILanguageConfigurationService, languageConfigurationService]
839
);
840
});
841
842
teardown(() => {
843
disposables.dispose();
844
});
845
846
ensureNoDisposablesAreLeakedInTestSuite();
847
848
// Failing tests from issues...
849
850
test('issue #208215: indent after arrow function', () => {
851
852
// https://github.com/microsoft/vscode/issues/208215
853
854
const model = createTextModel('', languageId, {});
855
disposables.add(model);
856
857
withTestCodeEditor(model, { autoIndent: 'full', serviceCollection }, (editor, viewModel) => {
858
viewModel.type('const add1 = (n) =>');
859
viewModel.type('\n', 'keyboard');
860
assert.strictEqual(model.getValue(), [
861
'const add1 = (n) =>',
862
' ',
863
].join('\n'));
864
});
865
});
866
867
test('issue #208215: indent after arrow function 2', () => {
868
869
// https://github.com/microsoft/vscode/issues/208215
870
871
const model = createTextModel([
872
'const array = [1, 2, 3, 4, 5];',
873
'array.map(',
874
' v =>',
875
].join('\n'), languageId, {});
876
disposables.add(model);
877
878
withTestCodeEditor(model, { autoIndent: 'full', serviceCollection }, (editor, viewModel) => {
879
editor.setSelection(new Selection(3, 9, 3, 9));
880
viewModel.type('\n', 'keyboard');
881
assert.strictEqual(model.getValue(), [
882
'const array = [1, 2, 3, 4, 5];',
883
'array.map(',
884
' v =>',
885
' '
886
].join('\n'));
887
});
888
});
889
890
test('issue #116843: indent after arrow function', () => {
891
892
// https://github.com/microsoft/vscode/issues/116843
893
894
const model = createTextModel('', languageId, {});
895
disposables.add(model);
896
897
withTestCodeEditor(model, { autoIndent: 'full', serviceCollection }, (editor, viewModel) => {
898
viewModel.type([
899
'const add1 = (n) =>',
900
' n + 1;',
901
].join('\n'));
902
viewModel.type('\n', 'keyboard');
903
assert.strictEqual(model.getValue(), [
904
'const add1 = (n) =>',
905
' n + 1;',
906
'',
907
].join('\n'));
908
});
909
});
910
911
test('issue #29755: do not add indentation on enter if indentation is already valid', () => {
912
913
//https://github.com/microsoft/vscode/issues/29755
914
915
const model = createTextModel([
916
'function f() {',
917
' const one = 1;',
918
' const two = 2;',
919
'}',
920
].join('\n'), languageId, {});
921
disposables.add(model);
922
923
withTestCodeEditor(model, { autoIndent: 'full', serviceCollection }, (editor, viewModel) => {
924
editor.setSelection(new Selection(3, 1, 3, 1));
925
viewModel.type('\n', 'keyboard');
926
assert.strictEqual(model.getValue(), [
927
'function f() {',
928
' const one = 1;',
929
'',
930
' const two = 2;',
931
'}',
932
].join('\n'));
933
});
934
});
935
936
test('issue #36090', () => {
937
938
// https://github.com/microsoft/vscode/issues/36090
939
940
const model = createTextModel([
941
'class ItemCtrl {',
942
' getPropertiesByItemId(id) {',
943
' return this.fetchItem(id)',
944
' .then(item => {',
945
' return this.getPropertiesOfItem(item);',
946
' });',
947
' }',
948
'}',
949
].join('\n'), languageId, {});
950
disposables.add(model);
951
952
withTestCodeEditor(model, { autoIndent: 'advanced', serviceCollection }, (editor, viewModel) => {
953
editor.setSelection(new Selection(7, 6, 7, 6));
954
viewModel.type('\n', 'keyboard');
955
assert.strictEqual(model.getValue(),
956
[
957
'class ItemCtrl {',
958
' getPropertiesByItemId(id) {',
959
' return this.fetchItem(id)',
960
' .then(item => {',
961
' return this.getPropertiesOfItem(item);',
962
' });',
963
' }',
964
' ',
965
'}',
966
].join('\n')
967
);
968
assert.deepStrictEqual(editor.getSelection(), new Selection(8, 5, 8, 5));
969
});
970
});
971
972
test('issue #115304: indent block comment onEnter', () => {
973
974
// https://github.com/microsoft/vscode/issues/115304
975
976
const model = createTextModel([
977
'/** */',
978
'function f() {}',
979
].join('\n'), languageId, {});
980
disposables.add(model);
981
982
withTestCodeEditor(model, { autoIndent: 'advanced', serviceCollection }, (editor, viewModel) => {
983
editor.setSelection(new Selection(1, 4, 1, 4));
984
viewModel.type('\n', 'keyboard');
985
assert.strictEqual(model.getValue(),
986
[
987
'/**',
988
' * ',
989
' */',
990
'function f() {}',
991
].join('\n')
992
);
993
assert.deepStrictEqual(editor.getSelection(), new Selection(2, 4, 2, 4));
994
});
995
});
996
997
test('issue #43244: indent when lambda arrow function is detected, outdent when end is reached', () => {
998
999
// https://github.com/microsoft/vscode/issues/43244
1000
1001
const model = createTextModel([
1002
'const array = [1, 2, 3, 4, 5];',
1003
'array.map(_)'
1004
].join('\n'), languageId, {});
1005
disposables.add(model);
1006
1007
withTestCodeEditor(model, { autoIndent: 'full', serviceCollection }, (editor, viewModel) => {
1008
editor.setSelection(new Selection(2, 12, 2, 12));
1009
viewModel.type('\n', 'keyboard');
1010
assert.strictEqual(model.getValue(), [
1011
'const array = [1, 2, 3, 4, 5];',
1012
'array.map(_',
1013
' ',
1014
')'
1015
].join('\n'));
1016
});
1017
});
1018
1019
test('issue #43244: incorrect indentation after if/for/while without braces', () => {
1020
1021
// https://github.com/microsoft/vscode/issues/43244
1022
1023
const model = createTextModel([
1024
'function f() {',
1025
' if (condition)',
1026
'}'
1027
].join('\n'), languageId, {});
1028
disposables.add(model);
1029
1030
withTestCodeEditor(model, { autoIndent: 'full', serviceCollection }, (editor, viewModel) => {
1031
editor.setSelection(new Selection(2, 19, 2, 19));
1032
viewModel.type('\n', 'keyboard');
1033
assert.strictEqual(model.getValue(), [
1034
'function f() {',
1035
' if (condition)',
1036
' ',
1037
'}',
1038
].join('\n'));
1039
1040
viewModel.type('return;');
1041
viewModel.type('\n', 'keyboard');
1042
assert.strictEqual(model.getValue(), [
1043
'function f() {',
1044
' if (condition)',
1045
' return;',
1046
' ',
1047
'}',
1048
].join('\n'));
1049
});
1050
});
1051
1052
test('issue #208232: incorrect indentation inside of comments', () => {
1053
1054
// https://github.com/microsoft/vscode/issues/208232
1055
1056
const model = createTextModel([
1057
'/**',
1058
'indentation done for {',
1059
'*/'
1060
].join('\n'), languageId, {});
1061
disposables.add(model);
1062
1063
withTestCodeEditor(model, { autoIndent: 'full', serviceCollection }, (editor, viewModel, instantiationService) => {
1064
const tokens: StandardTokenTypeData[][] = [
1065
[{ startIndex: 0, standardTokenType: StandardTokenType.Comment }],
1066
[{ startIndex: 0, standardTokenType: StandardTokenType.Comment }],
1067
[{ startIndex: 0, standardTokenType: StandardTokenType.Comment }]
1068
];
1069
disposables.add(registerTokenizationSupport(instantiationService, tokens, languageId));
1070
editor.setSelection(new Selection(2, 23, 2, 23));
1071
viewModel.type('\n', 'keyboard');
1072
assert.strictEqual(model.getValue(), [
1073
'/**',
1074
'indentation done for {',
1075
'',
1076
'*/'
1077
].join('\n'));
1078
});
1079
});
1080
1081
test('issue #209802: allman style braces in JavaScript', () => {
1082
1083
// https://github.com/microsoft/vscode/issues/209802
1084
1085
const model = createTextModel([
1086
'if (/*condition*/)',
1087
].join('\n'), languageId, {});
1088
disposables.add(model);
1089
1090
withTestCodeEditor(model, { autoIndent: 'full', serviceCollection }, (editor, viewModel) => {
1091
editor.setSelection(new Selection(1, 19, 1, 19));
1092
viewModel.type('\n', 'keyboard');
1093
assert.strictEqual(model.getValue(), [
1094
'if (/*condition*/)',
1095
' '
1096
].join('\n'));
1097
viewModel.type('{', 'keyboard');
1098
assert.strictEqual(model.getValue(), [
1099
'if (/*condition*/)',
1100
'{}'
1101
].join('\n'));
1102
editor.setSelection(new Selection(2, 2, 2, 2));
1103
viewModel.type('\n', 'keyboard');
1104
assert.strictEqual(model.getValue(), [
1105
'if (/*condition*/)',
1106
'{',
1107
' ',
1108
'}'
1109
].join('\n'));
1110
});
1111
});
1112
1113
// Failing tests...
1114
1115
test.skip('issue #43244: indent after equal sign is detected', () => {
1116
1117
// https://github.com/microsoft/vscode/issues/43244
1118
// issue: Should indent after an equal sign is detected followed by whitespace characters.
1119
// This should be outdented when a semi-colon is detected indicating the end of the assignment.
1120
1121
// TODO: requires exploring indent/outdent pairs instead
1122
1123
const model = createTextModel([
1124
'const array ='
1125
].join('\n'), languageId, {});
1126
disposables.add(model);
1127
1128
withTestCodeEditor(model, { autoIndent: 'full', serviceCollection }, (editor, viewModel) => {
1129
editor.setSelection(new Selection(1, 14, 1, 14));
1130
viewModel.type('\n', 'keyboard');
1131
assert.strictEqual(model.getValue(), [
1132
'const array =',
1133
' '
1134
].join('\n'));
1135
});
1136
});
1137
1138
test.skip('issue #43244: indent after dot detected after object/array signifying a method call', () => {
1139
1140
// https://github.com/microsoft/vscode/issues/43244
1141
// issue: When a dot is written, we should detect that this is a method call and indent accordingly
1142
1143
// TODO: requires exploring indent/outdent pairs instead
1144
1145
const model = createTextModel([
1146
'const array = [1, 2, 3];',
1147
'array.'
1148
].join('\n'), languageId, {});
1149
disposables.add(model);
1150
1151
withTestCodeEditor(model, { autoIndent: 'full', serviceCollection }, (editor, viewModel) => {
1152
editor.setSelection(new Selection(2, 7, 2, 7));
1153
viewModel.type('\n', 'keyboard');
1154
assert.strictEqual(model.getValue(), [
1155
'const array = [1, 2, 3];',
1156
'array.',
1157
' '
1158
].join('\n'));
1159
});
1160
});
1161
1162
test.skip('issue #43244: indent after dot detected on a subsequent line after object/array signifying a method call', () => {
1163
1164
// https://github.com/microsoft/vscode/issues/43244
1165
// issue: When a dot is written, we should detect that this is a method call and indent accordingly
1166
1167
// TODO: requires exploring indent/outdent pairs instead
1168
1169
const model = createTextModel([
1170
'const array = [1, 2, 3]',
1171
].join('\n'), languageId, {});
1172
disposables.add(model);
1173
1174
withTestCodeEditor(model, { autoIndent: 'full', serviceCollection }, (editor, viewModel) => {
1175
editor.setSelection(new Selection(2, 7, 2, 7));
1176
viewModel.type('\n', 'keyboard');
1177
viewModel.type('.');
1178
assert.strictEqual(model.getValue(), [
1179
'const array = [1, 2, 3]',
1180
' .'
1181
].join('\n'));
1182
});
1183
});
1184
1185
test.skip('issue #43244: keep indentation when methods called on object/array', () => {
1186
1187
// https://github.com/microsoft/vscode/issues/43244
1188
// Currently passes, but should pass with all the tests above too
1189
1190
// TODO: requires exploring indent/outdent pairs instead
1191
1192
const model = createTextModel([
1193
'const array = [1, 2, 3]',
1194
' .filter(() => true)'
1195
].join('\n'), languageId, {});
1196
disposables.add(model);
1197
1198
withTestCodeEditor(model, { autoIndent: 'full', serviceCollection }, (editor, viewModel) => {
1199
editor.setSelection(new Selection(2, 24, 2, 24));
1200
viewModel.type('\n', 'keyboard');
1201
assert.strictEqual(model.getValue(), [
1202
'const array = [1, 2, 3]',
1203
' .filter(() => true)',
1204
' '
1205
].join('\n'));
1206
});
1207
});
1208
1209
test.skip('issue #43244: keep indentation when chained methods called on object/array', () => {
1210
1211
// https://github.com/microsoft/vscode/issues/43244
1212
// When the call chain is not finished yet, and we type a dot, we do not want to change the indentation
1213
1214
// TODO: requires exploring indent/outdent pairs instead
1215
1216
const model = createTextModel([
1217
'const array = [1, 2, 3]',
1218
' .filter(() => true)',
1219
' '
1220
].join('\n'), languageId, {});
1221
disposables.add(model);
1222
1223
withTestCodeEditor(model, { autoIndent: 'full', serviceCollection }, (editor, viewModel) => {
1224
editor.setSelection(new Selection(3, 5, 3, 5));
1225
viewModel.type('.');
1226
assert.strictEqual(model.getValue(), [
1227
'const array = [1, 2, 3]',
1228
' .filter(() => true)',
1229
' .' // here we don't want to increase the indentation because we have chained methods
1230
].join('\n'));
1231
});
1232
});
1233
1234
test.skip('issue #43244: outdent when a semi-color is detected indicating the end of the assignment', () => {
1235
1236
// https://github.com/microsoft/vscode/issues/43244
1237
1238
// TODO: requires exploring indent/outdent pairs instead
1239
1240
const model = createTextModel([
1241
'const array = [1, 2, 3]',
1242
' .filter(() => true);'
1243
].join('\n'), languageId, {});
1244
disposables.add(model);
1245
1246
withTestCodeEditor(model, { autoIndent: 'full', serviceCollection }, (editor, viewModel) => {
1247
editor.setSelection(new Selection(2, 25, 2, 25));
1248
viewModel.type('\n', 'keyboard');
1249
assert.strictEqual(model.getValue(), [
1250
'const array = [1, 2, 3]',
1251
' .filter(() => true);',
1252
''
1253
].join('\n'));
1254
});
1255
});
1256
1257
1258
test.skip('issue #40115: keep indentation when added', () => {
1259
1260
// https://github.com/microsoft/vscode/issues/40115
1261
1262
const model = createTextModel('function foo() {}', languageId, {});
1263
disposables.add(model);
1264
1265
withTestCodeEditor(model, { autoIndent: 'full', serviceCollection }, (editor, viewModel) => {
1266
editor.setSelection(new Selection(1, 17, 1, 17));
1267
viewModel.type('\n', 'keyboard');
1268
assert.strictEqual(model.getValue(), [
1269
'function foo() {',
1270
' ',
1271
'}',
1272
].join('\n'));
1273
editor.setSelection(new Selection(2, 5, 2, 5));
1274
viewModel.type('\n', 'keyboard');
1275
assert.strictEqual(model.getValue(), [
1276
'function foo() {',
1277
' ',
1278
' ',
1279
'}',
1280
].join('\n'));
1281
});
1282
});
1283
1284
test.skip('issue #193875: incorrect indentation on enter', () => {
1285
1286
// https://github.com/microsoft/vscode/issues/193875
1287
1288
const model = createTextModel([
1289
'{',
1290
' for(;;)',
1291
' for(;;) {}',
1292
'}',
1293
].join('\n'), languageId, {});
1294
disposables.add(model);
1295
1296
withTestCodeEditor(model, { autoIndent: 'full', serviceCollection }, (editor, viewModel) => {
1297
editor.setSelection(new Selection(3, 14, 3, 14));
1298
viewModel.type('\n', 'keyboard');
1299
assert.strictEqual(model.getValue(), [
1300
'{',
1301
' for(;;)',
1302
' for(;;) {',
1303
' ',
1304
' }',
1305
'}',
1306
].join('\n'));
1307
});
1308
});
1309
1310
test.skip('issue #67678: indent on typing curly brace', () => {
1311
1312
// https://github.com/microsoft/vscode/issues/67678
1313
1314
const model = createTextModel([
1315
'if (true) {',
1316
'console.log("a")',
1317
'console.log("b")',
1318
'',
1319
].join('\n'), languageId, {});
1320
disposables.add(model);
1321
1322
withTestCodeEditor(model, { autoIndent: 'full', serviceCollection }, (editor, viewModel) => {
1323
editor.setSelection(new Selection(4, 1, 4, 1));
1324
viewModel.type('}', 'keyboard');
1325
assert.strictEqual(model.getValue(), [
1326
'if (true) {',
1327
' console.log("a")',
1328
' console.log("b")',
1329
'}',
1330
].join('\n'));
1331
});
1332
});
1333
1334
test.skip('issue #46401: outdent when encountering bracket on line - allman style indentation', () => {
1335
1336
// https://github.com/microsoft/vscode/issues/46401
1337
1338
const model = createTextModel([
1339
'if (true)',
1340
' ',
1341
].join('\n'), languageId, {});
1342
disposables.add(model);
1343
1344
withTestCodeEditor(model, { autoIndent: 'full', serviceCollection }, (editor, viewModel) => {
1345
editor.setSelection(new Selection(2, 5, 2, 5));
1346
viewModel.type('{}', 'keyboard');
1347
assert.strictEqual(model.getValue(), [
1348
'if (true)',
1349
'{}',
1350
].join('\n'));
1351
editor.setSelection(new Selection(2, 2, 2, 2));
1352
viewModel.type('\n', 'keyboard');
1353
assert.strictEqual(model.getValue(), [
1354
'if (true)',
1355
'{',
1356
' ',
1357
'}'
1358
].join('\n'));
1359
});
1360
});
1361
1362
test.skip('issue #125261: typing closing brace does not keep the current indentation', () => {
1363
1364
// https://github.com/microsoft/vscode/issues/125261
1365
1366
const model = createTextModel([
1367
'foo {',
1368
' ',
1369
].join('\n'), languageId, {});
1370
disposables.add(model);
1371
1372
withTestCodeEditor(model, { autoIndent: 'keep', serviceCollection }, (editor, viewModel) => {
1373
editor.setSelection(new Selection(2, 5, 2, 5));
1374
viewModel.type('}', 'keyboard');
1375
assert.strictEqual(model.getValue(), [
1376
'foo {',
1377
'}',
1378
].join('\n'));
1379
});
1380
});
1381
});
1382
1383
suite('Auto Indent On Type - Ruby', () => {
1384
1385
const languageId = Language.Ruby;
1386
let disposables: DisposableStore;
1387
let serviceCollection: ServiceCollection;
1388
1389
setup(() => {
1390
disposables = new DisposableStore();
1391
const languageService = new LanguageService();
1392
const languageConfigurationService = new TestLanguageConfigurationService();
1393
disposables.add(languageService);
1394
disposables.add(languageConfigurationService);
1395
disposables.add(registerLanguage(languageService, languageId));
1396
disposables.add(registerLanguageConfiguration(languageConfigurationService, languageId));
1397
serviceCollection = new ServiceCollection(
1398
[ILanguageService, languageService],
1399
[ILanguageConfigurationService, languageConfigurationService]
1400
);
1401
});
1402
1403
teardown(() => {
1404
disposables.dispose();
1405
});
1406
1407
ensureNoDisposablesAreLeakedInTestSuite();
1408
1409
test('issue #198350: in or when incorrectly match non keywords for Ruby', () => {
1410
1411
// https://github.com/microsoft/vscode/issues/198350
1412
1413
const model = createTextModel('', languageId, {});
1414
disposables.add(model);
1415
1416
withTestCodeEditor(model, { autoIndent: 'full', serviceCollection }, (editor, viewModel) => {
1417
viewModel.type('def foo\n i');
1418
viewModel.type('n', 'keyboard');
1419
assert.strictEqual(model.getValue(), 'def foo\n in');
1420
viewModel.type(' ', 'keyboard');
1421
assert.strictEqual(model.getValue(), 'def foo\nin ');
1422
1423
viewModel.model.setValue('');
1424
viewModel.type(' # in');
1425
assert.strictEqual(model.getValue(), ' # in');
1426
viewModel.type(' ', 'keyboard');
1427
assert.strictEqual(model.getValue(), ' # in ');
1428
});
1429
});
1430
1431
// Failing tests...
1432
1433
test.skip('issue #199846: in or when incorrectly match non keywords for Ruby', () => {
1434
1435
// https://github.com/microsoft/vscode/issues/199846
1436
// explanation: happening because the # is detected probably as a comment
1437
1438
const model = createTextModel('', languageId, {});
1439
disposables.add(model);
1440
1441
withTestCodeEditor(model, { autoIndent: 'full', serviceCollection }, (editor, viewModel) => {
1442
viewModel.type(`method('#foo') do`);
1443
viewModel.type('\n', 'keyboard');
1444
assert.strictEqual(model.getValue(), [
1445
`method('#foo') do`,
1446
' '
1447
].join('\n'));
1448
});
1449
});
1450
});
1451
1452
suite('Auto Indent On Type - PHP', () => {
1453
1454
const languageId = Language.PHP;
1455
let disposables: DisposableStore;
1456
let serviceCollection: ServiceCollection;
1457
1458
setup(() => {
1459
disposables = new DisposableStore();
1460
const languageService = new LanguageService();
1461
const languageConfigurationService = new TestLanguageConfigurationService();
1462
disposables.add(languageService);
1463
disposables.add(languageConfigurationService);
1464
disposables.add(registerLanguage(languageService, languageId));
1465
disposables.add(registerLanguageConfiguration(languageConfigurationService, languageId));
1466
serviceCollection = new ServiceCollection(
1467
[ILanguageService, languageService],
1468
[ILanguageConfigurationService, languageConfigurationService]
1469
);
1470
});
1471
1472
teardown(() => {
1473
disposables.dispose();
1474
});
1475
1476
ensureNoDisposablesAreLeakedInTestSuite();
1477
1478
test('issue #199050: should not indent after { detected in a string', () => {
1479
1480
// https://github.com/microsoft/vscode/issues/199050
1481
1482
const model = createTextModel(`preg_replace('{');`, languageId, {});
1483
disposables.add(model);
1484
1485
withTestCodeEditor(model, { autoIndent: 'full', serviceCollection }, (editor, viewModel, instantiationService) => {
1486
const tokens: StandardTokenTypeData[][] = [
1487
[
1488
{ startIndex: 0, standardTokenType: StandardTokenType.Other },
1489
{ startIndex: 13, standardTokenType: StandardTokenType.String },
1490
{ startIndex: 16, standardTokenType: StandardTokenType.Other },
1491
]
1492
];
1493
disposables.add(registerTokenizationSupport(instantiationService, tokens, languageId));
1494
editor.setSelection(new Selection(1, 54, 1, 54));
1495
viewModel.type('\n', 'keyboard');
1496
assert.strictEqual(model.getValue(), [
1497
`preg_replace('{');`,
1498
''
1499
].join('\n'));
1500
});
1501
});
1502
});
1503
1504
suite('Auto Indent On Paste - Go', () => {
1505
1506
const languageId = Language.Go;
1507
let disposables: DisposableStore;
1508
let serviceCollection: ServiceCollection;
1509
1510
setup(() => {
1511
disposables = new DisposableStore();
1512
const languageService = new LanguageService();
1513
const languageConfigurationService = new TestLanguageConfigurationService();
1514
disposables.add(languageService);
1515
disposables.add(languageConfigurationService);
1516
disposables.add(registerLanguage(languageService, languageId));
1517
disposables.add(registerLanguageConfiguration(languageConfigurationService, languageId));
1518
serviceCollection = new ServiceCollection(
1519
[ILanguageService, languageService],
1520
[ILanguageConfigurationService, languageConfigurationService]
1521
);
1522
});
1523
1524
teardown(() => {
1525
disposables.dispose();
1526
});
1527
1528
ensureNoDisposablesAreLeakedInTestSuite();
1529
1530
test('temp issue because there should be at least one passing test in a suite', () => {
1531
assert.ok(true);
1532
});
1533
1534
test.skip('issue #199050: should not indent after { detected in a string', () => {
1535
1536
// https://github.com/microsoft/vscode/issues/199050
1537
1538
const model = createTextModel([
1539
'var s = `',
1540
'quick brown',
1541
'fox',
1542
'`',
1543
].join('\n'), languageId, {});
1544
disposables.add(model);
1545
1546
withTestCodeEditor(model, { autoIndent: 'full', serviceCollection }, (editor, viewModel) => {
1547
editor.setSelection(new Selection(3, 1, 3, 1));
1548
const text = ' ';
1549
const autoIndentOnPasteController = editor.registerAndInstantiateContribution(AutoIndentOnPaste.ID, AutoIndentOnPaste);
1550
viewModel.paste(text, true, undefined, 'keyboard');
1551
autoIndentOnPasteController.trigger(new Range(3, 1, 3, 3));
1552
assert.strictEqual(model.getValue(), [
1553
'var s = `',
1554
'quick brown',
1555
' fox',
1556
'`',
1557
].join('\n'));
1558
});
1559
});
1560
});
1561
1562
suite('Auto Indent On Type - CPP', () => {
1563
1564
const languageId = Language.CPP;
1565
let disposables: DisposableStore;
1566
let serviceCollection: ServiceCollection;
1567
1568
setup(() => {
1569
disposables = new DisposableStore();
1570
const languageService = new LanguageService();
1571
const languageConfigurationService = new TestLanguageConfigurationService();
1572
disposables.add(languageService);
1573
disposables.add(languageConfigurationService);
1574
disposables.add(registerLanguage(languageService, languageId));
1575
disposables.add(registerLanguageConfiguration(languageConfigurationService, languageId));
1576
serviceCollection = new ServiceCollection(
1577
[ILanguageService, languageService],
1578
[ILanguageConfigurationService, languageConfigurationService]
1579
);
1580
});
1581
1582
teardown(() => {
1583
disposables.dispose();
1584
});
1585
1586
ensureNoDisposablesAreLeakedInTestSuite();
1587
1588
test('temp issue because there should be at least one passing test in a suite', () => {
1589
assert.ok(true);
1590
});
1591
1592
test.skip('issue #178334: incorrect outdent of } when signature spans multiple lines', () => {
1593
1594
// https://github.com/microsoft/vscode/issues/178334
1595
1596
const model = createTextModel([
1597
'int WINAPI WinMain(bool instance,',
1598
' int nshowcmd) {}',
1599
].join('\n'), languageId, {});
1600
disposables.add(model);
1601
1602
withTestCodeEditor(model, { autoIndent: 'full', serviceCollection }, (editor, viewModel) => {
1603
editor.setSelection(new Selection(2, 20, 2, 20));
1604
viewModel.type('\n', 'keyboard');
1605
assert.strictEqual(model.getValue(), [
1606
'int WINAPI WinMain(bool instance,',
1607
' int nshowcmd) {',
1608
' ',
1609
'}'
1610
].join('\n'));
1611
});
1612
});
1613
1614
test.skip('issue #118929: incorrect indent when // follows curly brace', () => {
1615
1616
// https://github.com/microsoft/vscode/issues/118929
1617
1618
const model = createTextModel([
1619
'if (true) { // jaja',
1620
'}',
1621
].join('\n'), languageId, {});
1622
disposables.add(model);
1623
1624
withTestCodeEditor(model, { autoIndent: 'full', serviceCollection }, (editor, viewModel) => {
1625
editor.setSelection(new Selection(1, 20, 1, 20));
1626
viewModel.type('\n', 'keyboard');
1627
assert.strictEqual(model.getValue(), [
1628
'if (true) { // jaja',
1629
' ',
1630
'}',
1631
].join('\n'));
1632
});
1633
});
1634
1635
test.skip('issue #111265: auto indentation set to "none" still changes the indentation', () => {
1636
1637
// https://github.com/microsoft/vscode/issues/111265
1638
1639
const model = createTextModel([
1640
'int func() {',
1641
' ',
1642
].join('\n'), languageId, {});
1643
disposables.add(model);
1644
1645
withTestCodeEditor(model, { autoIndent: 'none', serviceCollection }, (editor, viewModel) => {
1646
editor.setSelection(new Selection(2, 3, 2, 3));
1647
viewModel.type('}', 'keyboard');
1648
assert.strictEqual(model.getValue(), [
1649
'int func() {',
1650
' }',
1651
].join('\n'));
1652
});
1653
});
1654
1655
});
1656
1657
suite('Auto Indent On Type - HTML', () => {
1658
1659
const languageId = Language.HTML;
1660
let disposables: DisposableStore;
1661
let serviceCollection: ServiceCollection;
1662
1663
setup(() => {
1664
disposables = new DisposableStore();
1665
const languageService = new LanguageService();
1666
const languageConfigurationService = new TestLanguageConfigurationService();
1667
disposables.add(languageService);
1668
disposables.add(languageConfigurationService);
1669
disposables.add(registerLanguage(languageService, languageId));
1670
disposables.add(registerLanguageConfiguration(languageConfigurationService, languageId));
1671
serviceCollection = new ServiceCollection(
1672
[ILanguageService, languageService],
1673
[ILanguageConfigurationService, languageConfigurationService]
1674
);
1675
});
1676
1677
teardown(() => {
1678
disposables.dispose();
1679
});
1680
1681
ensureNoDisposablesAreLeakedInTestSuite();
1682
1683
test('temp issue because there should be at least one passing test in a suite', () => {
1684
assert.ok(true);
1685
});
1686
1687
test.skip('issue #61510: incorrect indentation after // in html file', () => {
1688
1689
// https://github.com/microsoft/vscode/issues/178334
1690
1691
const model = createTextModel([
1692
'<pre>',
1693
' foo //I press <Enter> at the end of this line',
1694
'</pre>',
1695
].join('\n'), languageId, {});
1696
disposables.add(model);
1697
1698
withTestCodeEditor(model, { autoIndent: 'full', serviceCollection }, (editor, viewModel) => {
1699
editor.setSelection(new Selection(2, 48, 2, 48));
1700
viewModel.type('\n', 'keyboard');
1701
assert.strictEqual(model.getValue(), [
1702
'<pre>',
1703
' foo //I press <Enter> at the end of this line',
1704
' ',
1705
'</pre>',
1706
].join('\n'));
1707
});
1708
});
1709
});
1710
1711
suite('Auto Indent On Type - Visual Basic', () => {
1712
1713
const languageId = Language.VB;
1714
let disposables: DisposableStore;
1715
let serviceCollection: ServiceCollection;
1716
1717
setup(() => {
1718
disposables = new DisposableStore();
1719
const languageService = new LanguageService();
1720
const languageConfigurationService = new TestLanguageConfigurationService();
1721
disposables.add(languageService);
1722
disposables.add(languageConfigurationService);
1723
disposables.add(registerLanguage(languageService, languageId));
1724
disposables.add(registerLanguageConfiguration(languageConfigurationService, languageId));
1725
serviceCollection = new ServiceCollection(
1726
[ILanguageService, languageService],
1727
[ILanguageConfigurationService, languageConfigurationService]
1728
);
1729
});
1730
1731
teardown(() => {
1732
disposables.dispose();
1733
});
1734
1735
ensureNoDisposablesAreLeakedInTestSuite();
1736
1737
test('temp issue because there should be at least one passing test in a suite', () => {
1738
assert.ok(true);
1739
});
1740
1741
test('issue #118932: no indentation in visual basic files', () => {
1742
1743
// https://github.com/microsoft/vscode/issues/118932
1744
1745
const model = createTextModel([
1746
'If True Then',
1747
' Some code',
1748
' End I',
1749
].join('\n'), languageId, {});
1750
disposables.add(model);
1751
1752
withTestCodeEditor(model, { autoIndent: 'full', serviceCollection }, (editor, viewModel, instantiationService) => {
1753
editor.setSelection(new Selection(3, 10, 3, 10));
1754
viewModel.type('f', 'keyboard');
1755
assert.strictEqual(model.getValue(), [
1756
'If True Then',
1757
' Some code',
1758
'End If',
1759
].join('\n'));
1760
});
1761
});
1762
});
1763
1764
1765
suite('Auto Indent On Type - Latex', () => {
1766
1767
const languageId = Language.Latex;
1768
let disposables: DisposableStore;
1769
let serviceCollection: ServiceCollection;
1770
1771
setup(() => {
1772
disposables = new DisposableStore();
1773
const languageService = new LanguageService();
1774
const languageConfigurationService = new TestLanguageConfigurationService();
1775
disposables.add(languageService);
1776
disposables.add(languageConfigurationService);
1777
disposables.add(registerLanguage(languageService, languageId));
1778
disposables.add(registerLanguageConfiguration(languageConfigurationService, languageId));
1779
serviceCollection = new ServiceCollection(
1780
[ILanguageService, languageService],
1781
[ILanguageConfigurationService, languageConfigurationService]
1782
);
1783
});
1784
1785
teardown(() => {
1786
disposables.dispose();
1787
});
1788
1789
ensureNoDisposablesAreLeakedInTestSuite();
1790
1791
test('temp issue because there should be at least one passing test in a suite', () => {
1792
assert.ok(true);
1793
});
1794
1795
test.skip('issue #178075: no auto closing pair when indentation done', () => {
1796
1797
// https://github.com/microsoft/vscode/issues/178075
1798
1799
const model = createTextModel([
1800
'\\begin{theorem}',
1801
' \\end',
1802
].join('\n'), languageId, {});
1803
disposables.add(model);
1804
1805
withTestCodeEditor(model, { autoIndent: 'full', serviceCollection }, (editor, viewModel) => {
1806
editor.setSelection(new Selection(2, 9, 2, 9));
1807
viewModel.type('{', 'keyboard');
1808
assert.strictEqual(model.getValue(), [
1809
'\\begin{theorem}',
1810
'\\end{}',
1811
].join('\n'));
1812
});
1813
});
1814
});
1815
1816
suite('Auto Indent On Type - Lua', () => {
1817
1818
const languageId = Language.Lua;
1819
let disposables: DisposableStore;
1820
let serviceCollection: ServiceCollection;
1821
1822
setup(() => {
1823
disposables = new DisposableStore();
1824
const languageService = new LanguageService();
1825
const languageConfigurationService = new TestLanguageConfigurationService();
1826
disposables.add(languageService);
1827
disposables.add(languageConfigurationService);
1828
disposables.add(registerLanguage(languageService, languageId));
1829
disposables.add(registerLanguageConfiguration(languageConfigurationService, languageId));
1830
serviceCollection = new ServiceCollection(
1831
[ILanguageService, languageService],
1832
[ILanguageConfigurationService, languageConfigurationService]
1833
);
1834
});
1835
1836
teardown(() => {
1837
disposables.dispose();
1838
});
1839
1840
ensureNoDisposablesAreLeakedInTestSuite();
1841
1842
test('temp issue because there should be at least one passing test in a suite', () => {
1843
assert.ok(true);
1844
});
1845
1846
test.skip('issue #178075: no auto closing pair when indentation done', () => {
1847
1848
// https://github.com/microsoft/vscode/issues/178075
1849
1850
const model = createTextModel([
1851
'print("asdf function asdf")',
1852
].join('\n'), languageId, {});
1853
disposables.add(model);
1854
1855
withTestCodeEditor(model, { autoIndent: 'full', serviceCollection }, (editor, viewModel) => {
1856
editor.setSelection(new Selection(1, 28, 1, 28));
1857
viewModel.type('\n', 'keyboard');
1858
assert.strictEqual(model.getValue(), [
1859
'print("asdf function asdf")',
1860
''
1861
].join('\n'));
1862
});
1863
});
1864
});
1865
1866