@lvce-editor/main-area-worker 9.11.0 → 9.13.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) {
@@ -1769,6 +1445,9 @@ const {
1769
1445
  invokeAndTransfer,
1770
1446
  set: set$1
1771
1447
  } = create$3(RendererWorker);
1448
+ const handleModifiedStatusChange$1 = async (uri, modified) => {
1449
+ return invoke('Main.handleModifiedStatusChange', uri, modified);
1450
+ };
1772
1451
  const showContextMenu2 = async (uid, menuId, x, y, args) => {
1773
1452
  number(uid);
1774
1453
  number(menuId);
@@ -1795,6 +1474,356 @@ const writeClipBoardText = async text => {
1795
1474
  await invoke('ClipBoard.writeText', /* text */text);
1796
1475
  };
1797
1476
 
1477
+ const getGroupIndexById = (state, groupId) => {
1478
+ const {
1479
+ layout
1480
+ } = state;
1481
+ const {
1482
+ groups
1483
+ } = layout;
1484
+ return groups.findIndex(group => group.id === groupId);
1485
+ };
1486
+
1487
+ const redistributeSizesWithRounding = groups => {
1488
+ return groups.map(group => ({
1489
+ ...group,
1490
+ size: Math.round(100 / groups.length)
1491
+ }));
1492
+ };
1493
+
1494
+ const withGroupsAndActiveGroup = (state, groups, activeGroupId) => {
1495
+ return {
1496
+ ...state,
1497
+ layout: {
1498
+ ...state.layout,
1499
+ activeGroupId,
1500
+ groups
1501
+ }
1502
+ };
1503
+ };
1504
+
1505
+ const withEmptyGroups = state => {
1506
+ return withGroupsAndActiveGroup(state, [], undefined);
1507
+ };
1508
+
1509
+ const withGroups = (state, groups) => {
1510
+ return {
1511
+ ...state,
1512
+ layout: {
1513
+ ...state.layout,
1514
+ groups
1515
+ }
1516
+ };
1517
+ };
1518
+
1519
+ const closeTab = (state, groupId, tabId) => {
1520
+ const {
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;
1529
+ }
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
+ };
1554
+ }
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);
1568
+ }
1569
+
1570
+ // If no remaining groups, return empty layout
1571
+ return withEmptyGroups(state);
1572
+ }
1573
+ return withGroups(state, newGroups);
1574
+ };
1575
+
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);
1582
+ };
1583
+
1584
+ const saveEditor = async editorUid => {
1585
+ return invoke('Editor.save', editorUid);
1586
+ };
1587
+
1588
+ const closeTabAndSave = async (state, groupId, tabId) => {
1589
+ const tab = findTabInState(state, groupId, tabId);
1590
+ if (!tab) {
1591
+ return state;
1592
+ }
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);
1600
+ };
1601
+
1602
+ const getFocusedGroup = state => {
1603
+ const {
1604
+ layout
1605
+ } = state;
1606
+ const {
1607
+ groups
1608
+ } = layout;
1609
+ return groups.find(group => group.focused);
1610
+ };
1611
+
1612
+ const closeActiveEditor = async state => {
1613
+ const focusedGroup = getFocusedGroup(state);
1614
+ if (!focusedGroup) {
1615
+ return state;
1616
+ }
1617
+ const {
1618
+ activeTabId
1619
+ } = focusedGroup;
1620
+ if (activeTabId === undefined) {
1621
+ return state;
1622
+ }
1623
+ return closeTabAndSave(state, focusedGroup.id, activeTabId);
1624
+ };
1625
+
1626
+ const closeAll$1 = state => {
1627
+ return withEmptyGroups(state);
1628
+ };
1629
+
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
+ }));
1637
+ };
1638
+
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);
1658
+ };
1659
+
1660
+ const isFocused = group => {
1661
+ return group.focused;
1662
+ };
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);
1681
+ };
1682
+
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
1722
+ }
1723
+ };
1724
+ };
1725
+
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;
1738
+ };
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
+ };
1755
+ };
1756
+ const closeSaved$1 = state => {
1757
+ const {
1758
+ groups
1759
+ } = state.layout;
1760
+ const newGroups = groups.map(closeSavedInGroup);
1761
+ return withGroups(state, newGroups);
1762
+ };
1763
+
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);
1770
+ });
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);
1779
+ }
1780
+ }
1781
+ return currentState;
1782
+ };
1783
+
1784
+ const getGroupById = (state, groupId) => {
1785
+ return state.layout.groups.find(group => group.id === groupId);
1786
+ };
1787
+
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);
1825
+ };
1826
+
1798
1827
  const copyPath$1 = async (state, path) => {
1799
1828
  string(path);
1800
1829
  await writeClipBoardText(path);
@@ -1899,6 +1928,99 @@ const diff2 = uid => {
1899
1928
  return result;
1900
1929
  };
1901
1930
 
1931
+ const getActiveTabId$1 = state => {
1932
+ const {
1933
+ layout
1934
+ } = state;
1935
+ const {
1936
+ activeGroupId,
1937
+ groups
1938
+ } = layout;
1939
+ const activeGroup = groups.find(group => group.id === activeGroupId);
1940
+ return activeGroup?.activeTabId;
1941
+ };
1942
+
1943
+ const getSelectedTabBounds = state => {
1944
+ return {
1945
+ height: state.height - state.tabHeight,
1946
+ width: state.width,
1947
+ x: state.x,
1948
+ y: state.y + state.tabHeight
1949
+ };
1950
+ };
1951
+
1952
+ const getSelectedTabData = (state, groupIndex, index) => {
1953
+ const group = state.layout.groups[groupIndex];
1954
+ if (!group || index < 0 || index >= group.tabs.length) {
1955
+ return undefined;
1956
+ }
1957
+ const tab = group.tabs[index];
1958
+ return {
1959
+ group,
1960
+ groupId: group.id,
1961
+ tab,
1962
+ tabId: tab.id
1963
+ };
1964
+ };
1965
+
1966
+ const getUpdatedGroups = (groups, groupIndex, needsLoading, tabId) => {
1967
+ return groups.map((group, index) => {
1968
+ if (index !== groupIndex) {
1969
+ return {
1970
+ ...group,
1971
+ focused: false
1972
+ };
1973
+ }
1974
+ const tabs = needsLoading ? group.tabs.map(tab => {
1975
+ if (tab.id !== tabId) {
1976
+ return tab;
1977
+ }
1978
+ return {
1979
+ ...tab,
1980
+ errorMessage: '',
1981
+ loadingState: 'loading'
1982
+ };
1983
+ }) : group.tabs;
1984
+ return {
1985
+ ...group,
1986
+ activeTabId: tabId,
1987
+ focused: true,
1988
+ tabs
1989
+ };
1990
+ });
1991
+ };
1992
+
1993
+ const getViewletModuleId$1 = async uri => {
1994
+ // Query RendererWorker for viewlet module ID (optional, may fail in tests)
1995
+ let viewletModuleId;
1996
+ try {
1997
+ viewletModuleId = await invoke('Layout.getModuleId', uri);
1998
+ } catch {
1999
+ // Viewlet creation is optional - silently ignore if RendererWorker isn't available
2000
+ }
2001
+ return viewletModuleId;
2002
+ };
2003
+
2004
+ const DiffEditor = 'DiffEditor';
2005
+ const EditorText = 'Editor';
2006
+ const ExtensionDetail = 'ExtensionDetail';
2007
+ const QuickPick = 'QuickPick';
2008
+
2009
+ const getViewletModuleIdForEditorInput = async editorInput => {
2010
+ switch (editorInput.type) {
2011
+ case 'diff-editor':
2012
+ return DiffEditor;
2013
+ case 'editor':
2014
+ return getViewletModuleId$1(editorInput.uri);
2015
+ case 'extension-detail-view':
2016
+ return ExtensionDetail;
2017
+ }
2018
+ };
2019
+
2020
+ const getViewletModuleId = async tab => {
2021
+ return tab.editorInput ? getViewletModuleIdForEditorInput(tab.editorInput) : invoke('Layout.getModuleId', tab.uri);
2022
+ };
2023
+
1902
2024
  const createViewlet = async (viewletModuleId, editorUid, tabId, bounds, uri) => {
1903
2025
  await invoke('Layout.createViewlet', viewletModuleId, editorUid, tabId, bounds, uri);
1904
2026
  };
@@ -2178,54 +2300,6 @@ const findTabById = (state, tabId) => {
2178
2300
  return undefined;
2179
2301
  };
2180
2302
 
2181
- // Counter for request IDs to handle race conditions
2182
- let requestIdCounter = 0;
2183
- const getNextRequestId = () => {
2184
- return ++requestIdCounter;
2185
- };
2186
-
2187
- const getViewletModuleId$1 = async uri => {
2188
- // Query RendererWorker for viewlet module ID (optional, may fail in tests)
2189
- let viewletModuleId;
2190
- try {
2191
- viewletModuleId = await invoke('Layout.getModuleId', uri);
2192
- } catch {
2193
- // Viewlet creation is optional - silently ignore if RendererWorker isn't available
2194
- }
2195
- return viewletModuleId;
2196
- };
2197
-
2198
- const DiffEditor = 'DiffEditor';
2199
- const ExtensionDetail = 'ExtensionDetail';
2200
- const QuickPick = 'QuickPick';
2201
-
2202
- const getViewletModuleIdForEditorInput = async editorInput => {
2203
- switch (editorInput.type) {
2204
- case 'diff-editor':
2205
- return DiffEditor;
2206
- case 'editor':
2207
- return getViewletModuleId$1(editorInput.uri);
2208
- case 'extension-detail-view':
2209
- return ExtensionDetail;
2210
- }
2211
- };
2212
-
2213
- const shouldLoadContentForTab = tab => {
2214
- if (tab.editorInput && tab.editorInput.type !== 'editor') {
2215
- return false;
2216
- }
2217
- if (!tab.uri) {
2218
- return false;
2219
- }
2220
- if (tab.loadingState === 'loading') {
2221
- return false;
2222
- }
2223
- if (tab.loadingState === 'loaded' && tab.editorUid !== -1) {
2224
- return false;
2225
- }
2226
- return true;
2227
- };
2228
-
2229
2303
  const startContentLoading = async (oldState, state, tabId, path, requestId) => {
2230
2304
  try {
2231
2305
  const getLatestState = () => {
@@ -2240,76 +2314,17 @@ const startContentLoading = async (oldState, state, tabId, path, requestId) => {
2240
2314
  return state;
2241
2315
  };
2242
2316
 
2243
- const getActiveTabId$1 = state => {
2244
- const {
2245
- layout
2246
- } = state;
2247
- const {
2248
- activeGroupId,
2249
- groups
2250
- } = layout;
2251
- const activeGroup = groups.find(g => g.id === activeGroupId);
2252
- return activeGroup?.activeTabId;
2253
- };
2254
- const getSelectedTabData = (state, groupIndex, index) => {
2255
- const group = state.layout.groups[groupIndex];
2256
- if (!group || index < 0 || index >= group.tabs.length) {
2257
- return undefined;
2258
- }
2259
- const tab = group.tabs[index];
2260
- return {
2261
- group,
2262
- groupId: group.id,
2263
- tab,
2264
- tabId: tab.id
2265
- };
2266
- };
2267
- const getUpdatedGroups = (groups, groupIndex, needsLoading, tabId) => {
2268
- return groups.map((group, index) => {
2269
- if (index !== groupIndex) {
2270
- return {
2271
- ...group,
2272
- focused: false
2273
- };
2274
- }
2275
- const tabs = needsLoading ? group.tabs.map(tab => {
2276
- if (tab.id !== tabId) {
2277
- return tab;
2278
- }
2279
- return {
2280
- ...tab,
2281
- errorMessage: '',
2282
- loadingState: 'loading'
2283
- };
2284
- }) : group.tabs;
2285
- return {
2286
- ...group,
2287
- activeTabId: tabId,
2288
- focused: true,
2289
- tabs
2290
- };
2291
- });
2292
- };
2293
- const shouldCreateViewletForSelectedTab = tab => {
2294
- return Boolean(tab.uri) && (tab.editorUid === -1 || !tab.loadingState || tab.loadingState === 'loading');
2295
- };
2296
- const getSelectedTabBounds = state => {
2297
- return {
2298
- height: state.height - state.tabHeight,
2299
- width: state.width,
2300
- x: state.x,
2301
- y: state.y + state.tabHeight
2302
- };
2303
- };
2304
- const getViewletModuleId = async tab => {
2305
- return tab.editorInput ? getViewletModuleIdForEditorInput(tab.editorInput) : invoke('Layout.getModuleId', tab.uri);
2306
- };
2307
2317
  const maybeStartLoading = async (state, newState, tabId, tab, needsLoading, requestId) => {
2308
2318
  if (needsLoading && tab.uri) {
2309
2319
  return startContentLoading(state, newState, tabId, tab.uri, requestId);
2310
2320
  }
2311
2321
  return newState;
2312
2322
  };
2323
+
2324
+ const shouldCreateViewletForSelectedTab = tab => {
2325
+ return Boolean(tab.uri) && (tab.editorUid === -1 || !tab.loadingState || tab.loadingState === 'loading');
2326
+ };
2327
+
2313
2328
  const maybeCreateViewletForSelectedTab = async (state, newState, groupIndex, index, tabId, tab, uid, needsLoading, requestId, switchCommands) => {
2314
2329
  const selectedTab = newState.layout.groups[groupIndex].tabs[index];
2315
2330
  if (!shouldCreateViewletForSelectedTab(selectedTab)) {
@@ -2338,6 +2353,29 @@ const maybeCreateViewletForSelectedTab = async (state, newState, groupIndex, ind
2338
2353
  }
2339
2354
  return maybeStartLoading(state, stateWithViewlet, tabId, tab, needsLoading, requestId);
2340
2355
  };
2356
+
2357
+ // Counter for request IDs to handle race conditions
2358
+ let requestIdCounter = 0;
2359
+ const getNextRequestId = () => {
2360
+ return ++requestIdCounter;
2361
+ };
2362
+
2363
+ const shouldLoadContentForTab = tab => {
2364
+ if (tab.editorInput && tab.editorInput.type !== 'editor') {
2365
+ return false;
2366
+ }
2367
+ if (!tab.uri) {
2368
+ return false;
2369
+ }
2370
+ if (tab.loadingState === 'loading') {
2371
+ return false;
2372
+ }
2373
+ if (tab.loadingState === 'loaded' && tab.editorUid !== -1) {
2374
+ return false;
2375
+ }
2376
+ return true;
2377
+ };
2378
+
2341
2379
  const selectTab = async (state, groupIndex, index) => {
2342
2380
  const {
2343
2381
  layout,
@@ -3434,7 +3472,7 @@ const handleClickAction = async (state, action, rawGroupId) => {
3434
3472
  }
3435
3473
  };
3436
3474
 
3437
- const handleClickCloseTab = (state, rawGroupIndex, rawIndex) => {
3475
+ const handleClickCloseTab = async (state, rawGroupIndex, rawIndex) => {
3438
3476
  if (!rawGroupIndex || !rawIndex) {
3439
3477
  return state;
3440
3478
  }
@@ -3458,7 +3496,7 @@ const handleClickCloseTab = (state, rawGroupIndex, rawIndex) => {
3458
3496
  const tab = group.tabs[index];
3459
3497
  const groupId = group.id;
3460
3498
  const tabId = tab.id;
3461
- return closeTab(state, groupId, tabId);
3499
+ return closeTabAndSave(state, groupId, tabId);
3462
3500
  };
3463
3501
 
3464
3502
  const handleClickTab = async (state, groupIndexRaw, indexRaw) => {
@@ -3605,6 +3643,7 @@ const newFile = async state => {
3605
3643
  x: stateWithNewTab.x,
3606
3644
  y: stateWithNewTab.y + stateWithNewTab.tabHeight
3607
3645
  };
3646
+ const viewletModuleId = EditorText;
3608
3647
  const stateWithViewlet = createViewletForTab(stateWithNewTab, tabId);
3609
3648
  let intermediateState = stateWithViewlet;
3610
3649
 
@@ -3626,7 +3665,7 @@ const newFile = async state => {
3626
3665
  if (actualEditorUid === -1) {
3627
3666
  throw new Error(`invalid editorUid`);
3628
3667
  }
3629
- await createViewlet('Editor', actualEditorUid, tabId, bounds, newTab.uri || '');
3668
+ await createViewlet(viewletModuleId, actualEditorUid, tabId, bounds, newTab.uri || '');
3630
3669
 
3631
3670
  // After viewlet is created, get the latest state and mark it as ready
3632
3671
  const {
@@ -5553,33 +5592,54 @@ const renderEventListeners = () => {
5553
5592
  }];
5554
5593
  };
5555
5594
 
5556
- const saveEditor = async editorUid => {
5557
- await invoke('Editor.save', editorUid);
5558
- };
5559
- const getEditorSaveState = async editorUid => {
5560
- return invoke('Editor.saveState', editorUid);
5595
+ const getLatestStoredState = (uid, fallbackState, referenceTabId, referenceTabUri, allowMissingReference = false) => {
5596
+ const stateFromStore = get(uid);
5597
+ if (!stateFromStore) {
5598
+ return fallbackState;
5599
+ }
5600
+ const storedState = stateFromStore.newState;
5601
+ const storedActiveTabData = getActiveTab(storedState);
5602
+ if (!storedActiveTabData) {
5603
+ return fallbackState;
5604
+ }
5605
+ if (allowMissingReference && referenceTabId === undefined && referenceTabUri === undefined) {
5606
+ return storedState;
5607
+ }
5608
+ if (storedActiveTabData.tab.id === referenceTabId) {
5609
+ return storedState;
5610
+ }
5611
+ if (referenceTabUri && storedActiveTabData.tab.uri === referenceTabUri) {
5612
+ return storedState;
5613
+ }
5614
+ return fallbackState;
5561
5615
  };
5562
-
5563
5616
  const save = async state => {
5564
- const activeTabData = getActiveTab(state);
5617
+ const requestedActiveTabData = getActiveTab(state);
5618
+ const currentState = getLatestStoredState(state.uid, state, requestedActiveTabData?.tab.id, requestedActiveTabData?.tab.uri, !requestedActiveTabData);
5619
+ const activeTabData = getActiveTab(currentState);
5565
5620
  if (!activeTabData) {
5566
- return state;
5621
+ return currentState;
5567
5622
  }
5568
5623
  const {
5569
5624
  tab
5570
5625
  } = activeTabData;
5571
5626
  if (tab.loadingState === 'loading') {
5572
- return state;
5627
+ return currentState;
5573
5628
  }
5574
- await saveEditor(tab.editorUid);
5575
5629
  if (!tab.isDirty) {
5576
- return state;
5630
+ await saveEditor(tab.editorUid);
5631
+ return getLatestStoredState(state.uid, currentState, tab.id, tab.uri);
5577
5632
  }
5578
- const editorState = await getEditorSaveState(tab.editorUid);
5579
- if (editorState.modified) {
5580
- return state;
5633
+ const editorState = await saveEditor(tab.editorUid);
5634
+ const latestState = getLatestStoredState(state.uid, currentState, tab.id, tab.uri);
5635
+ if (editorState?.modified) {
5636
+ return latestState;
5637
+ }
5638
+ if (tab.uri) {
5639
+ await handleModifiedStatusChange$1(tab.uri, false);
5581
5640
  }
5582
- return updateTab(state, tab.id, {
5641
+ const stateAfterModifiedStatusChange = getLatestStoredState(state.uid, latestState, tab.id, tab.uri);
5642
+ return updateTab(stateAfterModifiedStatusChange, tab.id, {
5583
5643
  isDirty: false
5584
5644
  });
5585
5645
  };
@@ -5768,6 +5828,7 @@ const commandMap = {
5768
5828
  'Main.focusNextTab': wrapCommand(focusNextTab),
5769
5829
  'Main.focusPrevious': wrapCommand(focusPreviousTab),
5770
5830
  'Main.focusPreviousTab': wrapCommand(focusPreviousTab),
5831
+ 'Main.handleModifiedStatusChange': wrapCommand(handleModifiedStatusChange),
5771
5832
  'Main.handleTabContextMenu': wrapCommand(handleTabContextMenu),
5772
5833
  'Main.openInput': wrapCommand(openInput),
5773
5834
  'Main.openUri': wrapCommand(openUri),