@lvce-editor/main-area-worker 9.9.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,310 +118,6 @@ 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
- };
147
- };
148
-
149
- const withEmptyGroups = state => {
150
- return withGroupsAndActiveGroup(state, [], undefined);
151
- };
152
-
153
- const withGroups = (state, groups) => {
154
- return {
155
- ...state,
156
- layout: {
157
- ...state.layout,
158
- groups
159
- }
160
- };
161
- };
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;
173
- }
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;
179
- }
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
- };
198
- }
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);
212
- }
213
-
214
- // If no remaining groups, return empty layout
215
- return withEmptyGroups(state);
216
- }
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
- };
229
-
230
- const closeActiveEditor = state => {
231
- const focusedGroup = getFocusedGroup(state);
232
- if (!focusedGroup) {
233
- return state;
234
- }
235
- const {
236
- activeTabId
237
- } = focusedGroup;
238
- if (activeTabId === undefined) {
239
- return state;
240
- }
241
- return closeTab(state, focusedGroup.id, activeTabId);
242
- };
243
-
244
- const closeAll$1 = state => {
245
- return withEmptyGroups(state);
246
- };
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
- }));
255
- };
256
-
257
- const closeEditorGroup$1 = (state, groupId) => {
258
- if (Number.isNaN(groupId)) {
259
- return state;
260
- }
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;
271
- }
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
- };
277
-
278
- const isFocused = group => {
279
- return group.focused;
280
- };
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);
299
- };
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
340
- }
341
- };
342
- };
343
-
344
- const getNextActiveTabId = (tabs, newTabs, activeTabId) => {
345
- if (activeTabId === undefined) {
346
- return undefined;
347
- }
348
- if (newTabs.some(tab => tab.id === activeTabId)) {
349
- return activeTabId;
350
- }
351
- const activeTabIndex = tabs.findIndex(tab => tab.id === activeTabId);
352
- if (activeTabIndex === -1 || newTabs.length === 0) {
353
- return undefined;
354
- }
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;
365
- }
366
- const newActiveTabId = getNextActiveTabId(tabs, newTabs, activeTabId);
367
- return {
368
- ...group,
369
- activeTabId: newActiveTabId,
370
- isEmpty: newTabs.length === 0,
371
- tabs: newTabs
372
- };
373
- };
374
- const closeSaved$1 = state => {
375
- const {
376
- groups
377
- } = state.layout;
378
- const newGroups = groups.map(closeSavedInGroup);
379
- return withGroups(state, newGroups);
380
- };
381
-
382
- const getGroupById = (state, groupId) => {
383
- return state.layout.groups.find(group => group.id === groupId);
384
- };
385
-
386
- const closeTabsRight = (state, groupId) => {
387
- const {
388
- layout
389
- } = state;
390
- const {
391
- groups
392
- } = layout;
393
- const group = getGroupById(state, groupId);
394
- if (!group) {
395
- return state;
396
- }
397
- const {
398
- activeTabId,
399
- tabs
400
- } = group;
401
- if (activeTabId === undefined) {
402
- return state;
403
- }
404
- const activeTabIndex = tabs.findIndex(tab => tab.id === activeTabId);
405
- if (activeTabIndex === -1) {
406
- return state;
407
- }
408
- const newTabs = tabs.slice(0, activeTabIndex + 1);
409
- if (newTabs.length === tabs.length) {
410
- return state;
411
- }
412
- const newGroups = groups.map(g => {
413
- if (g.id === groupId) {
414
- return {
415
- ...g,
416
- isEmpty: newTabs.length === 0,
417
- tabs: newTabs
418
- };
419
- }
420
- return g;
421
- });
422
- return withGroups(state, newGroups);
423
- };
424
-
425
121
  const normalizeLine = line => {
426
122
  if (line.startsWith('Error: ')) {
427
123
  return line.slice('Error: '.length);
@@ -1744,35 +1440,388 @@ const getIcons = async iconRequests => {
1744
1440
  return invoke$1('IconTheme.getIcons', iconRequests);
1745
1441
  };
1746
1442
 
1747
- const {
1748
- invoke,
1749
- invokeAndTransfer,
1750
- set: set$1
1751
- } = create$3(RendererWorker);
1752
- const showContextMenu2 = async (uid, menuId, x, y, args) => {
1753
- number(uid);
1754
- number(menuId);
1755
- number(x);
1756
- number(y);
1757
- await invoke('ContextMenu.show2', uid, menuId, x, y, args);
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);
1450
+ };
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);
1457
+ };
1458
+ const sendMessagePortToClipBoardWorker$1 = async (port, rpcId) => {
1459
+ const command = 'ClipBoard.handleMessagePort';
1460
+ await invokeAndTransfer('SendMessagePortToExtensionHostWorker.sendMessagePortToClipBoardWorker', port, command, rpcId);
1461
+ };
1462
+ const sendMessagePortToIconThemeWorker = async (port, rpcId) => {
1463
+ const command = 'IconTheme.handleMessagePort';
1464
+ await invokeAndTransfer('SendMessagePortToExtensionHostWorker.sendMessagePortToIconThemeWorker', port, command, rpcId);
1465
+ };
1466
+ const readFile = async uri => {
1467
+ return invoke('FileSystem.readFile', uri);
1468
+ };
1469
+ const sendMessagePortToExtensionHostWorker$1 = async (port, rpcId = 0) => {
1470
+ const command = 'HandleMessagePort.handleMessagePort2';
1471
+ await invokeAndTransfer('SendMessagePortToExtensionHostWorker.sendMessagePortToExtensionHostWorker', port, command, rpcId);
1472
+ };
1473
+ const writeClipBoardText = async text => {
1474
+ await invoke('ClipBoard.writeText', /* text */text);
1475
+ };
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;
1758
1738
  };
