Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/api/test/browser/extHostEditorTabs.test.ts
3296 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import type * as vscode from 'vscode';
7
import assert from 'assert';
8
import { URI } from '../../../../base/common/uri.js';
9
import { mock } from '../../../../base/test/common/mock.js';
10
import { IEditorTabDto, IEditorTabGroupDto, MainThreadEditorTabsShape, TabInputKind, TabModelOperationKind, TextInputDto } from '../../common/extHost.protocol.js';
11
import { ExtHostEditorTabs } from '../../common/extHostEditorTabs.js';
12
import { SingleProxyRPCProtocol } from '../common/testRPCProtocol.js';
13
import { TextMergeTabInput, TextTabInput } from '../../common/extHostTypes.js';
14
import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../base/test/common/utils.js';
15
16
suite('ExtHostEditorTabs', function () {
17
18
const defaultTabDto: IEditorTabDto = {
19
id: 'uniquestring',
20
input: { kind: TabInputKind.TextInput, uri: URI.parse('file://abc/def.txt') },
21
isActive: true,
22
isDirty: true,
23
isPinned: true,
24
isPreview: false,
25
label: 'label1',
26
};
27
28
function createTabDto(dto?: Partial<IEditorTabDto>): IEditorTabDto {
29
return { ...defaultTabDto, ...dto };
30
}
31
32
const store = ensureNoDisposablesAreLeakedInTestSuite();
33
34
test('Ensure empty model throws when accessing active group', function () {
35
const extHostEditorTabs = new ExtHostEditorTabs(
36
SingleProxyRPCProtocol(new class extends mock<MainThreadEditorTabsShape>() {
37
// override/implement $moveTab or $closeTab
38
})
39
);
40
41
assert.strictEqual(extHostEditorTabs.tabGroups.all.length, 0);
42
// Active group should never be undefined (there is always an active group). Ensure accessing it undefined throws.
43
// TODO @lramos15 Add a throw on the main side when a model is sent without an active group
44
assert.throws(() => extHostEditorTabs.tabGroups.activeTabGroup);
45
});
46
47
test('single tab', function () {
48
49
const extHostEditorTabs = new ExtHostEditorTabs(
50
SingleProxyRPCProtocol(new class extends mock<MainThreadEditorTabsShape>() {
51
// override/implement $moveTab or $closeTab
52
})
53
);
54
55
const tab: IEditorTabDto = createTabDto({
56
id: 'uniquestring',
57
isActive: true,
58
isDirty: true,
59
isPinned: true,
60
label: 'label1',
61
});
62
63
extHostEditorTabs.$acceptEditorTabModel([{
64
isActive: true,
65
viewColumn: 0,
66
groupId: 12,
67
tabs: [tab]
68
}]);
69
assert.strictEqual(extHostEditorTabs.tabGroups.all.length, 1);
70
const [first] = extHostEditorTabs.tabGroups.all;
71
assert.ok(first.activeTab);
72
assert.strictEqual(first.tabs.indexOf(first.activeTab), 0);
73
74
{
75
extHostEditorTabs.$acceptEditorTabModel([{
76
isActive: true,
77
viewColumn: 0,
78
groupId: 12,
79
tabs: [tab]
80
}]);
81
assert.strictEqual(extHostEditorTabs.tabGroups.all.length, 1);
82
const [first] = extHostEditorTabs.tabGroups.all;
83
assert.ok(first.activeTab);
84
assert.strictEqual(first.tabs.indexOf(first.activeTab), 0);
85
}
86
});
87
88
test('Empty tab group', function () {
89
const extHostEditorTabs = new ExtHostEditorTabs(
90
SingleProxyRPCProtocol(new class extends mock<MainThreadEditorTabsShape>() {
91
// override/implement $moveTab or $closeTab
92
})
93
);
94
95
extHostEditorTabs.$acceptEditorTabModel([{
96
isActive: true,
97
viewColumn: 0,
98
groupId: 12,
99
tabs: []
100
}]);
101
assert.strictEqual(extHostEditorTabs.tabGroups.all.length, 1);
102
const [first] = extHostEditorTabs.tabGroups.all;
103
assert.strictEqual(first.activeTab, undefined);
104
assert.strictEqual(first.tabs.length, 0);
105
});
106
107
test('Ensure tabGroup change events fires', function () {
108
const extHostEditorTabs = new ExtHostEditorTabs(
109
SingleProxyRPCProtocol(new class extends mock<MainThreadEditorTabsShape>() {
110
// override/implement $moveTab or $closeTab
111
})
112
);
113
114
let count = 0;
115
store.add(extHostEditorTabs.tabGroups.onDidChangeTabGroups(() => count++));
116
117
assert.strictEqual(count, 0);
118
119
extHostEditorTabs.$acceptEditorTabModel([{
120
isActive: true,
121
viewColumn: 0,
122
groupId: 12,
123
tabs: []
124
}]);
125
assert.ok(extHostEditorTabs.tabGroups.activeTabGroup);
126
const activeTabGroup: vscode.TabGroup = extHostEditorTabs.tabGroups.activeTabGroup;
127
assert.strictEqual(extHostEditorTabs.tabGroups.all.length, 1);
128
assert.strictEqual(activeTabGroup.tabs.length, 0);
129
assert.strictEqual(count, 1);
130
});
131
132
test('Check TabGroupChangeEvent properties', function () {
133
const extHostEditorTabs = new ExtHostEditorTabs(
134
SingleProxyRPCProtocol(new class extends mock<MainThreadEditorTabsShape>() {
135
// override/implement $moveTab or $closeTab
136
})
137
);
138
139
const group1Data: IEditorTabGroupDto = {
140
isActive: true,
141
viewColumn: 0,
142
groupId: 12,
143
tabs: []
144
};
145
const group2Data: IEditorTabGroupDto = { ...group1Data, groupId: 13 };
146
147
const events: vscode.TabGroupChangeEvent[] = [];
148
store.add(extHostEditorTabs.tabGroups.onDidChangeTabGroups(e => events.push(e)));
149
// OPEN
150
extHostEditorTabs.$acceptEditorTabModel([group1Data]);
151
assert.deepStrictEqual(events, [{
152
changed: [],
153
closed: [],
154
opened: [extHostEditorTabs.tabGroups.activeTabGroup]
155
}]);
156
157
// OPEN, CHANGE
158
events.length = 0;
159
extHostEditorTabs.$acceptEditorTabModel([{ ...group1Data, isActive: false }, group2Data]);
160
assert.deepStrictEqual(events, [{
161
changed: [extHostEditorTabs.tabGroups.all[0]],
162
closed: [],
163
opened: [extHostEditorTabs.tabGroups.all[1]]
164
}]);
165
166
// CHANGE
167
events.length = 0;
168
extHostEditorTabs.$acceptEditorTabModel([group1Data, { ...group2Data, isActive: false }]);
169
assert.deepStrictEqual(events, [{
170
changed: extHostEditorTabs.tabGroups.all,
171
closed: [],
172
opened: []
173
}]);
174
175
// CLOSE, CHANGE
176
events.length = 0;
177
const oldActiveGroup = extHostEditorTabs.tabGroups.activeTabGroup;
178
extHostEditorTabs.$acceptEditorTabModel([group2Data]);
179
assert.deepStrictEqual(events, [{
180
changed: extHostEditorTabs.tabGroups.all,
181
closed: [oldActiveGroup],
182
opened: []
183
}]);
184
});
185
186
test('Ensure reference equality for activeTab and activeGroup', function () {
187
const extHostEditorTabs = new ExtHostEditorTabs(
188
SingleProxyRPCProtocol(new class extends mock<MainThreadEditorTabsShape>() {
189
// override/implement $moveTab or $closeTab
190
})
191
);
192
const tab = createTabDto({
193
id: 'uniquestring',
194
isActive: true,
195
isDirty: true,
196
isPinned: true,
197
label: 'label1',
198
editorId: 'default',
199
});
200
201
extHostEditorTabs.$acceptEditorTabModel([{
202
isActive: true,
203
viewColumn: 0,
204
groupId: 12,
205
tabs: [tab]
206
}]);
207
assert.strictEqual(extHostEditorTabs.tabGroups.all.length, 1);
208
const [first] = extHostEditorTabs.tabGroups.all;
209
assert.ok(first.activeTab);
210
assert.strictEqual(first.tabs.indexOf(first.activeTab), 0);
211
assert.strictEqual(first.activeTab, first.tabs[0]);
212
assert.strictEqual(extHostEditorTabs.tabGroups.activeTabGroup, first);
213
});
214
215
test('TextMergeTabInput surfaces in the UI', function () {
216
217
const extHostEditorTabs = new ExtHostEditorTabs(
218
SingleProxyRPCProtocol(new class extends mock<MainThreadEditorTabsShape>() {
219
// override/implement $moveTab or $closeTab
220
})
221
);
222
223
const tab: IEditorTabDto = createTabDto({
224
input: {
225
kind: TabInputKind.TextMergeInput,
226
base: URI.from({ scheme: 'test', path: 'base' }),
227
input1: URI.from({ scheme: 'test', path: 'input1' }),
228
input2: URI.from({ scheme: 'test', path: 'input2' }),
229
result: URI.from({ scheme: 'test', path: 'result' }),
230
}
231
});
232
233
extHostEditorTabs.$acceptEditorTabModel([{
234
isActive: true,
235
viewColumn: 0,
236
groupId: 12,
237
tabs: [tab]
238
}]);
239
assert.strictEqual(extHostEditorTabs.tabGroups.all.length, 1);
240
const [first] = extHostEditorTabs.tabGroups.all;
241
assert.ok(first.activeTab);
242
assert.strictEqual(first.tabs.indexOf(first.activeTab), 0);
243
assert.ok(first.activeTab.input instanceof TextMergeTabInput);
244
});
245
246
test('Ensure reference stability', function () {
247
248
const extHostEditorTabs = new ExtHostEditorTabs(
249
SingleProxyRPCProtocol(new class extends mock<MainThreadEditorTabsShape>() {
250
// override/implement $moveTab or $closeTab
251
})
252
);
253
const tabDto = createTabDto();
254
255
// single dirty tab
256
257
extHostEditorTabs.$acceptEditorTabModel([{
258
isActive: true,
259
viewColumn: 0,
260
groupId: 12,
261
tabs: [tabDto]
262
}]);
263
let all = extHostEditorTabs.tabGroups.all.map(group => group.tabs).flat();
264
assert.strictEqual(all.length, 1);
265
const apiTab1 = all[0];
266
assert.ok(apiTab1.input instanceof TextTabInput);
267
assert.strictEqual(tabDto.input.kind, TabInputKind.TextInput);
268
const dtoResource = (tabDto.input as TextInputDto).uri;
269
assert.strictEqual(apiTab1.input.uri.toString(), URI.revive(dtoResource).toString());
270
assert.strictEqual(apiTab1.isDirty, true);
271
272
273
// NOT DIRTY anymore
274
275
const tabDto2: IEditorTabDto = { ...tabDto, isDirty: false };
276
// Accept a simple update
277
extHostEditorTabs.$acceptTabOperation({
278
kind: TabModelOperationKind.TAB_UPDATE,
279
index: 0,
280
tabDto: tabDto2,
281
groupId: 12
282
});
283
284
all = extHostEditorTabs.tabGroups.all.map(group => group.tabs).flat();
285
assert.strictEqual(all.length, 1);
286
const apiTab2 = all[0];
287
assert.ok(apiTab1.input instanceof TextTabInput);
288
assert.strictEqual(apiTab1.input.uri.toString(), URI.revive(dtoResource).toString());
289
assert.strictEqual(apiTab2.isDirty, false);
290
291
assert.strictEqual(apiTab1 === apiTab2, true);
292
});
293
294
test('Tab.isActive working', function () {
295
296
const extHostEditorTabs = new ExtHostEditorTabs(
297
SingleProxyRPCProtocol(new class extends mock<MainThreadEditorTabsShape>() {
298
// override/implement $moveTab or $closeTab
299
})
300
);
301
const tabDtoAAA = createTabDto({
302
id: 'AAA',
303
isActive: true,
304
isDirty: true,
305
isPinned: true,
306
label: 'label1',
307
input: { kind: TabInputKind.TextInput, uri: URI.parse('file://abc/AAA.txt') },
308
editorId: 'default'
309
});
310
311
const tabDtoBBB = createTabDto({
312
id: 'BBB',
313
isActive: false,
314
isDirty: true,
315
isPinned: true,
316
label: 'label1',
317
input: { kind: TabInputKind.TextInput, uri: URI.parse('file://abc/BBB.txt') },
318
editorId: 'default'
319
});
320
321
// single dirty tab
322
323
extHostEditorTabs.$acceptEditorTabModel([{
324
isActive: true,
325
viewColumn: 0,
326
groupId: 12,
327
tabs: [tabDtoAAA, tabDtoBBB]
328
}]);
329
330
const all = extHostEditorTabs.tabGroups.all.map(group => group.tabs).flat();
331
assert.strictEqual(all.length, 2);
332
333
const activeTab1 = extHostEditorTabs.tabGroups.activeTabGroup?.activeTab;
334
assert.ok(activeTab1?.input instanceof TextTabInput);
335
assert.strictEqual(tabDtoAAA.input.kind, TabInputKind.TextInput);
336
const dtoAAAResource = (tabDtoAAA.input as TextInputDto).uri;
337
assert.strictEqual(activeTab1?.input?.uri.toString(), URI.revive(dtoAAAResource)?.toString());
338
assert.strictEqual(activeTab1?.isActive, true);
339
340
extHostEditorTabs.$acceptTabOperation({
341
groupId: 12,
342
index: 1,
343
kind: TabModelOperationKind.TAB_UPDATE,
344
tabDto: { ...tabDtoBBB, isActive: true } /// BBB is now active
345
});
346
347
const activeTab2 = extHostEditorTabs.tabGroups.activeTabGroup?.activeTab;
348
assert.ok(activeTab2?.input instanceof TextTabInput);
349
assert.strictEqual(tabDtoBBB.input.kind, TabInputKind.TextInput);
350
const dtoBBBResource = (tabDtoBBB.input as TextInputDto).uri;
351
assert.strictEqual(activeTab2?.input?.uri.toString(), URI.revive(dtoBBBResource)?.toString());
352
assert.strictEqual(activeTab2?.isActive, true);
353
assert.strictEqual(activeTab1?.isActive, false);
354
});
355
356
test('vscode.window.tagGroups is immutable', function () {
357
358
const extHostEditorTabs = new ExtHostEditorTabs(
359
SingleProxyRPCProtocol(new class extends mock<MainThreadEditorTabsShape>() {
360
// override/implement $moveTab or $closeTab
361
})
362
);
363
364
assert.throws(() => {
365
// @ts-expect-error write to readonly prop
366
extHostEditorTabs.tabGroups.activeTabGroup = undefined;
367
});
368
assert.throws(() => {
369
// @ts-expect-error write to readonly prop
370
extHostEditorTabs.tabGroups.all.length = 0;
371
});
372
assert.throws(() => {
373
// @ts-expect-error write to readonly prop
374
extHostEditorTabs.tabGroups.onDidChangeActiveTabGroup = undefined;
375
});
376
assert.throws(() => {
377
// @ts-expect-error write to readonly prop
378
extHostEditorTabs.tabGroups.onDidChangeTabGroups = undefined;
379
});
380
});
381
382
test('Ensure close is called with all tab ids', function () {
383
const closedTabIds: string[][] = [];
384
const extHostEditorTabs = new ExtHostEditorTabs(
385
SingleProxyRPCProtocol(new class extends mock<MainThreadEditorTabsShape>() {
386
// override/implement $moveTab or $closeTab
387
override async $closeTab(tabIds: string[], preserveFocus?: boolean) {
388
closedTabIds.push(tabIds);
389
return true;
390
}
391
})
392
);
393
const tab: IEditorTabDto = createTabDto({
394
id: 'uniquestring',
395
isActive: true,
396
isDirty: true,
397
isPinned: true,
398
label: 'label1',
399
editorId: 'default'
400
});
401
402
extHostEditorTabs.$acceptEditorTabModel([{
403
isActive: true,
404
viewColumn: 0,
405
groupId: 12,
406
tabs: [tab]
407
}]);
408
assert.strictEqual(extHostEditorTabs.tabGroups.all.length, 1);
409
const activeTab = extHostEditorTabs.tabGroups.activeTabGroup?.activeTab;
410
assert.ok(activeTab);
411
extHostEditorTabs.tabGroups.close(activeTab, false);
412
assert.strictEqual(closedTabIds.length, 1);
413
assert.deepStrictEqual(closedTabIds[0], ['uniquestring']);
414
// Close with array
415
extHostEditorTabs.tabGroups.close([activeTab], false);
416
assert.strictEqual(closedTabIds.length, 2);
417
assert.deepStrictEqual(closedTabIds[1], ['uniquestring']);
418
});
419
420
test('Update tab only sends tab change event', async function () {
421
const closedTabIds: string[][] = [];
422
const extHostEditorTabs = new ExtHostEditorTabs(
423
SingleProxyRPCProtocol(new class extends mock<MainThreadEditorTabsShape>() {
424
// override/implement $moveTab or $closeTab
425
override async $closeTab(tabIds: string[], preserveFocus?: boolean) {
426
closedTabIds.push(tabIds);
427
return true;
428
}
429
})
430
);
431
const tabDto: IEditorTabDto = createTabDto({
432
id: 'uniquestring',
433
isActive: true,
434
isDirty: true,
435
isPinned: true,
436
label: 'label1',
437
editorId: 'default'
438
});
439
440
extHostEditorTabs.$acceptEditorTabModel([{
441
isActive: true,
442
viewColumn: 0,
443
groupId: 12,
444
tabs: [tabDto]
445
}]);
446
447
assert.strictEqual(extHostEditorTabs.tabGroups.all.length, 1);
448
assert.strictEqual(extHostEditorTabs.tabGroups.all.map(g => g.tabs).flat().length, 1);
449
450
const tab = extHostEditorTabs.tabGroups.all[0].tabs[0];
451
452
453
const p = new Promise<vscode.TabChangeEvent>(resolve => store.add(extHostEditorTabs.tabGroups.onDidChangeTabs(resolve)));
454
455
extHostEditorTabs.$acceptTabOperation({
456
groupId: 12,
457
index: 0,
458
kind: TabModelOperationKind.TAB_UPDATE,
459
tabDto: { ...tabDto, label: 'NEW LABEL' }
460
});
461
462
const changedTab = (await p).changed[0];
463
464
assert.ok(tab === changedTab);
465
assert.strictEqual(changedTab.label, 'NEW LABEL');
466
467
});
468
469
test('Active tab', function () {
470
471
const extHostEditorTabs = new ExtHostEditorTabs(
472
SingleProxyRPCProtocol(new class extends mock<MainThreadEditorTabsShape>() {
473
// override/implement $moveTab or $closeTab
474
})
475
);
476
477
const tab1: IEditorTabDto = createTabDto({
478
id: 'uniquestring',
479
isActive: true,
480
isDirty: true,
481
isPinned: true,
482
label: 'label1',
483
});
484
485
const tab2: IEditorTabDto = createTabDto({
486
isActive: false,
487
id: 'uniquestring2',
488
});
489
490
const tab3: IEditorTabDto = createTabDto({
491
isActive: false,
492
id: 'uniquestring3',
493
});
494
495
extHostEditorTabs.$acceptEditorTabModel([{
496
isActive: true,
497
viewColumn: 0,
498
groupId: 12,
499
tabs: [tab1, tab2, tab3]
500
}]);
501
502
assert.strictEqual(extHostEditorTabs.tabGroups.all.length, 1);
503
assert.strictEqual(extHostEditorTabs.tabGroups.all.map(g => g.tabs).flat().length, 3);
504
505
// Active tab is correct
506
assert.strictEqual(extHostEditorTabs.tabGroups.activeTabGroup?.activeTab, extHostEditorTabs.tabGroups.activeTabGroup?.tabs[0]);
507
508
// Switching active tab works
509
tab1.isActive = false;
510
tab2.isActive = true;
511
extHostEditorTabs.$acceptTabOperation({
512
groupId: 12,
513
index: 0,
514
kind: TabModelOperationKind.TAB_UPDATE,
515
tabDto: tab1
516
});
517
extHostEditorTabs.$acceptTabOperation({
518
groupId: 12,
519
index: 1,
520
kind: TabModelOperationKind.TAB_UPDATE,
521
tabDto: tab2
522
});
523
assert.strictEqual(extHostEditorTabs.tabGroups.activeTabGroup?.activeTab, extHostEditorTabs.tabGroups.activeTabGroup?.tabs[1]);
524
525
//Closing tabs out works
526
tab3.isActive = true;
527
extHostEditorTabs.$acceptEditorTabModel([{
528
isActive: true,
529
viewColumn: 0,
530
groupId: 12,
531
tabs: [tab3]
532
}]);
533
assert.strictEqual(extHostEditorTabs.tabGroups.all.length, 1);
534
assert.strictEqual(extHostEditorTabs.tabGroups.all.map(g => g.tabs).flat().length, 1);
535
assert.strictEqual(extHostEditorTabs.tabGroups.activeTabGroup?.activeTab, extHostEditorTabs.tabGroups.activeTabGroup?.tabs[0]);
536
537
// Closing out all tabs returns undefine active tab
538
extHostEditorTabs.$acceptEditorTabModel([{
539
isActive: true,
540
viewColumn: 0,
541
groupId: 12,
542
tabs: []
543
}]);
544
assert.strictEqual(extHostEditorTabs.tabGroups.all.length, 1);
545
assert.strictEqual(extHostEditorTabs.tabGroups.all.map(g => g.tabs).flat().length, 0);
546
assert.strictEqual(extHostEditorTabs.tabGroups.activeTabGroup?.activeTab, undefined);
547
});
548
549
test('Tab operations patches open and close correctly', function () {
550
const extHostEditorTabs = new ExtHostEditorTabs(
551
SingleProxyRPCProtocol(new class extends mock<MainThreadEditorTabsShape>() {
552
// override/implement $moveTab or $closeTab
553
})
554
);
555
556
const tab1: IEditorTabDto = createTabDto({
557
id: 'uniquestring',
558
isActive: true,
559
label: 'label1',
560
});
561
562
const tab2: IEditorTabDto = createTabDto({
563
isActive: false,
564
id: 'uniquestring2',
565
label: 'label2',
566
});
567
568
const tab3: IEditorTabDto = createTabDto({
569
isActive: false,
570
id: 'uniquestring3',
571
label: 'label3',
572
});
573
574
extHostEditorTabs.$acceptEditorTabModel([{
575
isActive: true,
576
viewColumn: 0,
577
groupId: 12,
578
tabs: [tab1, tab2, tab3]
579
}]);
580
581
assert.strictEqual(extHostEditorTabs.tabGroups.all.length, 1);
582
assert.strictEqual(extHostEditorTabs.tabGroups.all.map(g => g.tabs).flat().length, 3);
583
584
// Close tab 2
585
extHostEditorTabs.$acceptTabOperation({
586
groupId: 12,
587
index: 1,
588
kind: TabModelOperationKind.TAB_CLOSE,
589
tabDto: tab2
590
});
591
assert.strictEqual(extHostEditorTabs.tabGroups.all.length, 1);
592
assert.strictEqual(extHostEditorTabs.tabGroups.all.map(g => g.tabs).flat().length, 2);
593
594
// Close active tab and update tab 3 to be active
595
extHostEditorTabs.$acceptTabOperation({
596
groupId: 12,
597
index: 0,
598
kind: TabModelOperationKind.TAB_CLOSE,
599
tabDto: tab1
600
});
601
assert.strictEqual(extHostEditorTabs.tabGroups.all.length, 1);
602
assert.strictEqual(extHostEditorTabs.tabGroups.all.map(g => g.tabs).flat().length, 1);
603
tab3.isActive = true;
604
extHostEditorTabs.$acceptTabOperation({
605
groupId: 12,
606
index: 0,
607
kind: TabModelOperationKind.TAB_UPDATE,
608
tabDto: tab3
609
});
610
assert.strictEqual(extHostEditorTabs.tabGroups.all.length, 1);
611
assert.strictEqual(extHostEditorTabs.tabGroups.all.map(g => g.tabs).flat().length, 1);
612
assert.strictEqual(extHostEditorTabs.tabGroups.all[0]?.activeTab?.label, 'label3');
613
614
// Open tab 2 back
615
extHostEditorTabs.$acceptTabOperation({
616
groupId: 12,
617
index: 1,
618
kind: TabModelOperationKind.TAB_OPEN,
619
tabDto: tab2
620
});
621
assert.strictEqual(extHostEditorTabs.tabGroups.all.length, 1);
622
assert.strictEqual(extHostEditorTabs.tabGroups.all.map(g => g.tabs).flat().length, 2);
623
assert.strictEqual(extHostEditorTabs.tabGroups.all[0]?.tabs[1]?.label, 'label2');
624
});
625
626
test('Tab operations patches move correctly', function () {
627
const extHostEditorTabs = new ExtHostEditorTabs(
628
SingleProxyRPCProtocol(new class extends mock<MainThreadEditorTabsShape>() {
629
// override/implement $moveTab or $closeTab
630
})
631
);
632
633
const tab1: IEditorTabDto = createTabDto({
634
id: 'uniquestring',
635
isActive: true,
636
label: 'label1',
637
});
638
639
const tab2: IEditorTabDto = createTabDto({
640
isActive: false,
641
id: 'uniquestring2',
642
label: 'label2',
643
});
644
645
const tab3: IEditorTabDto = createTabDto({
646
isActive: false,
647
id: 'uniquestring3',
648
label: 'label3',
649
});
650
651
extHostEditorTabs.$acceptEditorTabModel([{
652
isActive: true,
653
viewColumn: 0,
654
groupId: 12,
655
tabs: [tab1, tab2, tab3]
656
}]);
657
658
assert.strictEqual(extHostEditorTabs.tabGroups.all.length, 1);
659
assert.strictEqual(extHostEditorTabs.tabGroups.all.map(g => g.tabs).flat().length, 3);
660
661
// Move tab 2 to index 0
662
extHostEditorTabs.$acceptTabOperation({
663
groupId: 12,
664
index: 0,
665
oldIndex: 1,
666
kind: TabModelOperationKind.TAB_MOVE,
667
tabDto: tab2
668
});
669
assert.strictEqual(extHostEditorTabs.tabGroups.all.length, 1);
670
assert.strictEqual(extHostEditorTabs.tabGroups.all.map(g => g.tabs).flat().length, 3);
671
assert.strictEqual(extHostEditorTabs.tabGroups.all[0]?.tabs[0]?.label, 'label2');
672
673
// Move tab 3 to index 1
674
extHostEditorTabs.$acceptTabOperation({
675
groupId: 12,
676
index: 1,
677
oldIndex: 2,
678
kind: TabModelOperationKind.TAB_MOVE,
679
tabDto: tab3
680
});
681
assert.strictEqual(extHostEditorTabs.tabGroups.all.length, 1);
682
assert.strictEqual(extHostEditorTabs.tabGroups.all.map(g => g.tabs).flat().length, 3);
683
assert.strictEqual(extHostEditorTabs.tabGroups.all[0]?.tabs[1]?.label, 'label3');
684
assert.strictEqual(extHostEditorTabs.tabGroups.all[0]?.tabs[0]?.label, 'label2');
685
assert.strictEqual(extHostEditorTabs.tabGroups.all[0]?.tabs[2]?.label, 'label1');
686
});
687
});
688
689