@lvce-editor/main-area-worker 9.11.0 → 9.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -118,579 +118,255 @@ const terminate = () => {
118
118
  globalThis.close();
119
119
  };
120
120
 
121
- const getGroupIndexById = (state, groupId) => {
122
- const {
123
- layout
124
- } = state;
125
- const {
126
- groups
127
- } = layout;
128
- return groups.findIndex(group => group.id === groupId);
129
- };
130
-
131
- const redistributeSizesWithRounding = groups => {
132
- return groups.map(group => ({
133
- ...group,
134
- size: Math.round(100 / groups.length)
135
- }));
136
- };
137
-
138
- const withGroupsAndActiveGroup = (state, groups, activeGroupId) => {
139
- return {
140
- ...state,
141
- layout: {
142
- ...state.layout,
143
- activeGroupId,
144
- groups
145
- }
146
- };
121
+ const normalizeLine = line => {
122
+ if (line.startsWith('Error: ')) {
123
+ return line.slice('Error: '.length);
124
+ }
125
+ if (line.startsWith('VError: ')) {
126
+ return line.slice('VError: '.length);
127
+ }
128
+ return line;
147
129
  };
148
-
149
- const withEmptyGroups = state => {
150
- return withGroupsAndActiveGroup(state, [], undefined);
130
+ const getCombinedMessage = (error, message) => {
131
+ const stringifiedError = normalizeLine(`${error}`);
132
+ if (message) {
133
+ return `${message}: ${stringifiedError}`;
134
+ }
135
+ return stringifiedError;
151
136
  };
152
-
153
- const withGroups = (state, groups) => {
154
- return {
155
- ...state,
156
- layout: {
157
- ...state.layout,
158
- groups
159
- }
160
- };
137
+ const NewLine$2 = '\n';
138
+ const getNewLineIndex$1 = (string, startIndex = undefined) => {
139
+ return string.indexOf(NewLine$2, startIndex);
161
140
  };
162
-
163
- const closeTab = (state, groupId, tabId) => {
164
- const {
165
- activeGroupId,
166
- groups
167
- } = state.layout;
168
-
169
- // Find the group to close the tab from
170
- const groupIndex = getGroupIndexById(state, groupId);
171
- if (groupIndex === -1) {
172
- return state;
141
+ const mergeStacks = (parent, child) => {
142
+ if (!child) {
143
+ return parent;
173
144
  }
174
- const group = groups[groupIndex];
175
- // Check if the tab exists in the group
176
- const tabWasRemoved = group.tabs.some(tab => tab.id === tabId);
177
- if (!tabWasRemoved) {
178
- return state;
145
+ const parentNewLineIndex = getNewLineIndex$1(parent);
146
+ const childNewLineIndex = getNewLineIndex$1(child);
147
+ if (childNewLineIndex === -1) {
148
+ return parent;
179
149
  }
180
- const newGroups = groups.map(grp => {
181
- if (grp.id === groupId) {
182
- const newTabs = grp.tabs.filter(tab => tab.id !== tabId);
183
- let newActiveTabId = grp.activeTabId;
184
- if (grp.activeTabId === tabId) {
185
- const tabIndex = grp.tabs.findIndex(tab => tab.id === tabId);
186
- if (newTabs.length > 0) {
187
- newActiveTabId = newTabs[Math.min(tabIndex, newTabs.length - 1)].id;
188
- } else {
189
- newActiveTabId = undefined;
190
- }
191
- }
192
- return {
193
- ...grp,
194
- activeTabId: newActiveTabId,
195
- isEmpty: newTabs.length === 0,
196
- tabs: newTabs
197
- };
150
+ const parentFirstLine = parent.slice(0, parentNewLineIndex);
151
+ const childRest = child.slice(childNewLineIndex);
152
+ const childFirstLine = normalizeLine(child.slice(0, childNewLineIndex));
153
+ if (parentFirstLine.includes(childFirstLine)) {
154
+ return parentFirstLine + childRest;
155
+ }
156
+ return child;
157
+ };
158
+ class VError extends Error {
159
+ constructor(error, message) {
160
+ const combinedMessage = getCombinedMessage(error, message);
161
+ super(combinedMessage);
162
+ this.name = 'VError';
163
+ if (error instanceof Error) {
164
+ this.stack = mergeStacks(this.stack, error.stack);
198
165
  }
199
- return grp;
200
- });
201
-
202
- // If the group has no tabs left after closing, remove the group
203
- const groupIsNowEmpty = newGroups[groupIndex].tabs.length === 0;
204
- if (groupIsNowEmpty) {
205
- const remainingGroups = newGroups.filter(group => group.id !== groupId);
206
-
207
- // If there are remaining groups, redistribute sizes
208
- if (remainingGroups.length > 0) {
209
- const redistributedGroups = redistributeSizesWithRounding(remainingGroups);
210
- const newActiveGroupId = activeGroupId === groupId ? remainingGroups[0]?.id : activeGroupId;
211
- return withGroupsAndActiveGroup(state, redistributedGroups, newActiveGroupId);
166
+ if (error.codeFrame) {
167
+ // @ts-ignore
168
+ this.codeFrame = error.codeFrame;
169
+ }
170
+ if (error.code) {
171
+ // @ts-ignore
172
+ this.code = error.code;
212
173
  }
213
-
214
- // If no remaining groups, return empty layout
215
- return withEmptyGroups(state);
216
174
  }
217
- return withGroups(state, newGroups);
218
- };
219
-
220
- const getFocusedGroup = state => {
221
- const {
222
- layout
223
- } = state;
224
- const {
225
- groups
226
- } = layout;
227
- return groups.find(group => group.focused);
228
- };
175
+ }
229
176
 
230
- const closeActiveEditor = state => {
231
- const focusedGroup = getFocusedGroup(state);
232
- if (!focusedGroup) {
233
- return state;
177
+ class AssertionError extends Error {
178
+ constructor(message) {
179
+ super(message);
180
+ this.name = 'AssertionError';
234
181
  }
235
- const {
236
- activeTabId
237
- } = focusedGroup;
238
- if (activeTabId === undefined) {
239
- return state;
182
+ }
183
+ const Object$1 = 1;
184
+ const Number$1 = 2;
185
+ const Array$1 = 3;
186
+ const String$1 = 4;
187
+ const Boolean$1 = 5;
188
+ const Function = 6;
189
+ const Null = 7;
190
+ const Unknown = 8;
191
+ const getType = value => {
192
+ switch (typeof value) {
193
+ case 'number':
194
+ return Number$1;
195
+ case 'function':
196
+ return Function;
197
+ case 'string':
198
+ return String$1;
199
+ case 'object':
200
+ if (value === null) {
201
+ return Null;
202
+ }
203
+ if (Array.isArray(value)) {
204
+ return Array$1;
205
+ }
206
+ return Object$1;
207
+ case 'boolean':
208
+ return Boolean$1;
209
+ default:
210
+ return Unknown;
240
211
  }
241
- return closeTab(state, focusedGroup.id, activeTabId);
242
- };
243
-
244
- const closeAll$1 = state => {
245
- return withEmptyGroups(state);
246
212
  };
247
-
248
- const redistributeSizesWithRemainder = groups => {
249
- const baseSize = Math.floor(100 / groups.length);
250
- const remainder = 100 % groups.length;
251
- return groups.map((group, index) => ({
252
- ...group,
253
- size: baseSize + (index === groups.length - 1 ? remainder : 0)
254
- }));
213
+ const object = value => {
214
+ const type = getType(value);
215
+ if (type !== Object$1) {
216
+ throw new AssertionError('expected value to be of type object');
217
+ }
255
218
  };
256
-
257
- const closeEditorGroup$1 = (state, groupId) => {
258
- if (Number.isNaN(groupId)) {
259
- return state;
219
+ const number = value => {
220
+ const type = getType(value);
221
+ if (type !== Number$1) {
222
+ throw new AssertionError('expected value to be of type number');
260
223
  }
261
- const {
262
- layout
263
- } = state;
264
- const {
265
- activeGroupId,
266
- groups
267
- } = layout;
268
- const groupIndex = getGroupIndexById(state, groupId);
269
- if (groupIndex === -1 || groups.length <= 1) {
270
- return state;
224
+ };
225
+ const string = value => {
226
+ const type = getType(value);
227
+ if (type !== String$1) {
228
+ throw new AssertionError('expected value to be of type string');
271
229
  }
272
- const remainingGroups = groups.filter(group => group.id !== groupId);
273
- const redistributedGroups = redistributeSizesWithRemainder(remainingGroups);
274
- const newActiveGroupId = activeGroupId === groupId ? remainingGroups[0].id : activeGroupId;
275
- return withGroupsAndActiveGroup(state, redistributedGroups, newActiveGroupId);
276
230
  };
277
231
 
278
- const isFocused = group => {
279
- return group.focused;
232
+ const isMessagePort = value => {
233
+ return value && value instanceof MessagePort;
280
234
  };
281
- const closeFocusedTab = state => {
282
- const {
283
- layout
284
- } = state;
285
- const {
286
- groups
287
- } = layout;
288
- const focusedGroup = groups.find(isFocused);
289
- if (!focusedGroup) {
290
- return state;
291
- }
292
- const {
293
- activeTabId
294
- } = focusedGroup;
295
- if (activeTabId === undefined) {
296
- return state;
297
- }
298
- return closeTab(state, focusedGroup.id, activeTabId);
235
+ const isMessagePortMain = value => {
236
+ return value && value.constructor && value.constructor.name === 'MessagePortMain';
299
237
  };
300
-
301
- const closeOtherTabs = (state, groupId) => {
302
- const {
303
- layout
304
- } = state;
305
- const {
306
- activeGroupId,
307
- groups
308
- } = layout;
309
- const targetGroupId = groupId ?? activeGroupId;
310
- if (targetGroupId === undefined) {
311
- return state;
312
- }
313
- const group = groups.find(g => g.id === targetGroupId);
314
- if (!group) {
315
- return state;
316
- }
317
- const {
318
- activeTabId
319
- } = group;
320
- if (activeTabId === undefined) {
321
- return state;
322
- }
323
- const newGroups = groups.map(g => {
324
- if (g.id === targetGroupId) {
325
- const newTabs = g.tabs.filter(tab => tab.id === activeTabId);
326
- return {
327
- ...g,
328
- activeTabId,
329
- isEmpty: newTabs.length === 0,
330
- tabs: newTabs
331
- };
332
- }
333
- return g;
334
- });
335
- return {
336
- ...state,
337
- layout: {
338
- ...layout,
339
- groups: newGroups
238
+ const isOffscreenCanvas = value => {
239
+ return typeof OffscreenCanvas !== 'undefined' && value instanceof OffscreenCanvas;
240
+ };
241
+ const isInstanceOf = (value, constructorName) => {
242
+ return value?.constructor?.name === constructorName;
243
+ };
244
+ const isSocket = value => {
245
+ return isInstanceOf(value, 'Socket');
246
+ };
247
+ const transferrables = [isMessagePort, isMessagePortMain, isOffscreenCanvas, isSocket];
248
+ const isTransferrable = value => {
249
+ for (const fn of transferrables) {
250
+ if (fn(value)) {
251
+ return true;
340
252
  }
341
- };
253
+ }
254
+ return false;
342
255
  };
343
-
344
- const getNextActiveTabId = (tabs, newTabs, activeTabId) => {
345
- if (activeTabId === undefined) {
346
- return undefined;
256
+ const walkValue = (value, transferrables, isTransferrable) => {
257
+ if (!value) {
258
+ return;
347
259
  }
348
- if (newTabs.some(tab => tab.id === activeTabId)) {
349
- return activeTabId;
260
+ if (isTransferrable(value)) {
261
+ transferrables.push(value);
262
+ return;
350
263
  }
351
- const activeTabIndex = tabs.findIndex(tab => tab.id === activeTabId);
352
- if (activeTabIndex === -1 || newTabs.length === 0) {
353
- return undefined;
264
+ if (Array.isArray(value)) {
265
+ for (const item of value) {
266
+ walkValue(item, transferrables, isTransferrable);
267
+ }
268
+ return;
354
269
  }
355
- return newTabs[Math.min(activeTabIndex, newTabs.length - 1)].id;
356
- };
357
- const closeSavedInGroup = group => {
358
- const {
359
- activeTabId,
360
- tabs
361
- } = group;
362
- const newTabs = tabs.filter(tab => tab.isDirty);
363
- if (newTabs.length === tabs.length) {
364
- return group;
270
+ if (typeof value === 'object') {
271
+ for (const property of Object.values(value)) {
272
+ walkValue(property, transferrables, isTransferrable);
273
+ }
274
+ return;
365
275
  }
366
- const newActiveTabId = getNextActiveTabId(tabs, newTabs, activeTabId);
367
- return {
368
- ...group,
369
- activeTabId: newActiveTabId,
370
- isEmpty: newTabs.length === 0,
371
- tabs: newTabs
372
- };
373
276
  };
374
- const closeSaved$1 = state => {
375
- const {
376
- groups
377
- } = state.layout;
378
- const newGroups = groups.map(closeSavedInGroup);
379
- return withGroups(state, newGroups);
277
+ const getTransferrables = value => {
278
+ const transferrables = [];
279
+ walkValue(value, transferrables, isTransferrable);
280
+ return transferrables;
380
281
  };
381
-
382
- const closeTabsByUris = (state, uris) => {
383
- let currentState = state;
384
- for (const uri of uris) {
385
- while (true) {
386
- const matchingGroup = currentState.layout.groups.find(group => {
387
- return group.tabs.some(tab => tab.uri === uri);
388
- });
389
- if (!matchingGroup) {
390
- break;
282
+ const removeValues = (value, toRemove) => {
283
+ if (!value) {
284
+ return value;
285
+ }
286
+ if (Array.isArray(value)) {
287
+ const newItems = [];
288
+ for (const item of value) {
289
+ if (!toRemove.includes(item)) {
290
+ newItems.push(removeValues(item, toRemove));
391
291
  }
392
- const matchingTab = matchingGroup.tabs.find(tab => tab.uri === uri);
393
- if (!matchingTab) {
394
- break;
292
+ }
293
+ return newItems;
294
+ }
295
+ if (typeof value === 'object') {
296
+ const newObject = Object.create(null);
297
+ for (const [key, property] of Object.entries(value)) {
298
+ if (!toRemove.includes(property)) {
299
+ newObject[key] = removeValues(property, toRemove);
395
300
  }
396
- currentState = closeTab(currentState, matchingGroup.id, matchingTab.id);
397
301
  }
302
+ return newObject;
398
303
  }
399
- return currentState;
304
+ return value;
400
305
  };
401
306
 
402
- const getGroupById = (state, groupId) => {
403
- return state.layout.groups.find(group => group.id === groupId);
307
+ // workaround for electron not supporting transferrable objects
308
+ // as parameters. If the transferrable object is a parameter, in electron
309
+ // only an empty objected is received in the main process
310
+ const fixElectronParameters = value => {
311
+ const transfer = getTransferrables(value);
312
+ const newValue = removeValues(value, transfer);
313
+ return {
314
+ newValue,
315
+ transfer
316
+ };
404
317
  };
405
-
406
- const closeTabsRight = (state, groupId) => {
407
- const {
408
- layout
409
- } = state;
410
- const {
411
- groups
412
- } = layout;
413
- const group = getGroupById(state, groupId);
414
- if (!group) {
415
- return state;
416
- }
318
+ const getActualDataElectron = event => {
417
319
  const {
418
- activeTabId,
419
- tabs
420
- } = group;
421
- if (activeTabId === undefined) {
422
- return state;
423
- }
424
- const activeTabIndex = tabs.findIndex(tab => tab.id === activeTabId);
425
- if (activeTabIndex === -1) {
426
- return state;
427
- }
428
- const newTabs = tabs.slice(0, activeTabIndex + 1);
429
- if (newTabs.length === tabs.length) {
430
- return state;
320
+ data,
321
+ ports
322
+ } = event;
323
+ if (ports.length === 0) {
324
+ return data;
431
325
  }
432
- const newGroups = groups.map(g => {
433
- if (g.id === groupId) {
434
- return {
435
- ...g,
436
- isEmpty: newTabs.length === 0,
437
- tabs: newTabs
438
- };
439
- }
440
- return g;
441
- });
442
- return withGroups(state, newGroups);
326
+ return {
327
+ ...data,
328
+ params: [...ports, ...data.params]
329
+ };
443
330
  };
444
-
445
- const normalizeLine = line => {
446
- if (line.startsWith('Error: ')) {
447
- return line.slice('Error: '.length);
448
- }
449
- if (line.startsWith('VError: ')) {
450
- return line.slice('VError: '.length);
451
- }
452
- return line;
331
+ const attachEvents = that => {
332
+ const handleMessage = (...args) => {
333
+ const data = that.getData(...args);
334
+ that.dispatchEvent(new MessageEvent('message', {
335
+ data
336
+ }));
337
+ };
338
+ that.onMessage(handleMessage);
339
+ const handleClose = event => {
340
+ that.dispatchEvent(new Event('close'));
341
+ };
342
+ that.onClose(handleClose);
453
343
  };
454
- const getCombinedMessage = (error, message) => {
455
- const stringifiedError = normalizeLine(`${error}`);
456
- if (message) {
457
- return `${message}: ${stringifiedError}`;
344
+ class Ipc extends EventTarget {
345
+ constructor(rawIpc) {
346
+ super();
347
+ this._rawIpc = rawIpc;
348
+ attachEvents(this);
458
349
  }
459
- return stringifiedError;
350
+ }
351
+ const E_INCOMPATIBLE_NATIVE_MODULE = 'E_INCOMPATIBLE_NATIVE_MODULE';
352
+ const E_MODULES_NOT_SUPPORTED_IN_ELECTRON = 'E_MODULES_NOT_SUPPORTED_IN_ELECTRON';
353
+ const ERR_MODULE_NOT_FOUND = 'ERR_MODULE_NOT_FOUND';
354
+ const NewLine$1 = '\n';
355
+ const joinLines$1 = lines => {
356
+ return lines.join(NewLine$1);
460
357
  };
461
- const NewLine$2 = '\n';
462
- const getNewLineIndex$1 = (string, startIndex = undefined) => {
463
- return string.indexOf(NewLine$2, startIndex);
358
+ const RE_AT = /^\s+at/;
359
+ const RE_AT_PROMISE_INDEX = /^\s*at async Promise.all \(index \d+\)$/;
360
+ const isNormalStackLine = line => {
361
+ return RE_AT.test(line) && !RE_AT_PROMISE_INDEX.test(line);
464
362
  };
465
- const mergeStacks = (parent, child) => {
466
- if (!child) {
467
- return parent;
468
- }
469
- const parentNewLineIndex = getNewLineIndex$1(parent);
470
- const childNewLineIndex = getNewLineIndex$1(child);
471
- if (childNewLineIndex === -1) {
472
- return parent;
473
- }
474
- const parentFirstLine = parent.slice(0, parentNewLineIndex);
475
- const childRest = child.slice(childNewLineIndex);
476
- const childFirstLine = normalizeLine(child.slice(0, childNewLineIndex));
477
- if (parentFirstLine.includes(childFirstLine)) {
478
- return parentFirstLine + childRest;
479
- }
480
- return child;
481
- };
482
- class VError extends Error {
483
- constructor(error, message) {
484
- const combinedMessage = getCombinedMessage(error, message);
485
- super(combinedMessage);
486
- this.name = 'VError';
487
- if (error instanceof Error) {
488
- this.stack = mergeStacks(this.stack, error.stack);
489
- }
490
- if (error.codeFrame) {
491
- // @ts-ignore
492
- this.codeFrame = error.codeFrame;
493
- }
494
- if (error.code) {
495
- // @ts-ignore
496
- this.code = error.code;
497
- }
498
- }
499
- }
500
-
501
- class AssertionError extends Error {
502
- constructor(message) {
503
- super(message);
504
- this.name = 'AssertionError';
505
- }
506
- }
507
- const Object$1 = 1;
508
- const Number$1 = 2;
509
- const Array$1 = 3;
510
- const String$1 = 4;
511
- const Boolean$1 = 5;
512
- const Function = 6;
513
- const Null = 7;
514
- const Unknown = 8;
515
- const getType = value => {
516
- switch (typeof value) {
517
- case 'number':
518
- return Number$1;
519
- case 'function':
520
- return Function;
521
- case 'string':
522
- return String$1;
523
- case 'object':
524
- if (value === null) {
525
- return Null;
526
- }
527
- if (Array.isArray(value)) {
528
- return Array$1;
529
- }
530
- return Object$1;
531
- case 'boolean':
532
- return Boolean$1;
533
- default:
534
- return Unknown;
535
- }
536
- };
537
- const object = value => {
538
- const type = getType(value);
539
- if (type !== Object$1) {
540
- throw new AssertionError('expected value to be of type object');
541
- }
542
- };
543
- const number = value => {
544
- const type = getType(value);
545
- if (type !== Number$1) {
546
- throw new AssertionError('expected value to be of type number');
547
- }
548
- };
549
- const string = value => {
550
- const type = getType(value);
551
- if (type !== String$1) {
552
- throw new AssertionError('expected value to be of type string');
553
- }
554
- };
555
-
556
- const isMessagePort = value => {
557
- return value && value instanceof MessagePort;
558
- };
559
- const isMessagePortMain = value => {
560
- return value && value.constructor && value.constructor.name === 'MessagePortMain';
561
- };
562
- const isOffscreenCanvas = value => {
563
- return typeof OffscreenCanvas !== 'undefined' && value instanceof OffscreenCanvas;
564
- };
565
- const isInstanceOf = (value, constructorName) => {
566
- return value?.constructor?.name === constructorName;
567
- };
568
- const isSocket = value => {
569
- return isInstanceOf(value, 'Socket');
570
- };
571
- const transferrables = [isMessagePort, isMessagePortMain, isOffscreenCanvas, isSocket];
572
- const isTransferrable = value => {
573
- for (const fn of transferrables) {
574
- if (fn(value)) {
575
- return true;
576
- }
577
- }
578
- return false;
579
- };
580
- const walkValue = (value, transferrables, isTransferrable) => {
581
- if (!value) {
582
- return;
583
- }
584
- if (isTransferrable(value)) {
585
- transferrables.push(value);
586
- return;
587
- }
588
- if (Array.isArray(value)) {
589
- for (const item of value) {
590
- walkValue(item, transferrables, isTransferrable);
591
- }
592
- return;
593
- }
594
- if (typeof value === 'object') {
595
- for (const property of Object.values(value)) {
596
- walkValue(property, transferrables, isTransferrable);
597
- }
598
- return;
599
- }
600
- };
601
- const getTransferrables = value => {
602
- const transferrables = [];
603
- walkValue(value, transferrables, isTransferrable);
604
- return transferrables;
605
- };
606
- const removeValues = (value, toRemove) => {
607
- if (!value) {
608
- return value;
609
- }
610
- if (Array.isArray(value)) {
611
- const newItems = [];
612
- for (const item of value) {
613
- if (!toRemove.includes(item)) {
614
- newItems.push(removeValues(item, toRemove));
615
- }
616
- }
617
- return newItems;
618
- }
619
- if (typeof value === 'object') {
620
- const newObject = Object.create(null);
621
- for (const [key, property] of Object.entries(value)) {
622
- if (!toRemove.includes(property)) {
623
- newObject[key] = removeValues(property, toRemove);
624
- }
625
- }
626
- return newObject;
627
- }
628
- return value;
629
- };
630
-
631
- // workaround for electron not supporting transferrable objects
632
- // as parameters. If the transferrable object is a parameter, in electron
633
- // only an empty objected is received in the main process
634
- const fixElectronParameters = value => {
635
- const transfer = getTransferrables(value);
636
- const newValue = removeValues(value, transfer);
637
- return {
638
- newValue,
639
- transfer
640
- };
641
- };
642
- const getActualDataElectron = event => {
643
- const {
644
- data,
645
- ports
646
- } = event;
647
- if (ports.length === 0) {
648
- return data;
649
- }
650
- return {
651
- ...data,
652
- params: [...ports, ...data.params]
653
- };
654
- };
655
- const attachEvents = that => {
656
- const handleMessage = (...args) => {
657
- const data = that.getData(...args);
658
- that.dispatchEvent(new MessageEvent('message', {
659
- data
660
- }));
661
- };
662
- that.onMessage(handleMessage);
663
- const handleClose = event => {
664
- that.dispatchEvent(new Event('close'));
665
- };
666
- that.onClose(handleClose);
667
- };
668
- class Ipc extends EventTarget {
669
- constructor(rawIpc) {
670
- super();
671
- this._rawIpc = rawIpc;
672
- attachEvents(this);
673
- }
674
- }
675
- const E_INCOMPATIBLE_NATIVE_MODULE = 'E_INCOMPATIBLE_NATIVE_MODULE';
676
- const E_MODULES_NOT_SUPPORTED_IN_ELECTRON = 'E_MODULES_NOT_SUPPORTED_IN_ELECTRON';
677
- const ERR_MODULE_NOT_FOUND = 'ERR_MODULE_NOT_FOUND';
678
- const NewLine$1 = '\n';
679
- const joinLines$1 = lines => {
680
- return lines.join(NewLine$1);
681
- };
682
- const RE_AT = /^\s+at/;
683
- const RE_AT_PROMISE_INDEX = /^\s*at async Promise.all \(index \d+\)$/;
684
- const isNormalStackLine = line => {
685
- return RE_AT.test(line) && !RE_AT_PROMISE_INDEX.test(line);
686
- };
687
- const getDetails = lines => {
688
- const index = lines.findIndex(isNormalStackLine);
689
- if (index === -1) {
690
- return {
691
- actualMessage: joinLines$1(lines),
692
- rest: []
693
- };
363
+ const getDetails = lines => {
364
+ const index = lines.findIndex(isNormalStackLine);
365
+ if (index === -1) {
366
+ return {
367
+ actualMessage: joinLines$1(lines),
368
+ rest: []
369
+ };
694
370
  }
695
371
  let lastIndex = index - 1;
696
372
  while (++lastIndex < lines.length) {
@@ -1288,511 +964,864 @@ const getErrorResponse = (id, error, preparePrettyError, logError) => {
1288
964
  const errorProperty = getErrorProperty(error, prettyError);
1289
965
  return create$1$1(id, errorProperty);
1290
966
  };
1291
- const create$e = (message, result) => {
1292
- return {
1293
- id: message.id,
1294
- jsonrpc: Two$1,
1295
- result: result ?? null
1296
- };
967
+ const create$e = (message, result) => {
968
+ return {
969
+ id: message.id,
970
+ jsonrpc: Two$1,
971
+ result: result ?? null
972
+ };
973
+ };
974
+ const getSuccessResponse = (message, result) => {
975
+ const resultProperty = result ?? null;
976
+ return create$e(message, resultProperty);
977
+ };
978
+ const getErrorResponseSimple = (id, error) => {
979
+ return {
980
+ error: {
981
+ code: Custom,
982
+ data: error,
983
+ // @ts-ignore
984
+ message: error.message
985
+ },
986
+ id,
987
+ jsonrpc: Two$1
988
+ };
989
+ };
990
+ const getResponse = async (message, ipc, execute, preparePrettyError, logError, requiresSocket) => {
991
+ try {
992
+ const result = requiresSocket(message.method) ? await execute(message.method, ipc, ...message.params) : await execute(message.method, ...message.params);
993
+ return getSuccessResponse(message, result);
994
+ } catch (error) {
995
+ if (ipc.canUseSimpleErrorResponse) {
996
+ return getErrorResponseSimple(message.id, error);
997
+ }
998
+ return getErrorResponse(message.id, error, preparePrettyError, logError);
999
+ }
1000
+ };
1001
+ const defaultPreparePrettyError = error => {
1002
+ return error;
1003
+ };
1004
+ const defaultLogError = () => {
1005
+ // ignore
1006
+ };
1007
+ const defaultRequiresSocket = () => {
1008
+ return false;
1009
+ };
1010
+ const defaultResolve = resolve;
1011
+
1012
+ // TODO maybe remove this in v6 or v7, only accept options object to simplify the code
1013
+ const normalizeParams = args => {
1014
+ if (args.length === 1) {
1015
+ const options = args[0];
1016
+ return {
1017
+ execute: options.execute,
1018
+ ipc: options.ipc,
1019
+ logError: options.logError || defaultLogError,
1020
+ message: options.message,
1021
+ preparePrettyError: options.preparePrettyError || defaultPreparePrettyError,
1022
+ requiresSocket: options.requiresSocket || defaultRequiresSocket,
1023
+ resolve: options.resolve || defaultResolve
1024
+ };
1025
+ }
1026
+ return {
1027
+ execute: args[2],
1028
+ ipc: args[0],
1029
+ logError: args[5],
1030
+ message: args[1],
1031
+ preparePrettyError: args[4],
1032
+ requiresSocket: args[6],
1033
+ resolve: args[3]
1034
+ };
1035
+ };
1036
+ const handleJsonRpcMessage = async (...args) => {
1037
+ const options = normalizeParams(args);
1038
+ const {
1039
+ execute,
1040
+ ipc,
1041
+ logError,
1042
+ message,
1043
+ preparePrettyError,
1044
+ requiresSocket,
1045
+ resolve
1046
+ } = options;
1047
+ if ('id' in message) {
1048
+ if ('method' in message) {
1049
+ const response = await getResponse(message, ipc, execute, preparePrettyError, logError, requiresSocket);
1050
+ try {
1051
+ ipc.send(response);
1052
+ } catch (error) {
1053
+ const errorResponse = getErrorResponse(message.id, error, preparePrettyError, logError);
1054
+ ipc.send(errorResponse);
1055
+ }
1056
+ return;
1057
+ }
1058
+ resolve(message.id, message);
1059
+ return;
1060
+ }
1061
+ if ('method' in message) {
1062
+ await getResponse(message, ipc, execute, preparePrettyError, logError, requiresSocket);
1063
+ return;
1064
+ }
1065
+ throw new JsonRpcError('unexpected message');
1066
+ };
1067
+
1068
+ const Two = '2.0';
1069
+
1070
+ const create$d = (method, params) => {
1071
+ return {
1072
+ jsonrpc: Two,
1073
+ method,
1074
+ params
1075
+ };
1076
+ };
1077
+
1078
+ const create$c = (id, method, params) => {
1079
+ const message = {
1080
+ id,
1081
+ jsonrpc: Two,
1082
+ method,
1083
+ params
1084
+ };
1085
+ return message;
1086
+ };
1087
+
1088
+ let id$1 = 0;
1089
+ const create$b = () => {
1090
+ return ++id$1;
1091
+ };
1092
+
1093
+ const registerPromise = map => {
1094
+ const id = create$b();
1095
+ const {
1096
+ promise,
1097
+ resolve
1098
+ } = Promise.withResolvers();
1099
+ map[id] = resolve;
1100
+ return {
1101
+ id,
1102
+ promise
1103
+ };
1104
+ };
1105
+
1106
+ const invokeHelper = async (callbacks, ipc, method, params, useSendAndTransfer) => {
1107
+ const {
1108
+ id,
1109
+ promise
1110
+ } = registerPromise(callbacks);
1111
+ const message = create$c(id, method, params);
1112
+ if (useSendAndTransfer && ipc.sendAndTransfer) {
1113
+ ipc.sendAndTransfer(message);
1114
+ } else {
1115
+ ipc.send(message);
1116
+ }
1117
+ const responseMessage = await promise;
1118
+ return unwrapJsonRpcResult(responseMessage);
1119
+ };
1120
+ const createRpc = ipc => {
1121
+ const callbacks = Object.create(null);
1122
+ ipc._resolve = (id, response) => {
1123
+ const fn = callbacks[id];
1124
+ if (!fn) {
1125
+ console.warn(`callback ${id} may already be disposed`);
1126
+ return;
1127
+ }
1128
+ fn(response);
1129
+ delete callbacks[id];
1130
+ };
1131
+ const rpc = {
1132
+ async dispose() {
1133
+ await ipc?.dispose();
1134
+ },
1135
+ invoke(method, ...params) {
1136
+ return invokeHelper(callbacks, ipc, method, params, false);
1137
+ },
1138
+ invokeAndTransfer(method, ...params) {
1139
+ return invokeHelper(callbacks, ipc, method, params, true);
1140
+ },
1141
+ // @ts-ignore
1142
+ ipc,
1143
+ /**
1144
+ * @deprecated
1145
+ */
1146
+ send(method, ...params) {
1147
+ const message = create$d(method, params);
1148
+ ipc.send(message);
1149
+ }
1150
+ };
1151
+ return rpc;
1152
+ };
1153
+
1154
+ const requiresSocket = () => {
1155
+ return false;
1156
+ };
1157
+ const preparePrettyError = error => {
1158
+ return error;
1159
+ };
1160
+ const logError = () => {
1161
+ // handled by renderer worker
1162
+ };
1163
+ const handleMessage = event => {
1164
+ const actualRequiresSocket = event?.target?.requiresSocket || requiresSocket;
1165
+ const actualExecute = event?.target?.execute || execute;
1166
+ return handleJsonRpcMessage(event.target, event.data, actualExecute, event.target._resolve, preparePrettyError, logError, actualRequiresSocket);
1167
+ };
1168
+
1169
+ const handleIpc = ipc => {
1170
+ if ('addEventListener' in ipc) {
1171
+ ipc.addEventListener('message', handleMessage);
1172
+ } else if ('on' in ipc) {
1173
+ // deprecated
1174
+ ipc.on('message', handleMessage);
1175
+ }
1176
+ };
1177
+
1178
+ const listen$1 = async (module, options) => {
1179
+ const rawIpc = await module.listen(options);
1180
+ if (module.signal) {
1181
+ module.signal(rawIpc);
1182
+ }
1183
+ const ipc = module.wrap(rawIpc);
1184
+ return ipc;
1185
+ };
1186
+
1187
+ const create$a = async ({
1188
+ commandMap,
1189
+ messagePort,
1190
+ requiresSocket
1191
+ }) => {
1192
+ // TODO create a commandMap per rpc instance
1193
+ register(commandMap);
1194
+ const ipc = await listen$1(IpcChildWithElectronMessagePort$1, {
1195
+ messagePort
1196
+ });
1197
+ if (requiresSocket) {
1198
+ ipc.requiresSocket = requiresSocket;
1199
+ }
1200
+ handleIpc(ipc);
1201
+ const rpc = createRpc(ipc);
1202
+ return rpc;
1203
+ };
1204
+
1205
+ const create$9 = async ({
1206
+ commandMap,
1207
+ isMessagePortOpen = true,
1208
+ messagePort
1209
+ }) => {
1210
+ // TODO create a commandMap per rpc instance
1211
+ register(commandMap);
1212
+ const rawIpc = await IpcParentWithMessagePort$1.create({
1213
+ isMessagePortOpen,
1214
+ messagePort
1215
+ });
1216
+ const ipc = IpcParentWithMessagePort$1.wrap(rawIpc);
1217
+ handleIpc(ipc);
1218
+ const rpc = createRpc(ipc);
1219
+ messagePort.start();
1220
+ return rpc;
1221
+ };
1222
+
1223
+ const create$8 = async ({
1224
+ commandMap,
1225
+ isMessagePortOpen,
1226
+ send
1227
+ }) => {
1228
+ const {
1229
+ port1,
1230
+ port2
1231
+ } = new MessageChannel();
1232
+ await send(port1);
1233
+ return create$9({
1234
+ commandMap,
1235
+ isMessagePortOpen,
1236
+ messagePort: port2
1237
+ });
1238
+ };
1239
+
1240
+ const createSharedLazyRpc = factory => {
1241
+ let rpcPromise;
1242
+ const getOrCreate = () => {
1243
+ if (!rpcPromise) {
1244
+ rpcPromise = factory();
1245
+ }
1246
+ return rpcPromise;
1247
+ };
1248
+ return {
1249
+ async dispose() {
1250
+ const rpc = await getOrCreate();
1251
+ await rpc.dispose();
1252
+ },
1253
+ async invoke(method, ...params) {
1254
+ const rpc = await getOrCreate();
1255
+ return rpc.invoke(method, ...params);
1256
+ },
1257
+ async invokeAndTransfer(method, ...params) {
1258
+ const rpc = await getOrCreate();
1259
+ return rpc.invokeAndTransfer(method, ...params);
1260
+ },
1261
+ async send(method, ...params) {
1262
+ const rpc = await getOrCreate();
1263
+ rpc.send(method, ...params);
1264
+ }
1265
+ };
1266
+ };
1267
+
1268
+ const create$7 = async ({
1269
+ commandMap,
1270
+ getPortTuple,
1271
+ send
1272
+ }) => {
1273
+ const {
1274
+ port1,
1275
+ port2
1276
+ } = await getPortTuple();
1277
+ await send(port1);
1278
+ const rpc = create$a({
1279
+ commandMap,
1280
+ messagePort: port2
1281
+ });
1282
+ return rpc;
1283
+ };
1284
+
1285
+ const create$6 = async ({
1286
+ commandMap,
1287
+ getPortTuple,
1288
+ send
1289
+ }) => {
1290
+ return createSharedLazyRpc(() => {
1291
+ return create$7({
1292
+ commandMap,
1293
+ getPortTuple,
1294
+ send
1295
+ });
1296
+ });
1297
+ };
1298
+
1299
+ const create$5 = async ({
1300
+ commandMap,
1301
+ isMessagePortOpen,
1302
+ send
1303
+ }) => {
1304
+ return createSharedLazyRpc(() => {
1305
+ return create$8({
1306
+ commandMap,
1307
+ isMessagePortOpen,
1308
+ send
1309
+ });
1310
+ });
1311
+ };
1312
+
1313
+ const create$4 = async ({
1314
+ commandMap
1315
+ }) => {
1316
+ // TODO create a commandMap per rpc instance
1317
+ register(commandMap);
1318
+ const ipc = await listen$1(IpcChildWithModuleWorkerAndMessagePort$1);
1319
+ handleIpc(ipc);
1320
+ const rpc = createRpc(ipc);
1321
+ return rpc;
1322
+ };
1323
+
1324
+ const createMockRpc = ({
1325
+ commandMap
1326
+ }) => {
1327
+ const invocations = [];
1328
+ const invoke = (method, ...params) => {
1329
+ invocations.push([method, ...params]);
1330
+ const command = commandMap[method];
1331
+ if (!command) {
1332
+ throw new Error(`command ${method} not found`);
1333
+ }
1334
+ return command(...params);
1335
+ };
1336
+ const mockRpc = {
1337
+ invocations,
1338
+ invoke,
1339
+ invokeAndTransfer: invoke
1340
+ };
1341
+ return mockRpc;
1342
+ };
1343
+
1344
+ const rpcs = Object.create(null);
1345
+ const set$5 = (id, rpc) => {
1346
+ rpcs[id] = rpc;
1347
+ };
1348
+ const get$1 = id => {
1349
+ return rpcs[id];
1350
+ };
1351
+ const remove = id => {
1352
+ delete rpcs[id];
1353
+ };
1354
+
1355
+ /* eslint-disable @typescript-eslint/explicit-function-return-type */
1356
+ const create$3 = rpcId => {
1357
+ return {
1358
+ async dispose() {
1359
+ const rpc = get$1(rpcId);
1360
+ await rpc.dispose();
1361
+ },
1362
+ // @ts-ignore
1363
+ invoke(method, ...params) {
1364
+ const rpc = get$1(rpcId);
1365
+ // @ts-ignore
1366
+ return rpc.invoke(method, ...params);
1367
+ },
1368
+ // @ts-ignore
1369
+ invokeAndTransfer(method, ...params) {
1370
+ const rpc = get$1(rpcId);
1371
+ // @ts-ignore
1372
+ return rpc.invokeAndTransfer(method, ...params);
1373
+ },
1374
+ registerMockRpc(commandMap) {
1375
+ const mockRpc = createMockRpc({
1376
+ commandMap
1377
+ });
1378
+ set$5(rpcId, mockRpc);
1379
+ // @ts-ignore
1380
+ mockRpc[Symbol.dispose] = () => {
1381
+ remove(rpcId);
1382
+ };
1383
+ // @ts-ignore
1384
+ return mockRpc;
1385
+ },
1386
+ set(rpc) {
1387
+ set$5(rpcId, rpc);
1388
+ }
1389
+ };
1390
+ };
1391
+
1392
+ const None$1 = 'none';
1393
+
1394
+ const Button$2 = 1;
1395
+ const Div = 4;
1396
+ const Span = 8;
1397
+ const Text = 12;
1398
+ const Img = 17;
1399
+ const P = 50;
1400
+ const Pre = 51;
1401
+ const Reference = 100;
1402
+
1403
+ const Button$1 = 'event.button';
1404
+ const ClientX = 'event.clientX';
1405
+ const ClientY = 'event.clientY';
1406
+ const EventTargetClassName = 'event.target.className';
1407
+ const TargetName = 'event.target.name';
1408
+
1409
+ const Tab = 13;
1410
+ const Main$1 = 24;
1411
+
1412
+ const Separator = 1;
1413
+ const None = 0;
1414
+
1415
+ const Electron = 2;
1416
+
1417
+ const ClipBoardWorker = 3400;
1418
+ const ExtensionHostWorker = 44;
1419
+ const IconThemeWorker = 7009;
1420
+ const RendererWorker = 1;
1421
+
1422
+ const SetCss = 'Viewlet.setCss';
1423
+ const SetDom2 = 'Viewlet.setDom2';
1424
+ const SetPatches = 'Viewlet.setPatches';
1425
+
1426
+ const {
1427
+ set: set$4
1428
+ } = create$3(ClipBoardWorker);
1429
+
1430
+ const {
1431
+ set: set$3
1432
+ } = create$3(ExtensionHostWorker);
1433
+
1434
+ const {
1435
+ invoke: invoke$1,
1436
+ set: set$2
1437
+ } = create$3(IconThemeWorker);
1438
+ const getIcons = async iconRequests => {
1439
+ // @ts-ignore
1440
+ return invoke$1('IconTheme.getIcons', iconRequests);
1441
+ };
1442
+
1443
+ const {
1444
+ invoke,
1445
+ invokeAndTransfer,
1446
+ set: set$1
1447
+ } = create$3(RendererWorker);
1448
+ const handleModifiedStatusChange$1 = async (uri, modified) => {
1449
+ return invoke('Main.handleModifiedStatusChange', uri, modified);
1297
1450
  };
1298
- const getSuccessResponse = (message, result) => {
1299
- const resultProperty = result ?? null;
1300
- return create$e(message, resultProperty);
1451
+ const showContextMenu2 = async (uid, menuId, x, y, args) => {
1452
+ number(uid);
1453
+ number(menuId);
1454
+ number(x);
1455
+ number(y);
1456
+ await invoke('ContextMenu.show2', uid, menuId, x, y, args);
1301
1457
  };
1302
- const getErrorResponseSimple = (id, error) => {
1303
- return {
1304
- error: {
1305
- code: Custom,
1306
- data: error,
1307
- // @ts-ignore
1308
- message: error.message
1309
- },
1310
- id,
1311
- jsonrpc: Two$1
1312
- };
1458
+ const sendMessagePortToClipBoardWorker$1 = async (port, rpcId) => {
1459
+ const command = 'ClipBoard.handleMessagePort';
1460
+ await invokeAndTransfer('SendMessagePortToExtensionHostWorker.sendMessagePortToClipBoardWorker', port, command, rpcId);
1313
1461
  };
1314
- const getResponse = async (message, ipc, execute, preparePrettyError, logError, requiresSocket) => {
1315
- try {
1316
- const result = requiresSocket(message.method) ? await execute(message.method, ipc, ...message.params) : await execute(message.method, ...message.params);
1317
- return getSuccessResponse(message, result);
1318
- } catch (error) {
1319
- if (ipc.canUseSimpleErrorResponse) {
1320
- return getErrorResponseSimple(message.id, error);
1321
- }
1322
- return getErrorResponse(message.id, error, preparePrettyError, logError);
1323
- }
1462
+ const sendMessagePortToIconThemeWorker = async (port, rpcId) => {
1463
+ const command = 'IconTheme.handleMessagePort';
1464
+ await invokeAndTransfer('SendMessagePortToExtensionHostWorker.sendMessagePortToIconThemeWorker', port, command, rpcId);
1324
1465
  };
1325
- const defaultPreparePrettyError = error => {
1326
- return error;
1466
+ const readFile = async uri => {
1467
+ return invoke('FileSystem.readFile', uri);
1327
1468
  };
1328
- const defaultLogError = () => {
1329
- // ignore
1469
+ const sendMessagePortToExtensionHostWorker$1 = async (port, rpcId = 0) => {
1470
+ const command = 'HandleMessagePort.handleMessagePort2';
1471
+ await invokeAndTransfer('SendMessagePortToExtensionHostWorker.sendMessagePortToExtensionHostWorker', port, command, rpcId);
1330
1472
  };
1331
- const defaultRequiresSocket = () => {
1332
- return false;
1473
+ const writeClipBoardText = async text => {
1474
+ await invoke('ClipBoard.writeText', /* text */text);
1333
1475
  };
1334
- const defaultResolve = resolve;
1335
1476
 
1336
- // TODO maybe remove this in v6 or v7, only accept options object to simplify the code
1337
- const normalizeParams = args => {
1338
- if (args.length === 1) {
1339
- const options = args[0];
1340
- return {
1341
- execute: options.execute,
1342
- ipc: options.ipc,
1343
- logError: options.logError || defaultLogError,
1344
- message: options.message,
1345
- preparePrettyError: options.preparePrettyError || defaultPreparePrettyError,
1346
- requiresSocket: options.requiresSocket || defaultRequiresSocket,
1347
- resolve: options.resolve || defaultResolve
1348
- };
1349
- }
1350
- return {
1351
- execute: args[2],
1352
- ipc: args[0],
1353
- logError: args[5],
1354
- message: args[1],
1355
- preparePrettyError: args[4],
1356
- requiresSocket: args[6],
1357
- resolve: args[3]
1358
- };
1359
- };
1360
- const handleJsonRpcMessage = async (...args) => {
1361
- const options = normalizeParams(args);
1477
+ const getGroupIndexById = (state, groupId) => {
1362
1478
  const {
1363
- execute,
1364
- ipc,
1365
- logError,
1366
- message,
1367
- preparePrettyError,
1368
- requiresSocket,
1369
- resolve
1370
- } = options;
1371
- if ('id' in message) {
1372
- if ('method' in message) {
1373
- const response = await getResponse(message, ipc, execute, preparePrettyError, logError, requiresSocket);
1374
- try {
1375
- ipc.send(response);
1376
- } catch (error) {
1377
- const errorResponse = getErrorResponse(message.id, error, preparePrettyError, logError);
1378
- ipc.send(errorResponse);
1379
- }
1380
- return;
1381
- }
1382
- resolve(message.id, message);
1383
- return;
1384
- }
1385
- if ('method' in message) {
1386
- await getResponse(message, ipc, execute, preparePrettyError, logError, requiresSocket);
1387
- return;
1388
- }
1389
- throw new JsonRpcError('unexpected message');
1479
+ layout
1480
+ } = state;
1481
+ const {
1482
+ groups
1483
+ } = layout;
1484
+ return groups.findIndex(group => group.id === groupId);
1390
1485
  };
1391
1486
 
1392
- const Two = '2.0';
1393
-
1394
- const create$d = (method, params) => {
1395
- return {
1396
- jsonrpc: Two,
1397
- method,
1398
- params
1399
- };
1487
+ const redistributeSizesWithRounding = groups => {
1488
+ return groups.map(group => ({
1489
+ ...group,
1490
+ size: Math.round(100 / groups.length)
1491
+ }));
1400
1492
  };
1401
1493
 
1402
- const create$c = (id, method, params) => {
1403
- const message = {
1404
- id,
1405
- jsonrpc: Two,
1406
- method,
1407
- params
1494
+ const withGroupsAndActiveGroup = (state, groups, activeGroupId) => {
1495
+ return {
1496
+ ...state,
1497
+ layout: {
1498
+ ...state.layout,
1499
+ activeGroupId,
1500
+ groups
1501
+ }
1408
1502
  };
1409
- return message;
1410
1503
  };
1411
1504
 
1412
- let id$1 = 0;
1413
- const create$b = () => {
1414
- return ++id$1;
1505
+ const withEmptyGroups = state => {
1506
+ return withGroupsAndActiveGroup(state, [], undefined);
1415
1507
  };
1416
1508
 
1417
- const registerPromise = map => {
1418
- const id = create$b();
1419
- const {
1420
- promise,
1421
- resolve
1422
- } = Promise.withResolvers();
1423
- map[id] = resolve;
1509
+ const withGroups = (state, groups) => {
1424
1510
  return {
1425
- id,
1426
- promise
1511
+ ...state,
1512
+ layout: {
1513
+ ...state.layout,
1514
+ groups
1515
+ }
1427
1516
  };
1428
1517
  };
1429
1518
 
1430
- const invokeHelper = async (callbacks, ipc, method, params, useSendAndTransfer) => {
1519
+ const closeTab = (state, groupId, tabId) => {
1431
1520
  const {
1432
- id,
1433
- promise
1434
- } = registerPromise(callbacks);
1435
- const message = create$c(id, method, params);
1436
- if (useSendAndTransfer && ipc.sendAndTransfer) {
1437
- ipc.sendAndTransfer(message);
1438
- } else {
1439
- ipc.send(message);
1521
+ activeGroupId,
1522
+ groups
1523
+ } = state.layout;
1524
+
1525
+ // Find the group to close the tab from
1526
+ const groupIndex = getGroupIndexById(state, groupId);
1527
+ if (groupIndex === -1) {
1528
+ return state;
1440
1529
  }
1441
- const responseMessage = await promise;
1442
- return unwrapJsonRpcResult(responseMessage);
1443
- };
1444
- const createRpc = ipc => {
1445
- const callbacks = Object.create(null);
1446
- ipc._resolve = (id, response) => {
1447
- const fn = callbacks[id];
1448
- if (!fn) {
1449
- console.warn(`callback ${id} may already be disposed`);
1450
- return;
1530
+ const group = groups[groupIndex];
1531
+ // Check if the tab exists in the group
1532
+ const tabWasRemoved = group.tabs.some(tab => tab.id === tabId);
1533
+ if (!tabWasRemoved) {
1534
+ return state;
1535
+ }
1536
+ const newGroups = groups.map(grp => {
1537
+ if (grp.id === groupId) {
1538
+ const newTabs = grp.tabs.filter(tab => tab.id !== tabId);
1539
+ let newActiveTabId = grp.activeTabId;
1540
+ if (grp.activeTabId === tabId) {
1541
+ const tabIndex = grp.tabs.findIndex(tab => tab.id === tabId);
1542
+ if (newTabs.length > 0) {
1543
+ newActiveTabId = newTabs[Math.min(tabIndex, newTabs.length - 1)].id;
1544
+ } else {
1545
+ newActiveTabId = undefined;
1546
+ }
1547
+ }
1548
+ return {
1549
+ ...grp,
1550
+ activeTabId: newActiveTabId,
1551
+ isEmpty: newTabs.length === 0,
1552
+ tabs: newTabs
1553
+ };
1451
1554
  }
1452
- fn(response);
1453
- delete callbacks[id];
1454
- };
1455
- const rpc = {
1456
- async dispose() {
1457
- await ipc?.dispose();
1458
- },
1459
- invoke(method, ...params) {
1460
- return invokeHelper(callbacks, ipc, method, params, false);
1461
- },
1462
- invokeAndTransfer(method, ...params) {
1463
- return invokeHelper(callbacks, ipc, method, params, true);
1464
- },
1465
- // @ts-ignore
1466
- ipc,
1467
- /**
1468
- * @deprecated
1469
- */
1470
- send(method, ...params) {
1471
- const message = create$d(method, params);
1472
- ipc.send(message);
1555
+ return grp;
1556
+ });
1557
+
1558
+ // If the group has no tabs left after closing, remove the group
1559
+ const groupIsNowEmpty = newGroups[groupIndex].tabs.length === 0;
1560
+ if (groupIsNowEmpty) {
1561
+ const remainingGroups = newGroups.filter(group => group.id !== groupId);
1562
+
1563
+ // If there are remaining groups, redistribute sizes
1564
+ if (remainingGroups.length > 0) {
1565
+ const redistributedGroups = redistributeSizesWithRounding(remainingGroups);
1566
+ const newActiveGroupId = activeGroupId === groupId ? remainingGroups[0]?.id : activeGroupId;
1567
+ return withGroupsAndActiveGroup(state, redistributedGroups, newActiveGroupId);
1473
1568
  }
1474
- };
1475
- return rpc;
1476
- };
1477
1569
 
1478
- const requiresSocket = () => {
1479
- return false;
1480
- };
1481
- const preparePrettyError = error => {
1482
- return error;
1483
- };
1484
- const logError = () => {
1485
- // handled by renderer worker
1486
- };
1487
- const handleMessage = event => {
1488
- const actualRequiresSocket = event?.target?.requiresSocket || requiresSocket;
1489
- const actualExecute = event?.target?.execute || execute;
1490
- return handleJsonRpcMessage(event.target, event.data, actualExecute, event.target._resolve, preparePrettyError, logError, actualRequiresSocket);
1570
+ // If no remaining groups, return empty layout
1571
+ return withEmptyGroups(state);
1572
+ }
1573
+ return withGroups(state, newGroups);
1491
1574
  };
1492
1575
 
1493
- const handleIpc = ipc => {
1494
- if ('addEventListener' in ipc) {
1495
- ipc.addEventListener('message', handleMessage);
1496
- } else if ('on' in ipc) {
1497
- // deprecated
1498
- ipc.on('message', handleMessage);
1499
- }
1576
+ const findTabInState = (state, groupId, tabId) => {
1577
+ const {
1578
+ layout
1579
+ } = state;
1580
+ const group = layout.groups.find(g => g.id === groupId);
1581
+ return group?.tabs.find(t => t.id === tabId);
1500
1582
  };
1501
1583
 
1502
- const listen$1 = async (module, options) => {
1503
- const rawIpc = await module.listen(options);
1504
- if (module.signal) {
1505
- module.signal(rawIpc);
1506
- }
1507
- const ipc = module.wrap(rawIpc);
1508
- return ipc;
1584
+ const saveEditor = async editorUid => {
1585
+ return invoke('Editor.save', editorUid);
1509
1586
  };
1510
1587
 
1511
- const create$a = async ({
1512
- commandMap,
1513
- messagePort,
1514
- requiresSocket
1515
- }) => {
1516
- // TODO create a commandMap per rpc instance
1517
- register(commandMap);
1518
- const ipc = await listen$1(IpcChildWithElectronMessagePort$1, {
1519
- messagePort
1520
- });
1521
- if (requiresSocket) {
1522
- ipc.requiresSocket = requiresSocket;
1588
+ const closeTabAndSave = async (state, groupId, tabId) => {
1589
+ const tab = findTabInState(state, groupId, tabId);
1590
+ if (!tab) {
1591
+ return state;
1523
1592
  }
1524
- handleIpc(ipc);
1525
- const rpc = createRpc(ipc);
1526
- return rpc;
1593
+ if (tab.editorUid !== -1) {
1594
+ const editorState = await saveEditor(tab.editorUid);
1595
+ if (!editorState?.modified && tab.uri) {
1596
+ await handleModifiedStatusChange$1(tab.uri, false);
1597
+ }
1598
+ }
1599
+ return closeTab(state, groupId, tabId);
1527
1600
  };
1528
1601
 
1529
- const create$9 = async ({
1530
- commandMap,
1531
- isMessagePortOpen = true,
1532
- messagePort
1533
- }) => {
1534
- // TODO create a commandMap per rpc instance
1535
- register(commandMap);
1536
- const rawIpc = await IpcParentWithMessagePort$1.create({
1537
- isMessagePortOpen,
1538
- messagePort
1539
- });
1540
- const ipc = IpcParentWithMessagePort$1.wrap(rawIpc);
1541
- handleIpc(ipc);
1542
- const rpc = createRpc(ipc);
1543
- messagePort.start();
1544
- return rpc;
1602
+ const getFocusedGroup = state => {
1603
+ const {
1604
+ layout
1605
+ } = state;
1606
+ const {
1607
+ groups
1608
+ } = layout;
1609
+ return groups.find(group => group.focused);
1545
1610
  };
1546
1611
 
1547
- const create$8 = async ({
1548
- commandMap,
1549
- isMessagePortOpen,
1550
- send
1551
- }) => {
1612
+ const closeActiveEditor = async state => {
1613
+ const focusedGroup = getFocusedGroup(state);
1614
+ if (!focusedGroup) {
1615
+ return state;
1616
+ }
1552
1617
  const {
1553
- port1,
1554
- port2
1555
- } = new MessageChannel();
1556
- await send(port1);
1557
- return create$9({
1558
- commandMap,
1559
- isMessagePortOpen,
1560
- messagePort: port2
1561
- });
1618
+ activeTabId
1619
+ } = focusedGroup;
1620
+ if (activeTabId === undefined) {
1621
+ return state;
1622
+ }
1623
+ return closeTabAndSave(state, focusedGroup.id, activeTabId);
1562
1624
  };
1563
1625
 
1564
- const createSharedLazyRpc = factory => {
1565
- let rpcPromise;
1566
- const getOrCreate = () => {
1567
- if (!rpcPromise) {
1568
- rpcPromise = factory();
1569
- }
1570
- return rpcPromise;
1571
- };
1572
- return {
1573
- async dispose() {
1574
- const rpc = await getOrCreate();
1575
- await rpc.dispose();
1576
- },
1577
- async invoke(method, ...params) {
1578
- const rpc = await getOrCreate();
1579
- return rpc.invoke(method, ...params);
1580
- },
1581
- async invokeAndTransfer(method, ...params) {
1582
- const rpc = await getOrCreate();
1583
- return rpc.invokeAndTransfer(method, ...params);
1584
- },
1585
- async send(method, ...params) {
1586
- const rpc = await getOrCreate();
1587
- rpc.send(method, ...params);
1588
- }
1589
- };
1626
+ const closeAll$1 = state => {
1627
+ return withEmptyGroups(state);
1590
1628
  };
1591
1629
 
1592
- const create$7 = async ({
1593
- commandMap,
1594
- getPortTuple,
1595
- send
1596
- }) => {
1597
- const {
1598
- port1,
1599
- port2
1600
- } = await getPortTuple();
1601
- await send(port1);
1602
- const rpc = create$a({
1603
- commandMap,
1604
- messagePort: port2
1605
- });
1606
- return rpc;
1630
+ const redistributeSizesWithRemainder = groups => {
1631
+ const baseSize = Math.floor(100 / groups.length);
1632
+ const remainder = 100 % groups.length;
1633
+ return groups.map((group, index) => ({
1634
+ ...group,
1635
+ size: baseSize + (index === groups.length - 1 ? remainder : 0)
1636
+ }));
1607
1637
  };
1608
1638
 
1609
- const create$6 = async ({
1610
- commandMap,
1611
- getPortTuple,
1612
- send
1613
- }) => {
1614
- return createSharedLazyRpc(() => {
1615
- return create$7({
1616
- commandMap,
1617
- getPortTuple,
1618
- send
1619
- });
1620
- });
1639
+ const closeEditorGroup$1 = (state, groupId) => {
1640
+ if (Number.isNaN(groupId)) {
1641
+ return state;
1642
+ }
1643
+ const {
1644
+ layout
1645
+ } = state;
1646
+ const {
1647
+ activeGroupId,
1648
+ groups
1649
+ } = layout;
1650
+ const groupIndex = getGroupIndexById(state, groupId);
1651
+ if (groupIndex === -1 || groups.length <= 1) {
1652
+ return state;
1653
+ }
1654
+ const remainingGroups = groups.filter(group => group.id !== groupId);
1655
+ const redistributedGroups = redistributeSizesWithRemainder(remainingGroups);
1656
+ const newActiveGroupId = activeGroupId === groupId ? remainingGroups[0].id : activeGroupId;
1657
+ return withGroupsAndActiveGroup(state, redistributedGroups, newActiveGroupId);
1621
1658
  };
1622
1659
 
1623
- const create$5 = async ({
1624
- commandMap,
1625
- isMessagePortOpen,
1626
- send
1627
- }) => {
1628
- return createSharedLazyRpc(() => {
1629
- return create$8({
1630
- commandMap,
1631
- isMessagePortOpen,
1632
- send
1633
- });
1634
- });
1660
+ const isFocused = group => {
1661
+ return group.focused;
1635
1662
  };
1636
-
1637
- const create$4 = async ({
1638
- commandMap
1639
- }) => {
1640
- // TODO create a commandMap per rpc instance
1641
- register(commandMap);
1642
- const ipc = await listen$1(IpcChildWithModuleWorkerAndMessagePort$1);
1643
- handleIpc(ipc);
1644
- const rpc = createRpc(ipc);
1645
- return rpc;
1663
+ const closeFocusedTab = async state => {
1664
+ const {
1665
+ layout
1666
+ } = state;
1667
+ const {
1668
+ groups
1669
+ } = layout;
1670
+ const focusedGroup = groups.find(isFocused);
1671
+ if (!focusedGroup) {
1672
+ return state;
1673
+ }
1674
+ const {
1675
+ activeTabId
1676
+ } = focusedGroup;
1677
+ if (activeTabId === undefined) {
1678
+ return state;
1679
+ }
1680
+ return closeTabAndSave(state, focusedGroup.id, activeTabId);
1646
1681
  };
1647
1682
 
1648
- const createMockRpc = ({
1649
- commandMap
1650
- }) => {
1651
- const invocations = [];
1652
- const invoke = (method, ...params) => {
1653
- invocations.push([method, ...params]);
1654
- const command = commandMap[method];
1655
- if (!command) {
1656
- throw new Error(`command ${method} not found`);
1683
+ const closeOtherTabs = (state, groupId) => {
1684
+ const {
1685
+ layout
1686
+ } = state;
1687
+ const {
1688
+ activeGroupId,
1689
+ groups
1690
+ } = layout;
1691
+ const targetGroupId = groupId ?? activeGroupId;
1692
+ if (targetGroupId === undefined) {
1693
+ return state;
1694
+ }
1695
+ const group = groups.find(g => g.id === targetGroupId);
1696
+ if (!group) {
1697
+ return state;
1698
+ }
1699
+ const {
1700
+ activeTabId
1701
+ } = group;
1702
+ if (activeTabId === undefined) {
1703
+ return state;
1704
+ }
1705
+ const newGroups = groups.map(g => {
1706
+ if (g.id === targetGroupId) {
1707
+ const newTabs = g.tabs.filter(tab => tab.id === activeTabId);
1708
+ return {
1709
+ ...g,
1710
+ activeTabId,
1711
+ isEmpty: newTabs.length === 0,
1712
+ tabs: newTabs
1713
+ };
1714
+ }
1715
+ return g;
1716
+ });
1717
+ return {
1718
+ ...state,
1719
+ layout: {
1720
+ ...layout,
1721
+ groups: newGroups
1657
1722
  }
1658
- return command(...params);
1659
- };
1660
- const mockRpc = {
1661
- invocations,
1662
- invoke,
1663
- invokeAndTransfer: invoke
1664
1723
  };
1665
- return mockRpc;
1666
1724
  };
1667
1725
 
1668
- const rpcs = Object.create(null);
1669
- const set$5 = (id, rpc) => {
1670
- rpcs[id] = rpc;
1726
+ const getNextActiveTabId = (tabs, newTabs, activeTabId) => {
1727
+ if (activeTabId === undefined) {
1728
+ return undefined;
1729
+ }
1730
+ if (newTabs.some(tab => tab.id === activeTabId)) {
1731
+ return activeTabId;
1732
+ }
1733
+ const activeTabIndex = tabs.findIndex(tab => tab.id === activeTabId);
1734
+ if (activeTabIndex === -1 || newTabs.length === 0) {
1735
+ return undefined;
1736
+ }
1737
+ return newTabs[Math.min(activeTabIndex, newTabs.length - 1)].id;
1671
1738
  };
1672
- const get$1 = id => {
1673
- return rpcs[id];
1739
+ const closeSavedInGroup = group => {
1740
+ const {
1741
+ activeTabId,
1742
+ tabs
1743
+ } = group;
1744
+ const newTabs = tabs.filter(tab => tab.isDirty);
1745
+ if (newTabs.length === tabs.length) {
1746
+ return group;
1747
+ }
1748
+ const newActiveTabId = getNextActiveTabId(tabs, newTabs, activeTabId);
1749
+ return {
1750
+ ...group,
1751
+ activeTabId: newActiveTabId,
1752
+ isEmpty: newTabs.length === 0,
1753
+ tabs: newTabs
1754
+ };
1674
1755
  };
1675
- const remove = id => {
1676
- delete rpcs[id];
1756
+ const closeSaved$1 = state => {
1757
+ const {
1758
+ groups
1759
+ } = state.layout;
1760
+ const newGroups = groups.map(closeSavedInGroup);
1761
+ return withGroups(state, newGroups);
1677
1762
  };
1678
1763
 
1679
- /* eslint-disable @typescript-eslint/explicit-function-return-type */
1680
- const create$3 = rpcId => {
1681
- return {
1682
- async dispose() {
1683
- const rpc = get$1(rpcId);
1684
- await rpc.dispose();
1685
- },
1686
- // @ts-ignore
1687
- invoke(method, ...params) {
1688
- const rpc = get$1(rpcId);
1689
- // @ts-ignore
1690
- return rpc.invoke(method, ...params);
1691
- },
1692
- // @ts-ignore
1693
- invokeAndTransfer(method, ...params) {
1694
- const rpc = get$1(rpcId);
1695
- // @ts-ignore
1696
- return rpc.invokeAndTransfer(method, ...params);
1697
- },
1698
- registerMockRpc(commandMap) {
1699
- const mockRpc = createMockRpc({
1700
- commandMap
1764
+ const closeTabsByUris = (state, uris) => {
1765
+ let currentState = state;
1766
+ for (const uri of uris) {
1767
+ while (true) {
1768
+ const matchingGroup = currentState.layout.groups.find(group => {
1769
+ return group.tabs.some(tab => tab.uri === uri);
1701
1770
  });
1702
- set$5(rpcId, mockRpc);
1703
- // @ts-ignore
1704
- mockRpc[Symbol.dispose] = () => {
1705
- remove(rpcId);
1706
- };
1707
- // @ts-ignore
1708
- return mockRpc;
1709
- },
1710
- set(rpc) {
1711
- set$5(rpcId, rpc);
1771
+ if (!matchingGroup) {
1772
+ break;
1773
+ }
1774
+ const matchingTab = matchingGroup.tabs.find(tab => tab.uri === uri);
1775
+ if (!matchingTab) {
1776
+ break;
1777
+ }
1778
+ currentState = closeTab(currentState, matchingGroup.id, matchingTab.id);
1712
1779
  }
1713
- };
1780
+ }
1781
+ return currentState;
1714
1782
  };
1715
1783
 
1716
- const None$1 = 'none';
1717
-
1718
- const Button$2 = 1;
1719
- const Div = 4;
1720
- const Span = 8;
1721
- const Text = 12;
1722
- const Img = 17;
1723
- const P = 50;
1724
- const Pre = 51;
1725
- const Reference = 100;
1726
-
1727
- const Button$1 = 'event.button';
1728
- const ClientX = 'event.clientX';
1729
- const ClientY = 'event.clientY';
1730
- const EventTargetClassName = 'event.target.className';
1731
- const TargetName = 'event.target.name';
1732
-
1733
- const Tab = 13;
1734
- const Main$1 = 24;
1735
-
1736
- const Separator = 1;
1737
- const None = 0;
1738
-
1739
- const Electron = 2;
1740
-
1741
- const ClipBoardWorker = 3400;
1742
- const ExtensionHostWorker = 44;
1743
- const IconThemeWorker = 7009;
1744
- const RendererWorker = 1;
1745
-
1746
- const SetCss = 'Viewlet.setCss';
1747
- const SetDom2 = 'Viewlet.setDom2';
1748
- const SetPatches = 'Viewlet.setPatches';
1749
-
1750
- const {
1751
- set: set$4
1752
- } = create$3(ClipBoardWorker);
1753
-
1754
- const {
1755
- set: set$3
1756
- } = create$3(ExtensionHostWorker);
1757
-
1758
- const {
1759
- invoke: invoke$1,
1760
- set: set$2
1761
- } = create$3(IconThemeWorker);
1762
- const getIcons = async iconRequests => {
1763
- // @ts-ignore
1764
- return invoke$1('IconTheme.getIcons', iconRequests);
1784
+ const getGroupById = (state, groupId) => {
1785
+ return state.layout.groups.find(group => group.id === groupId);
1765
1786
  };
1766
1787
 
1767
- const {
1768
- invoke,
1769
- invokeAndTransfer,
1770
- set: set$1
1771
- } = create$3(RendererWorker);
1772
- const showContextMenu2 = async (uid, menuId, x, y, args) => {
1773
- number(uid);
1774
- number(menuId);
1775
- number(x);
1776
- number(y);
1777
- await invoke('ContextMenu.show2', uid, menuId, x, y, args);
1778
- };
1779
- const sendMessagePortToClipBoardWorker$1 = async (port, rpcId) => {
1780
- const command = 'ClipBoard.handleMessagePort';
1781
- await invokeAndTransfer('SendMessagePortToExtensionHostWorker.sendMessagePortToClipBoardWorker', port, command, rpcId);
1782
- };
1783
- const sendMessagePortToIconThemeWorker = async (port, rpcId) => {
1784
- const command = 'IconTheme.handleMessagePort';
1785
- await invokeAndTransfer('SendMessagePortToExtensionHostWorker.sendMessagePortToIconThemeWorker', port, command, rpcId);
1786
- };
1787
- const readFile = async uri => {
1788
- return invoke('FileSystem.readFile', uri);
1789
- };
1790
- const sendMessagePortToExtensionHostWorker$1 = async (port, rpcId = 0) => {
1791
- const command = 'HandleMessagePort.handleMessagePort2';
1792
- await invokeAndTransfer('SendMessagePortToExtensionHostWorker.sendMessagePortToExtensionHostWorker', port, command, rpcId);
1793
- };
1794
- const writeClipBoardText = async text => {
1795
- await invoke('ClipBoard.writeText', /* text */text);
1788
+ const closeTabsRight = (state, groupId) => {
1789
+ const {
1790
+ layout
1791
+ } = state;
1792
+ const {
1793
+ groups
1794
+ } = layout;
1795
+ const group = getGroupById(state, groupId);
1796
+ if (!group) {
1797
+ return state;
1798
+ }
1799
+ const {
1800
+ activeTabId,
1801
+ tabs
1802
+ } = group;
1803
+ if (activeTabId === undefined) {
1804
+ return state;
1805
+ }
1806
+ const activeTabIndex = tabs.findIndex(tab => tab.id === activeTabId);
1807
+ if (activeTabIndex === -1) {
1808
+ return state;
1809
+ }
1810
+ const newTabs = tabs.slice(0, activeTabIndex + 1);
1811
+ if (newTabs.length === tabs.length) {
1812
+ return state;
1813
+ }
1814
+ const newGroups = groups.map(g => {
1815
+ if (g.id === groupId) {
1816
+ return {
1817
+ ...g,
1818
+ isEmpty: newTabs.length === 0,
1819
+ tabs: newTabs
1820
+ };
1821
+ }
1822
+ return g;
1823
+ });
1824
+ return withGroups(state, newGroups);
1796
1825
  };
1797
1826
 
1798
1827
  const copyPath$1 = async (state, path) => {
@@ -2196,6 +2225,7 @@ const getViewletModuleId$1 = async uri => {
2196
2225
  };
2197
2226
 
2198
2227
  const DiffEditor = 'DiffEditor';
2228
+ const EditorText = 'Editor';
2199
2229
  const ExtensionDetail = 'ExtensionDetail';
2200
2230
  const QuickPick = 'QuickPick';
2201
2231
 
@@ -3434,7 +3464,7 @@ const handleClickAction = async (state, action, rawGroupId) => {
3434
3464
  }
3435
3465
  };
3436
3466
 
3437
- const handleClickCloseTab = (state, rawGroupIndex, rawIndex) => {
3467
+ const handleClickCloseTab = async (state, rawGroupIndex, rawIndex) => {
3438
3468
  if (!rawGroupIndex || !rawIndex) {
3439
3469
  return state;
3440
3470
  }
@@ -3458,7 +3488,7 @@ const handleClickCloseTab = (state, rawGroupIndex, rawIndex) => {
3458
3488
  const tab = group.tabs[index];
3459
3489
  const groupId = group.id;
3460
3490
  const tabId = tab.id;
3461
- return closeTab(state, groupId, tabId);
3491
+ return closeTabAndSave(state, groupId, tabId);
3462
3492
  };
3463
3493
 
3464
3494
  const handleClickTab = async (state, groupIndexRaw, indexRaw) => {
@@ -3605,6 +3635,7 @@ const newFile = async state => {
3605
3635
  x: stateWithNewTab.x,
3606
3636
  y: stateWithNewTab.y + stateWithNewTab.tabHeight
3607
3637
  };
3638
+ const viewletModuleId = EditorText;
3608
3639
  const stateWithViewlet = createViewletForTab(stateWithNewTab, tabId);
3609
3640
  let intermediateState = stateWithViewlet;
3610
3641
 
@@ -3626,7 +3657,7 @@ const newFile = async state => {
3626
3657
  if (actualEditorUid === -1) {
3627
3658
  throw new Error(`invalid editorUid`);
3628
3659
  }
3629
- await createViewlet('Editor', actualEditorUid, tabId, bounds, newTab.uri || '');
3660
+ await createViewlet(viewletModuleId, actualEditorUid, tabId, bounds, newTab.uri || '');
3630
3661
 
3631
3662
  // After viewlet is created, get the latest state and mark it as ready
3632
3663
  const {
@@ -5553,33 +5584,54 @@ const renderEventListeners = () => {
5553
5584
  }];
5554
5585
  };
5555
5586
 
5556
- const saveEditor = async editorUid => {
5557
- await invoke('Editor.save', editorUid);
5558
- };
5559
- const getEditorSaveState = async editorUid => {
5560
- return invoke('Editor.saveState', editorUid);
5587
+ const getLatestStoredState = (uid, fallbackState, referenceTabId, referenceTabUri, allowMissingReference = false) => {
5588
+ const stateFromStore = get(uid);
5589
+ if (!stateFromStore) {
5590
+ return fallbackState;
5591
+ }
5592
+ const storedState = stateFromStore.newState;
5593
+ const storedActiveTabData = getActiveTab(storedState);
5594
+ if (!storedActiveTabData) {
5595
+ return fallbackState;
5596
+ }
5597
+ if (allowMissingReference && referenceTabId === undefined && referenceTabUri === undefined) {
5598
+ return storedState;
5599
+ }
5600
+ if (storedActiveTabData.tab.id === referenceTabId) {
5601
+ return storedState;
5602
+ }
5603
+ if (referenceTabUri && storedActiveTabData.tab.uri === referenceTabUri) {
5604
+ return storedState;
5605
+ }
5606
+ return fallbackState;
5561
5607
  };
5562
-
5563
5608
  const save = async state => {
5564
- const activeTabData = getActiveTab(state);
5609
+ const requestedActiveTabData = getActiveTab(state);
5610
+ const currentState = getLatestStoredState(state.uid, state, requestedActiveTabData?.tab.id, requestedActiveTabData?.tab.uri, !requestedActiveTabData);
5611
+ const activeTabData = getActiveTab(currentState);
5565
5612
  if (!activeTabData) {
5566
- return state;
5613
+ return currentState;
5567
5614
  }
5568
5615
  const {
5569
5616
  tab
5570
5617
  } = activeTabData;
5571
5618
  if (tab.loadingState === 'loading') {
5572
- return state;
5619
+ return currentState;
5573
5620
  }
5574
- await saveEditor(tab.editorUid);
5575
5621
  if (!tab.isDirty) {
5576
- return state;
5622
+ await saveEditor(tab.editorUid);
5623
+ return getLatestStoredState(state.uid, currentState, tab.id, tab.uri);
5577
5624
  }
5578
- const editorState = await getEditorSaveState(tab.editorUid);
5579
- if (editorState.modified) {
5580
- return state;
5625
+ const editorState = await saveEditor(tab.editorUid);
5626
+ const latestState = getLatestStoredState(state.uid, currentState, tab.id, tab.uri);
5627
+ if (editorState?.modified) {
5628
+ return latestState;
5629
+ }
5630
+ if (tab.uri) {
5631
+ await handleModifiedStatusChange$1(tab.uri, false);
5581
5632
  }
5582
- return updateTab(state, tab.id, {
5633
+ const stateAfterModifiedStatusChange = getLatestStoredState(state.uid, latestState, tab.id, tab.uri);
5634
+ return updateTab(stateAfterModifiedStatusChange, tab.id, {
5583
5635
  isDirty: false
5584
5636
  });
5585
5637
  };
@@ -5768,6 +5820,7 @@ const commandMap = {
5768
5820
  'Main.focusNextTab': wrapCommand(focusNextTab),
5769
5821
  'Main.focusPrevious': wrapCommand(focusPreviousTab),
5770
5822
  'Main.focusPreviousTab': wrapCommand(focusPreviousTab),
5823
+ 'Main.handleModifiedStatusChange': wrapCommand(handleModifiedStatusChange),
5771
5824
  'Main.handleTabContextMenu': wrapCommand(handleTabContextMenu),
5772
5825
  'Main.openInput': wrapCommand(openInput),
5773
5826
  'Main.openUri': wrapCommand(openUri),