1759
- const sendMessagePortToClipBoardWorker$1 = async (port, rpcId) => {
1760
- const command = 'ClipBoard.handleMessagePort';
1761
- await invokeAndTransfer('SendMessagePortToExtensionHostWorker.sendMessagePortToClipBoardWorker', port, command, rpcId);
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
+ };
1762
1755
  };
1763
- const sendMessagePortToIconThemeWorker = async (port, rpcId) => {
1764
- const command = 'IconTheme.handleMessagePort';
1765
- await invokeAndTransfer('SendMessagePortToExtensionHostWorker.sendMessagePortToIconThemeWorker', port, command, rpcId);
1756
+ const closeSaved$1 = state => {
1757
+ const {
1758
+ groups
1759
+ } = state.layout;
1760
+ const newGroups = groups.map(closeSavedInGroup);
1761
+ return withGroups(state, newGroups);
1766
1762
  };
1767
- const readFile = async uri => {
1768
- return invoke('FileSystem.readFile', uri);
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;
1769
1782
  };
1770
- const sendMessagePortToExtensionHostWorker$1 = async (port, rpcId = 0) => {
1771
- const command = 'HandleMessagePort.handleMessagePort2';
1772
- await invokeAndTransfer('SendMessagePortToExtensionHostWorker.sendMessagePortToExtensionHostWorker', port, command, rpcId);
1783
+
1784
+ const getGroupById = (state, groupId) => {
1785
+ return state.layout.groups.find(group => group.id === groupId);
1773
1786
  };
1774
- const writeClipBoardText = async text => {
1775
- await invoke('ClipBoard.writeText', /* text */text);
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);
1776
1825
  };
1777
1826
 
1778
1827
  const copyPath$1 = async (state, path) => {
@@ -1947,6 +1996,15 @@ const loadFileContent = async path => {
1947
1996
  const content = await readFile(path);
1948
1997
  return content;
1949
1998
  };
1999
+ const getLoadFileErrorMessage = error => {
2000
+ if (!(error instanceof Error)) {
2001
+ return 'Failed to load file content';
2002
+ }
2003
+ if (error.message.includes('EISDIR') || error.message.includes('illegal operation on a directory') || error.message.includes('is a directory')) {
2004
+ return 'Expected a file but received a folder';
2005
+ }
2006
+ return error.message;
2007
+ };
1950
2008
  const loadTabContentAsync = async (tabId, path, requestId, getLatestState) => {
1951
2009
  try {
1952
2010
  await loadFileContent(path);
@@ -1984,7 +2042,7 @@ const loadTabContentAsync = async (tabId, path, requestId, getLatestState) => {
1984
2042
  if (latestTab.loadingState !== 'loading') {
1985
2043
  return latestState;
1986
2044
  }
1987
- const errorMessage = error instanceof Error ? error.message : 'Failed to load file content';
2045
+ const errorMessage = getLoadFileErrorMessage(error);
1988
2046
  return updateTab(latestState, tabId, {
1989
2047
  errorMessage,
1990
2048
  loadingState: 'error'
@@ -2167,6 +2225,7 @@ const getViewletModuleId$1 = async uri => {
2167
2225
  };
2168
2226
 
2169
2227
  const DiffEditor = 'DiffEditor';
2228
+ const EditorText = 'Editor';
2170
2229
  const ExtensionDetail = 'ExtensionDetail';
2171
2230
  const QuickPick = 'QuickPick';
2172
2231
 
@@ -2487,6 +2546,89 @@ const parseRawGroupId = rawGroupId => {
2487
2546
  return Number.isNaN(groupId) ? undefined : groupId;
2488
2547
  };
2489
2548
 
2549
+ const findTabByUri = (state, uri) => {
2550
+ const {
2551
+ layout
2552
+ } = state;
2553
+ const {
2554
+ groups
2555
+ } = layout;
2556
+ for (const group of groups) {
2557
+ const tab = group.tabs.find(t => t.uri === uri);
2558
+ if (tab) {
2559
+ return {
2560
+ groupId: group.id,
2561
+ tab
2562
+ };
2563
+ }
2564
+ }
2565
+ return undefined;
2566
+ };
2567
+
2568
+ const focusEditorGroup = (state, groupId) => {
2569
+ const {
2570
+ layout
2571
+ } = state;
2572
+ const {
2573
+ groups
2574
+ } = layout;
2575
+ const updatedGroups = groups.map(group => ({
2576
+ ...group,
2577
+ focused: group.id === groupId
2578
+ }));
2579
+ return {
2580
+ ...state,
2581
+ layout: {
2582
+ ...layout,
2583
+ activeGroupId: groupId,
2584
+ groups: updatedGroups
2585
+ }
2586
+ };
2587
+ };
2588
+
2589
+ const getActiveTabId = state => {
2590
+ const {
2591
+ layout
2592
+ } = state;
2593
+ const {
2594
+ activeGroupId,
2595
+ groups
2596
+ } = layout;
2597
+ const activeGroup = groups.find(g => g.id === activeGroupId);
2598
+ return activeGroup?.activeTabId;
2599
+ };
2600
+
2601
+ const getTabCount = state => {
2602
+ return state.layout.groups.reduce((sum, group) => sum + group.tabs.length, 0);
2603
+ };
2604
+
2605
+ const getCurrentState = state => {
2606
+ const {
2607
+ uid
2608
+ } = state;
2609
+ const stateFromStore = get(uid);
2610
+ if (!stateFromStore) {
2611
+ set(uid, state, state);
2612
+ return state;
2613
+ }
2614
+ const storedState = stateFromStore.newState;
2615
+ if (getTabCount(storedState) > getTabCount(state)) {
2616
+ return storedState;
2617
+ }
2618
+ set(uid, state, state);
2619
+ return state;
2620
+ };
2621
+
2622
+ const getEditorInputEditorType = editorInput => {
2623
+ switch (editorInput.type) {
2624
+ case 'diff-editor':
2625
+ case 'extension-detail-view':
2626
+ return 'custom';
2627
+ case 'editor':
2628
+ return 'text';
2629
+ }
2630
+ };
2631
+
2490
2632
  const getBasename$1 = uri => {
2491
2633
  const lastSlashIndex = uri.lastIndexOf('/');
2492
2634
  if (lastSlashIndex === -1) {
@@ -2521,6 +2663,32 @@ const getLabel = uri => {
2521
2663
  return getBasename$1(uri);
2522
2664
  };
2523
2665
 
2666
+ const getEditorInputTitle = editorInput => {
2667
+ switch (editorInput.type) {
2668
+ case 'diff-editor':
2669
+ {
2670
+ const leftTitle = getLabel(editorInput.uriLeft);
2671
+ const rightTitle = getLabel(editorInput.uriRight);
2672
+ return `${leftTitle} - ${rightTitle}`;
2673
+ }
2674
+ case 'editor':
2675
+ return getLabel(editorInput.uri);
2676
+ case 'extension-detail-view':
2677
+ return editorInput.extensionId;
2678
+ }
2679
+ };
2680
+
2681
+ const getEditorInputUri = editorInput => {
2682
+ switch (editorInput.type) {
2683
+ case 'diff-editor':
2684
+ return `diff://?left=${encodeURIComponent(editorInput.uriLeft)}&right=${encodeURIComponent(editorInput.uriRight)}`;
2685
+ case 'editor':
2686
+ return editorInput.uri;
2687
+ case 'extension-detail-view':
2688
+ return `extension-detail://${editorInput.extensionId}`;
2689
+ }
2690
+ };
2691
+
2524
2692
  const createEmptyGroup = (state, uri, requestId, preview = false, title = getLabel(uri), editorType = 'text', editorInput) => {
2525
2693
  const {
2526
2694
  layout
@@ -2679,94 +2847,85 @@ const ensureActiveGroup = (state, uri, preview = false, title = getLabel(uri), e
2679
2847
  return newState;
2680
2848
  };
2681
2849
 
2682
- const findTabByUri = (state, uri) => {
2683
- const {
2684
- layout
2685
- } = state;
2686
- const {
2687
- groups
2688
- } = layout;
2689
- for (const group of groups) {
2690
- const tab = group.tabs.find(t => t.uri === uri);
2691
- if (tab) {
2692
- return {
2693
- groupId: group.id,
2694
- tab
2695
- };
2696
- }
2850
+ const getStateWithTab = (currentState, editorInput, existingTab, shouldRetryExistingTab, uri, preview, title, editorType) => {
2851
+ if (shouldRetryExistingTab && existingTab) {
2852
+ const focusedState = focusEditorGroup(currentState, existingTab.groupId);
2853
+ return {
2854
+ stateWithTab: updateTab(focusedState, existingTab.tab.id, {
2855
+ editorInput,
2856
+ errorMessage: '',
2857
+ loadingState: 'loading',
2858
+ title,
2859
+ uri
2860
+ }),
2861
+ tabId: existingTab.tab.id
2862
+ };
2697
2863
  }
2698
- return undefined;
2864
+ const stateWithTab = ensureActiveGroup(currentState, uri, preview, title, editorType, editorInput);
2865
+ return {
2866
+ stateWithTab,
2867
+ tabId: getActiveTabId(stateWithTab)
2868
+ };
2699
2869
  };
2700
2870
 
2701
- const focusEditorGroup = (state, groupId) => {
2871
+ const Directory = 3;
2872
+ const DirectoryExpanded = 4;
2873
+
2874
+ const isLocalEditorInput = editorInput => {
2875
+ if (editorInput.type !== 'editor') {
2876
+ return false;
2877
+ }
2878
+ return editorInput.uri.startsWith('file://') || !editorInput.uri.includes('://');
2879
+ };
2880
+
2881
+ const shouldCheckDirectoryEditorInput = editorInput => {
2882
+ if (!isLocalEditorInput(editorInput)) {
2883
+ return false;
2884
+ }
2885
+ const baseName = editorInput.uri.slice(editorInput.uri.lastIndexOf('/') + 1);
2886
+ return baseName.endsWith('/') || baseName !== '' && !baseName.includes('.');
2887
+ };
2888
+
2889
+ const isDirectoryEditorInput = async editorInput => {
2890
+ if (!shouldCheckDirectoryEditorInput(editorInput)) {
2891
+ return false;
2892
+ }
2893
+ try {
2894
+ const type = await invoke('FileSystem.stat', editorInput.uri);
2895
+ return type === Directory;
2896
+ } catch {
2897
+ return false;
2898
+ }
2899
+ };
2900
+
2901
+ const switchTab = (state, groupId, tabId) => {
2702
2902
  const {
2703
2903
  layout
2704
2904
  } = state;
2705
2905
  const {
2706
2906
  groups
2707
2907
  } = layout;
2708
- const updatedGroups = groups.map(group => ({
2709
- ...group,
2710
- focused: group.id === groupId
2711
- }));
2908
+ const updatedGroups = groups.map(group => {
2909
+ if (group.id === groupId) {
2910
+ const tabExists = group.tabs.some(tab => tab.id === tabId);
2911
+ if (tabExists) {
2912
+ return {
2913
+ ...group,
2914
+ activeTabId: tabId
2915
+ };
2916
+ }
2917
+ }
2918
+ return group;
2919
+ });
2712
2920
  return {
2713
2921
  ...state,
2714
2922
  layout: {
2715
2923
  ...layout,
2716
- activeGroupId: groupId,
2717
2924
  groups: updatedGroups
2718
2925
  }
2719
2926
  };
2720
2927
  };
2721
2928
 
2722
- const getActiveTabId = state => {
2723
- const {
2724
- layout
2725
- } = state;
2726
- const {
2727
- activeGroupId,
2728
- groups
2729
- } = layout;
2730
- const activeGroup = groups.find(g => g.id === activeGroupId);
2731
- return activeGroup?.activeTabId;
2732
- };
2733
-
2734
- const getEditorInputEditorType = editorInput => {
2735
- switch (editorInput.type) {
2736
- case 'diff-editor':
2737
- case 'extension-detail-view':
2738
- return 'custom';
2739
- case 'editor':
2740
- return 'text';
2741
- }
2742
- };
2743
-
2744
- const getEditorInputTitle = editorInput => {
2745
- switch (editorInput.type) {
2746
- case 'diff-editor':
2747
- {
2748
- const leftTitle = getLabel(editorInput.uriLeft);
2749
- const rightTitle = getLabel(editorInput.uriRight);
2750
- return `${leftTitle} - ${rightTitle}`;
2751
- }
2752
- case 'editor':
2753
- return getLabel(editorInput.uri);
2754
- case 'extension-detail-view':
2755
- return editorInput.extensionId;
2756
- }
2757
- };
2758
-
2759
- const getEditorInputUri = editorInput => {
2760
- switch (editorInput.type) {
2761
- case 'diff-editor':
2762
- return `diff://?left=${encodeURIComponent(editorInput.uriLeft)}&right=${encodeURIComponent(editorInput.uriRight)}`;
2763
- case 'editor':
2764
- return editorInput.uri;
2765
- case 'extension-detail-view':
2766
- return `extension-detail://${editorInput.extensionId}`;
2767
- }
2768
- };
2769
-
2770
2929
  const getIconsCached = (dirents, fileIconCache) => {
2771
2930
  return dirents.map(dirent => fileIconCache[dirent]);
2772
2931
  };
@@ -2801,9 +2960,6 @@ const getMissingIconRequestsForTabs = (tabs, fileIconCache) => {
2801
2960
  return iconRequests;
2802
2961
  };
2803
2962
 
2804
- const Directory = 3;
2805
- const DirectoryExpanded = 4;
2806
-
2807
2963
  const getSimpleIconRequestType = direntType => {
2808
2964
  if (direntType === Directory || direntType === DirectoryExpanded) {
2809
2965
  return 2;
@@ -2854,73 +3010,6 @@ const getFileIconsForTabs = async (tabs, fileIconCache) => {
2854
3010
  };
2855
3011
  };
2856
3012
 
2857
- const switchTab = (state, groupId, tabId) => {
2858
- const {
2859
- layout
2860
- } = state;
2861
- const {
2862
- groups
2863
- } = layout;
2864
- const updatedGroups = groups.map(group => {
2865
- if (group.id === groupId) {
2866
- const tabExists = group.tabs.some(tab => tab.id === tabId);
2867
- if (tabExists) {
2868
- return {
2869
- ...group,
2870
- activeTabId: tabId
2871
- };
2872
- }
2873
- }
2874
- return group;
2875
- });
2876
- return {
2877
- ...state,
2878
- layout: {
2879
- ...layout,
2880
- groups: updatedGroups
2881
- }
2882
- };
2883
- };
2884
-
2885
- const getTabCount = state => {
2886
- return state.layout.groups.reduce((sum, group) => sum + group.tabs.length, 0);
2887
- };
2888
- const getCurrentState = state => {
2889
- const {
2890
- uid
2891
- } = state;
2892
- const stateFromStore = get(uid);
2893
- if (!stateFromStore) {
2894
- set(uid, state, state);
2895
- return state;
2896
- }
2897
- const storedState = stateFromStore.newState;
2898
- if (getTabCount(storedState) > getTabCount(state)) {
2899
- return storedState;
2900
- }
2901
- set(uid, state, state);
2902
- return state;
2903
- };
2904
- const getStateWithTab = (currentState, editorInput, existingTab, shouldRetryExistingTab, uri, preview, title, editorType) => {
2905
- if (shouldRetryExistingTab && existingTab) {
2906
- const focusedState = focusEditorGroup(currentState, existingTab.groupId);
2907
- return {
2908
- stateWithTab: updateTab(focusedState, existingTab.tab.id, {
2909
- editorInput,
2910
- errorMessage: '',
2911
- loadingState: 'loading',
2912
- title,
2913
- uri
2914
- }),
2915
- tabId: existingTab.tab.id
2916
- };
2917
- }
2918
- const stateWithTab = ensureActiveGroup(currentState, uri, preview, title, editorType, editorInput);
2919
- return {
2920
- stateWithTab,
2921
- tabId: getActiveTabId(stateWithTab)
2922
- };
2923
- };
2924
3013
  const updateTabIcon = async (uid, state, readyState, tabId) => {
2925
3014
  const newTab = findTabById(readyState, tabId);
2926
3015
  if (!newTab || !newTab.tab.uri) {
@@ -2954,6 +3043,7 @@ const updateTabIcon = async (uid, state, readyState, tabId) => {
2954
3043
  return undefined;
2955
3044
  }
2956
3045
  };
3046
+
2957
3047
  const openInput = async (state, options) => {
2958
3048
  object(state);
2959
3049
  object(options);
@@ -2967,19 +3057,30 @@ const openInput = async (state, options) => {
2967
3057
  const uri = getEditorInputUri(editorInput);
2968
3058
  const title = getEditorInputTitle(editorInput);
2969
3059
  const editorType = getEditorInputEditorType(editorInput);
2970
- const existingTab = findTabByUri(state, uri);
3060
+ const currentState = getCurrentState(state);
3061
+ const existingTab = findTabByUri(currentState, uri);
2971
3062
  const shouldRetryExistingTab = !!existingTab && existingTab.tab.loadingState === 'error';
2972
3063
  if (existingTab && !shouldRetryExistingTab) {
2973
- const focusedState = focusEditorGroup(state, existingTab.groupId);
3064
+ const focusedState = focusEditorGroup(currentState, existingTab.groupId);
2974
3065
  return switchTab(focusedState, existingTab.groupId, existingTab.tab.id);
2975
3066
  }
2976
- const previousTabId = getActiveTabId(state);
2977
- const currentState = getCurrentState(state);
3067
+ const previousTabId = getActiveTabId(currentState);
2978
3068
  const {
2979
3069
  stateWithTab,
2980
3070
  tabId
2981
3071
  } = getStateWithTab(currentState, editorInput, existingTab, shouldRetryExistingTab, uri, preview, title, editorType);
2982
3072
  set(uid, state, stateWithTab);
3073
+ if (await isDirectoryEditorInput(editorInput)) {
3074
+ const {
3075
+ newState: latestState
3076
+ } = get(uid);
3077
+ const errorState = updateTab(latestState, tabId, {
3078
+ errorMessage: 'Expected a file but received a folder',
3079
+ loadingState: 'error'
3080
+ });
3081
+ set(uid, state, errorState);
3082
+ return errorState;
3083
+ }
2983
3084
  try {
2984
3085
  const viewletModuleId = await getViewletModuleIdForEditorInput(editorInput);
2985
3086
  const {
@@ -3363,7 +3464,7 @@ const handleClickAction = async (state, action, rawGroupId) => {
3363
3464
  }
3364
3465
  };
3365
3466
 
3366
- const handleClickCloseTab = (state, rawGroupIndex, rawIndex) => {
3467
+ const handleClickCloseTab = async (state, rawGroupIndex, rawIndex) => {
3367
3468
  if (!rawGroupIndex || !rawIndex) {
3368
3469
  return state;
3369
3470
  }
@@ -3387,7 +3488,7 @@ const handleClickCloseTab = (state, rawGroupIndex, rawIndex) => {
3387
3488
  const tab = group.tabs[index];
3388
3489
  const groupId = group.id;
3389
3490
  const tabId = tab.id;
3390
- return closeTab(state, groupId, tabId);
3491
+ return closeTabAndSave(state, groupId, tabId);
3391
3492
  };
3392
3493
 
3393
3494
  const handleClickTab = async (state, groupIndexRaw, indexRaw) => {
@@ -3534,6 +3635,7 @@ const newFile = async state => {
3534
3635
  x: stateWithNewTab.x,
3535
3636
  y: stateWithNewTab.y + stateWithNewTab.tabHeight
3536
3637
  };
3638
+ const viewletModuleId = EditorText;
3537
3639
  const stateWithViewlet = createViewletForTab(stateWithNewTab, tabId);
3538
3640
  let intermediateState = stateWithViewlet;
3539
3641
 
@@ -3555,7 +3657,7 @@ const newFile = async state => {
3555
3657
  if (actualEditorUid === -1) {
3556
3658
  throw new Error(`invalid editorUid`);
3557
3659
  }
3558
- await createViewlet('Editor', actualEditorUid, tabId, bounds, newTab.uri || '');
3660
+ await createViewlet(viewletModuleId, actualEditorUid, tabId, bounds, newTab.uri || '');
3559
3661
 
3560
3662
  // After viewlet is created, get the latest state and mark it as ready
3561
3663
  const {
@@ -4183,6 +4285,7 @@ const Pin = 'Pin';
4183
4285
  const SplitAndMove = 'Split & Move';
4184
4286
  const MoveIntoNewWindow = 'Move into New Window';
4185
4287
  const CopyIntoNewWindow = 'Copy into New Window';
4288
+ const NewTextFile = 'New Text File';
4186
4289
  const NewWindow = 'New Window';
4187
4290
  const OpenFile = 'Open File';
4188
4291
  const SplitDown = 'Split Down';
@@ -4214,6 +4317,9 @@ const splitEditorGroup = () => {
4214
4317
  const newWindow$1 = () => {
4215
4318
  return i18nString(NewWindow);
4216
4319
  };
4320
+ const newTextFile = () => {
4321
+ return i18nString(NewTextFile);
4322
+ };
4217
4323
  const close = () => {
4218
4324
  return i18nString(Close);
4219
4325
  };
@@ -4300,6 +4406,11 @@ const getNewWindowMenuEntries = state => {
4300
4406
  const getMenuEntries$2 = (state, groupId) => {
4301
4407
  const groupArgs = getMenuEntryArgs(groupId);
4302
4408
  const entries = [{
4409
+ command: 'MainArea.newFile',
4410
+ flags: None,
4411
+ id: 'newTextFile',
4412
+ label: newTextFile()
4413
+ }, {
4303
4414
  args: [QuickPick, 'file'],
4304
4415
  command: 'Viewlet.openWidget',
4305
4416
  flags: None,
@@ -4552,30 +4663,40 @@ const getSashOffset = (layout, groupIndex, width) => {
4552
4663
  const escapeCssAttributeValue = value => {
4553
4664
  return value.replaceAll('\\', '\\\\').replaceAll('"', '\\"');
4554
4665
  };
4555
- const getSashCss = (layout, width = 0) => {
4556
- if (layout.groups.length <= 1) {
4557
- return [];
4558
- }
4559
- const rules = [];
4666
+ const toSashProperty = direction => {
4667
+ return direction === Horizontal ? 'left' : 'top';
4668
+ };
4669
+ const renderSashCss = ({
4670
+ property,
4671
+ sashId,
4672
+ value
4673
+ }) => {
4674
+ const escapedSashId = escapeCssAttributeValue(sashId);
4675
+ return `[data-sash-id="${escapedSashId}"] {
4676
+ ${property}: ${value};
4677
+ }`;
4678
+ };
4679
+ const getProtoSashCss = (layout, width) => {
4560
4680
  const segments = getGroupSegments(layout.groups, layout.direction);
4561
- const sashPositionProperty = layout.direction === Horizontal ? 'left' : 'top';
4681
+ const hasNestedSegments = segments.some(segment => segment.direction !== undefined);
4682
+ const rules = [];
4562
4683
  let segmentOffset = 0;
4563
4684
  for (let i = 1; i < segments.length; i++) {
4564
4685
  segmentOffset += getSegmentSize(segments[i - 1]);
4565
4686
  const beforeGroupId = segments[i - 1].groups.at(-1)?.id || 0;
4566
4687
  const afterGroupId = segments[i].groups[0].id;
4567
4688
  const sashId = create(beforeGroupId, afterGroupId);
4568
- const escapedSashId = escapeCssAttributeValue(sashId);
4569
- const sashOffset = segments.some(segment => segment.direction !== undefined) || layout.direction !== Horizontal || !width ? `${segmentOffset}%` : getSashOffset(layout, i, width);
4570
- rules.push(`[data-sashId="${escapedSashId}"] {
4571
- ${sashPositionProperty}: ${sashOffset};
4572
- }`);
4689
+ const value = hasNestedSegments || layout.direction !== Horizontal || !width ? `${segmentOffset}%` : getSashOffset(layout, i, width);
4690
+ rules.push({
4691
+ property: toSashProperty(layout.direction),
4692
+ sashId,
4693
+ value
4694
+ });
4573
4695
  }
4574
4696
  for (const segment of segments) {
4575
4697
  if (segment.direction === undefined || segment.groups.length <= 1) {
4576
4698
  continue;
4577
4699
  }
4578
- const nestedProperty = segment.direction === Horizontal ? 'left' : 'top';
4579
4700
  const segmentSize = getSegmentSize(segment);
4580
4701
  let nestedOffset = 0;
4581
4702
  for (let i = 1; i < segment.groups.length; i++) {
@@ -4583,20 +4704,35 @@ const getSashCss = (layout, width = 0) => {
4583
4704
  const beforeGroupId = segment.groups[i - 1].id;
4584
4705
  const afterGroupId = segment.groups[i].id;
4585
4706
  const sashId = create(beforeGroupId, afterGroupId);
4586
- const escapedSashId = escapeCssAttributeValue(sashId);
4587
- const relativeOffset = Number((nestedOffset / segmentSize * 100).toFixed(6));
4588
- rules.push(`[data-sashId="${escapedSashId}"] {
4589
- ${nestedProperty}: ${relativeOffset}%;
4590
- }`);
4707
+ const value = `${Number((nestedOffset / segmentSize * 100).toFixed(6))}%`;
4708
+ rules.push({
4709
+ property: toSashProperty(segment.direction),
4710
+ sashId,
4711
+ value
4712
+ });
4591
4713
  }
4592
4714
  }
4593
4715
  return rules;
4594
4716
  };
4717
+ const getSashCss = (layout, width = 0) => {
4718
+ if (layout.groups.length <= 1) {
4719
+ return [];
4720
+ }
4721
+ return getProtoSashCss(layout, width).map(renderSashCss);
4722
+ };
4595
4723
 
4596
4724
  const getCss = (layout, width = 0) => {
4597
4725
  const rules = [`.MainArea {
4598
4726
  }`, `.editor-groups-container {
4599
4727
  overflow: auto;
4728
+ }`, `.SashBorder {
4729
+ background: var(--SashBorder, gray);
4730
+ }`, `.SashBorderHorizontal {
4731
+ width: 100%;
4732
+ height: 1px;
4733
+ }`, `.SashBorderVertical {
4734
+ width: 1px;
4735
+ height: 100%;
4600
4736
  }`, `.EditorGroup {
4601
4737
  min-width: 250px;
4602
4738
  width: var(--EditorGroupWidth, auto);
@@ -5217,6 +5353,9 @@ const getSashClassName = direction => {
5217
5353
  return direction === Horizontal ? 'Sash SashVertical' : 'Sash SashHorizontal';
5218
5354
  };
5219
5355
 
5356
+ const getSashBorderClassName = direction => {
5357
+ return direction === 1 ? 'SashBorder SashBorderVertical' : 'SashBorder SashBorderHorizontal';
5358
+ };
5220
5359
  const renderSash = (direction, sashId) => {
5221
5360
  return [{
5222
5361
  childCount: 1,
@@ -5227,7 +5366,7 @@ const renderSash = (direction, sashId) => {
5227
5366
  type: Button$2
5228
5367
  }, {
5229
5368
  childCount: 0,
5230
- className: 'SashBorder',
5369
+ className: getSashBorderClassName(direction),
5231
5370
  type: Div
5232
5371
  }];
5233
5372
  };
@@ -5445,42 +5584,69 @@ const renderEventListeners = () => {
5445
5584
  }];
5446
5585
  };
5447
5586
 
5448
- const saveEditor = async editorUid => {
5449
- await invoke('Editor.save', editorUid);
5450
- };
5451
- const getEditorSaveState = async editorUid => {
5452
- 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;
5453
5607
  };
5454
-
5455
5608
  const save = async state => {
5456
- 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);
5457
5612
  if (!activeTabData) {
5458
- return state;
5613
+ return currentState;
5459
5614
  }
5460
5615
  const {
5461
5616
  tab
5462
5617
  } = activeTabData;
5463
5618
  if (tab.loadingState === 'loading') {
5464
- return state;
5619
+ return currentState;
5465
5620
  }
5466
- await saveEditor(tab.editorUid);
5467
5621
  if (!tab.isDirty) {
5468
- return state;
5622
+ await saveEditor(tab.editorUid);
5623
+ return getLatestStoredState(state.uid, currentState, tab.id, tab.uri);
5469
5624
  }
5470
- const editorState = await getEditorSaveState(tab.editorUid);
5471
- if (editorState.modified) {
5472
- 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;
5473
5629
  }
5474
- return updateTab(state, tab.id, {
5630
+ if (tab.uri) {
5631
+ await handleModifiedStatusChange$1(tab.uri, false);
5632
+ }
5633
+ const stateAfterModifiedStatusChange = getLatestStoredState(state.uid, latestState, tab.id, tab.uri);
5634
+ return updateTab(stateAfterModifiedStatusChange, tab.id, {
5475
5635
  isDirty: false
5476
5636
  });
5477
5637
  };
5478
5638
 
5479
5639
  const getFilteredGroups = groups => {
5480
- return groups.map(group => ({
5481
- ...group,
5482
- tabs: group.tabs.filter(tab => !tab.uri?.startsWith('untitled://')).map(normalizeTabEditorInput)
5483
- })).filter(group => group.tabs.length > 0);
5640
+ return groups.map(group => {
5641
+ const tabs = group.tabs.filter(tab => !tab.uri?.startsWith('untitled://')).map(normalizeTabEditorInput);
5642
+ const activeTabId = tabs.some(tab => tab.id === group.activeTabId) ? group.activeTabId : tabs[0]?.id;
5643
+ return {
5644
+ ...group,
5645
+ activeTabId,
5646
+ isEmpty: tabs.length === 0,
5647
+ tabs
5648
+ };
5649
+ });
5484
5650
  };
5485
5651
 
5486
5652
  const saveState = state => {
@@ -5640,6 +5806,27 @@ const splitUp = (state, groupId) => {
5640
5806
  };
5641
5807
 
5642
5808
  const commandMap = {
5809
+ 'Main.closeActiveEditor': wrapCommand(closeActiveEditor),
5810
+ 'Main.closeAll': wrapCommand(closeAll$1),
5811
+ 'Main.closeAllEditors': wrapCommand(closeAll$1),
5812
+ 'Main.closeFocusedTab': wrapCommand(closeFocusedTab),
5813
+ 'Main.closeOthers': wrapCommand(closeOtherTabs),
5814
+ 'Main.closeSaved': wrapCommand(closeSaved$1),
5815
+ 'Main.closeTabsByUris': wrapCommand(closeTabsByUris),
5816
+ 'Main.closeTabsRight': wrapCommand(closeTabsRight),
5817
+ 'Main.copyPath': wrapCommand(copyPath$1),
5818
+ 'Main.copyRelativePath': wrapCommand(copyRelativePath$1),
5819
+ 'Main.focusNext': wrapCommand(focusNextTab),
5820
+ 'Main.focusNextTab': wrapCommand(focusNextTab),
5821
+ 'Main.focusPrevious': wrapCommand(focusPreviousTab),
5822
+ 'Main.focusPreviousTab': wrapCommand(focusPreviousTab),
5823
+ 'Main.handleModifiedStatusChange': wrapCommand(handleModifiedStatusChange),
5824
+ 'Main.handleTabContextMenu': wrapCommand(handleTabContextMenu),
5825
+ 'Main.openInput': wrapCommand(openInput),
5826
+ 'Main.openUri': wrapCommand(openUri),
5827
+ 'Main.openUris': wrapCommand(openUris),
5828
+ 'Main.save': wrapCommand(save),
5829
+ 'Main.splitRight': wrapCommand(splitRight),
5643
5830
  'MainArea.closeActiveEditor': wrapCommand(closeActiveEditor),
5644
5831
  'MainArea.closeAll': wrapCommand(closeAll$1),
5645
5832
  'MainArea.closeAllEditors': wrapCommand(closeAll$1),
@@ -5647,6 +5834,7 @@ const commandMap = {
5647
5834
  'MainArea.closeFocusedTab': wrapCommand(closeFocusedTab),
5648
5835
  'MainArea.closeOthers': wrapCommand(closeOtherTabs),
5649
5836
  'MainArea.closeSaved': wrapCommand(closeSaved$1),
5837
+ 'MainArea.closeTabsByUris': wrapCommand(closeTabsByUris),
5650
5838
  'MainArea.closeTabsRight': wrapCommand(closeTabsRight),
5651
5839
  'MainArea.copyPath': wrapCommand(copyPath$1),
5652
5840
  'MainArea.copyRelativePath': wrapCommand(copyRelativePath$1),