@lvce-editor/main-area-worker 9.24.0 → 9.28.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.
@@ -3,10 +3,67 @@ const toCommandId = key => {
3
3
  return key.slice(dotIndex + 1);
4
4
  };
5
5
  const create$f = () => {
6
+ const commandQueues = new Map();
7
+ const generations = Object.create(null);
6
8
  const states = Object.create(null);
7
9
  const commandMapRef = {};
10
+ const getGeneration = uid => generations[uid] || 0;
11
+ const isCurrentGeneration = (uid, generation) => {
12
+ return states[uid] !== undefined && getGeneration(uid) === generation;
13
+ };
14
+ const updateState = (uid, generation, fallbackState, updater) => {
15
+ if (!isCurrentGeneration(uid, generation)) {
16
+ return Promise.resolve(fallbackState);
17
+ }
18
+ const current = states[uid];
19
+ const updatedState = updater(current.newState);
20
+ if (updatedState !== current.newState) {
21
+ states[uid] = {
22
+ newState: updatedState,
23
+ oldState: current.oldState,
24
+ scheduledState: updatedState
25
+ };
26
+ }
27
+ return Promise.resolve(updatedState);
28
+ };
29
+ const createAsyncCommandContext = (uid, generation) => {
30
+ let latestState = states[uid].newState;
31
+ return {
32
+ getState: () => {
33
+ if (isCurrentGeneration(uid, generation)) {
34
+ latestState = states[uid].newState;
35
+ }
36
+ return latestState;
37
+ },
38
+ updateState: async updater => {
39
+ latestState = await updateState(uid, generation, latestState, updater);
40
+ return latestState;
41
+ }
42
+ };
43
+ };
44
+ const enqueueCommand = async (uid, command) => {
45
+ const previous = commandQueues.get(uid) || Promise.resolve();
46
+ const run = async () => {
47
+ try {
48
+ await previous;
49
+ } catch {
50
+ // The previous caller receives its error; later commands must still run.
51
+ }
52
+ await command();
53
+ };
54
+ const current = run();
55
+ commandQueues.set(uid, current);
56
+ try {
57
+ await current;
58
+ } finally {
59
+ if (commandQueues.get(uid) === current) {
60
+ commandQueues.delete(uid);
61
+ }
62
+ }
63
+ };
8
64
  return {
9
65
  clear() {
66
+ commandQueues.clear();
10
67
  for (const key of Object.keys(states)) {
11
68
  delete states[key];
12
69
  }
@@ -26,6 +83,7 @@ const create$f = () => {
26
83
  return diffResult;
27
84
  },
28
85
  dispose(uid) {
86
+ commandQueues.delete(uid);
29
87
  delete states[uid];
30
88
  },
31
89
  get(uid) {
@@ -43,14 +101,27 @@ const create$f = () => {
43
101
  Object.assign(commandMapRef, commandMap);
44
102
  },
45
103
  set(uid, oldState, newState, scheduledState) {
104
+ const current = states[uid];
105
+ if (!current || oldState === newState && newState !== current.newState) {
106
+ generations[uid] = getGeneration(uid) + 1;
107
+ }
46
108
  states[uid] = {
47
109
  newState,
48
110
  oldState,
49
111
  scheduledState: scheduledState ?? newState
50
112
  };
51
113
  },
114
+ wrapAsyncCommand(fn) {
115
+ const wrapped = async (uid, ...args) => {
116
+ const generation = getGeneration(uid);
117
+ const context = createAsyncCommandContext(uid, generation);
118
+ await fn(context, ...args);
119
+ };
120
+ return wrapped;
121
+ },
52
122
  wrapCommand(fn) {
53
123
  const wrapped = async (uid, ...args) => {
124
+ const generation = getGeneration(uid);
54
125
  const {
55
126
  newState,
56
127
  oldState
@@ -59,6 +130,9 @@ const create$f = () => {
59
130
  if (oldState === newerState || newState === newerState) {
60
131
  return;
61
132
  }
133
+ if (!isCurrentGeneration(uid, generation)) {
134
+ return;
135
+ }
62
136
  const latestOld = states[uid];
63
137
  const latestNew = {
64
138
  ...latestOld.newState,
@@ -83,6 +157,7 @@ const create$f = () => {
83
157
  },
84
158
  wrapLoadContent(fn) {
85
159
  const wrapped = async (uid, ...args) => {
160
+ const generation = getGeneration(uid);
86
161
  const {
87
162
  newState,
88
163
  oldState
@@ -97,6 +172,11 @@ const create$f = () => {
97
172
  error
98
173
  };
99
174
  }
175
+ if (!isCurrentGeneration(uid, generation)) {
176
+ return {
177
+ error
178
+ };
179
+ }
100
180
  const latestOld = states[uid];
101
181
  const latestNew = {
102
182
  ...latestOld.newState,
@@ -112,6 +192,51 @@ const create$f = () => {
112
192
  };
113
193
  };
114
194
  return wrapped;
195
+ },
196
+ wrapSerialAsyncCommand(fn) {
197
+ const wrapped = async (uid, ...args) => {
198
+ await enqueueCommand(uid, async () => {
199
+ if (!states[uid]) {
200
+ return;
201
+ }
202
+ const generation = getGeneration(uid);
203
+ const context = createAsyncCommandContext(uid, generation);
204
+ await fn(context, ...args);
205
+ });
206
+ };
207
+ return wrapped;
208
+ },
209
+ wrapSerialCommand(fn) {
210
+ const wrapped = async (uid, ...args) => {
211
+ await enqueueCommand(uid, async () => {
212
+ if (!states[uid]) {
213
+ return;
214
+ }
215
+ const generation = getGeneration(uid);
216
+ const {
217
+ newState,
218
+ oldState
219
+ } = states[uid];
220
+ const newerState = await fn(newState, ...args);
221
+ if (oldState === newerState || newState === newerState) {
222
+ return;
223
+ }
224
+ if (!isCurrentGeneration(uid, generation)) {
225
+ return;
226
+ }
227
+ const latestOld = states[uid];
228
+ const latestNew = {
229
+ ...latestOld.newState,
230
+ ...newerState
231
+ };
232
+ states[uid] = {
233
+ newState: latestNew,
234
+ oldState: latestOld.oldState,
235
+ scheduledState: latestNew
236
+ };
237
+ });
238
+ };
239
+ return wrapped;
115
240
  }
116
241
  };
117
242
  };
@@ -474,7 +599,14 @@ class IpcError extends VError {
474
599
  const cause = new Error(message);
475
600
  // @ts-ignore
476
601
  cause.code = code;
477
- cause.stack = stack;
602
+ if (stack) {
603
+ Object.defineProperty(cause, 'stack', {
604
+ configurable: true,
605
+ enumerable: false,
606
+ value: stack,
607
+ writable: true
608
+ });
609
+ }
478
610
  super(cause, betterMessage);
479
611
  } else {
480
612
  super(betterMessage);
@@ -1773,123 +1905,463 @@ const closeTab = (state, groupId, tabId) => {
1773
1905
  return withGroups(stateWithClosedTab, newGroups);
1774
1906
  };
1775
1907
 
1776
- const findTabInState = (state, groupId, tabId) => {
1777
- const {
1778
- layout
1779
- } = state;
1780
- const group = layout.groups.find(g => g.id === groupId);
1781
- return group?.tabs.find(t => t.id === tabId);
1908
+ const handleAttach = async command => {
1909
+ // TODO find a better way to append editors
1910
+ const parentNodeSelector = '.editor-groups-container, .EditorGroup';
1911
+ await invoke('Layout.attachViewlet', parentNodeSelector, command.instanceId);
1782
1912
  };
1783
1913
 
1784
- const saveEditor = async editorUid => {
1785
- return invoke('Editor.save', editorUid);
1914
+ const getTitle$1 = async editorUid => {
1915
+ try {
1916
+ const title = await invoke('Viewlet.getTitle', editorUid);
1917
+ return typeof title === 'string' && title ? title : undefined;
1918
+ } catch {
1919
+ return undefined;
1920
+ }
1921
+ };
1922
+ const createViewlet = async (viewletModuleId, editorUid, tabId, bounds, uri) => {
1923
+ await invoke('Layout.createViewlet', viewletModuleId, editorUid, tabId, bounds, uri);
1924
+ return getTitle$1(editorUid);
1786
1925
  };
1787
1926
 
1788
- const closeTabAndSave = async (state, groupId, tabId) => {
1789
- const tab = findTabInState(state, groupId, tabId);
1790
- if (!tab) {
1791
- return state;
1792
- }
1793
- if (tab.editorUid !== -1 && tab.isDirty) {
1794
- const editorState = await saveEditor(tab.editorUid);
1795
- if (!editorState?.modified && tab.uri) {
1796
- await handleModifiedStatusChange$1(tab.uri, false);
1797
- }
1798
- }
1799
- return closeTab(state, groupId, tabId);
1927
+ const {
1928
+ get,
1929
+ getCommandIds,
1930
+ getKeys: getKeys$1,
1931
+ registerCommands,
1932
+ set,
1933
+ wrapAsyncCommand,
1934
+ wrapGetter,
1935
+ wrapSerialAsyncCommand,
1936
+ wrapSerialCommand
1937
+ } = create$f();
1938
+
1939
+ const create$2 = () => {
1940
+ return Math.random();
1800
1941
  };
1801
1942
 
1802
- const getFocusedGroup = state => {
1943
+ const updateTab = (state, tabId, updates) => {
1803
1944
  const {
1804
1945
  layout
1805
1946
  } = state;
1806
1947
  const {
1807
1948
  groups
1808
1949
  } = layout;
1809
- return groups.find(group => group.focused);
1810
- };
1811
-
1812
- const closeActiveEditor = async state => {
1813
- const focusedGroup = getFocusedGroup(state);
1814
- if (!focusedGroup) {
1815
- return state;
1816
- }
1817
- const {
1818
- activeTabId
1819
- } = focusedGroup;
1820
- if (activeTabId === undefined) {
1821
- return state;
1822
- }
1823
- return closeTabAndSave(state, focusedGroup.id, activeTabId);
1824
- };
1825
-
1826
- const closeAll$1 = state => {
1827
- const entries = state.layout.groups.flatMap((group, groupIndex) => {
1828
- return group.tabs.map((tab, tabIndex) => ({
1829
- group,
1830
- groupIndex,
1831
- tab,
1832
- tabIndex
1833
- }));
1950
+ const updatedGroups = groups.map(group => {
1951
+ const tabIndex = group.tabs.findIndex(t => t.id === tabId);
1952
+ if (tabIndex === -1) {
1953
+ return group;
1954
+ }
1955
+ const updatedTabs = group.tabs.map((tab, index) => {
1956
+ if (index === tabIndex) {
1957
+ return {
1958
+ ...tab,
1959
+ ...updates
1960
+ };
1961
+ }
1962
+ return tab;
1963
+ });
1964
+ return {
1965
+ ...group,
1966
+ tabs: updatedTabs
1967
+ };
1834
1968
  });
1835
- return withEmptyGroups(addClosedTabs(state, entries));
1836
- };
1837
-
1838
- const redistributeSizesWithRemainder = groups => {
1839
- const baseSize = Math.floor(100 / groups.length);
1840
- const remainder = 100 % groups.length;
1841
- return groups.map((group, index) => ({
1842
- ...group,
1843
- size: baseSize + (index === groups.length - 1 ? remainder : 0)
1844
- }));
1969
+ return {
1970
+ ...state,
1971
+ layout: {
1972
+ ...layout,
1973
+ groups: updatedGroups
1974
+ }
1975
+ };
1845
1976
  };
1846
1977
 
1847
- const closeEditorGroup$1 = (state, groupId) => {
1848
- if (Number.isNaN(groupId)) {
1849
- return state;
1850
- }
1978
+ const findTab = (state, tabId) => {
1851
1979
  const {
1852
1980
  layout
1853
1981
  } = state;
1854
1982
  const {
1855
- activeGroupId,
1856
1983
  groups
1857
1984
  } = layout;
1858
- const groupIndex = getGroupIndexById(state, groupId);
1859
- if (groupIndex === -1 || groups.length <= 1) {
1860
- return state;
1985
+ for (const group of groups) {
1986
+ const tab = group.tabs.find(t => t.id === tabId);
1987
+ if (tab) {
1988
+ return tab;
1989
+ }
1861
1990
  }
1862
- const remainingGroups = groups.filter(group => group.id !== groupId);
1863
- const redistributedGroups = redistributeSizesWithRemainder(remainingGroups);
1864
- const newActiveGroupId = activeGroupId === groupId ? remainingGroups[0].id : activeGroupId;
1865
- return withGroupsAndActiveGroup(state, redistributedGroups, newActiveGroupId);
1991
+ return undefined;
1992
+ };
1993
+ const loadFileContent = async path => {
1994
+ const content = await readFile(path);
1995
+ return content;
1996
+ };
1997
+ const getLoadFileErrorMessage = error => {
1998
+ if (!(error instanceof Error)) {
1999
+ return 'Failed to load file content';
2000
+ }
2001
+ if (error.message.includes('EISDIR') || error.message.includes('illegal operation on a directory') || error.message.includes('is a directory')) {
2002
+ return 'Expected a file but received a folder';
2003
+ }
2004
+ return error.message;
1866
2005
  };
2006
+ const loadTabContentAsync = async (tabId, path, requestId, getLatestState) => {
2007
+ try {
2008
+ await loadFileContent(path);
1867
2009
 
1868
- const isFocused = group => {
1869
- return group.focused;
2010
+ // Check for race condition: get the latest state
2011
+ const latestState = getLatestState();
2012
+ const latestTab = findTab(latestState, tabId);
2013
+
2014
+ // If the tab no longer exists, discard this result
2015
+ if (!latestTab) {
2016
+ return latestState;
2017
+ }
2018
+
2019
+ // If the tab is no longer in loading state, discard this result (newer request started)
2020
+ if (latestTab.loadingState !== 'loading') {
2021
+ return latestState;
2022
+ }
2023
+
2024
+ // Assign editorUid if tab doesn't have one yet
2025
+ const editorUid = latestTab.editorUid === -1 ? create$2() : latestTab.editorUid;
2026
+ return updateTab(latestState, tabId, {
2027
+ editorUid,
2028
+ errorMessage: undefined,
2029
+ loadingState: 'loaded'
2030
+ });
2031
+ } catch (error) {
2032
+ // Check for race condition before updating with error
2033
+ const latestState = getLatestState();
2034
+ const latestTab = findTab(latestState, tabId);
2035
+ if (!latestTab) {
2036
+ return latestState;
2037
+ }
2038
+
2039
+ // If the tab is no longer in loading state, discard this result (newer request started)
2040
+ if (latestTab.loadingState !== 'loading') {
2041
+ return latestState;
2042
+ }
2043
+ const errorMessage = getLoadFileErrorMessage(error);
2044
+ return updateTab(latestState, tabId, {
2045
+ errorMessage,
2046
+ loadingState: 'error'
2047
+ });
2048
+ }
1870
2049
  };
1871
- const closeFocusedTab = async state => {
1872
- const {
1873
- layout
1874
- } = state;
1875
- const {
1876
- groups
1877
- } = layout;
1878
- const focusedGroup = groups.find(isFocused);
1879
- if (!focusedGroup) {
2050
+
2051
+ /**
2052
+ * SAFE: Create viewlet for a tab (no visible side effects)
2053
+ * Can be called eagerly when tab is opened - the viewlet loads in the background.
2054
+ */
2055
+ const createViewletForTab = (state, tabId, viewletModuleId, bounds) => {
2056
+ const tab = findTab(state, tabId);
2057
+ if (!tab) {
1880
2058
  return state;
1881
2059
  }
1882
- const {
1883
- activeTabId
1884
- } = focusedGroup;
1885
- if (activeTabId === undefined) {
2060
+
2061
+ // If tab already has an editorUid or is loading/loaded, don't recreate
2062
+ if (tab.editorUid !== -1 || tab.loadingState === 'loading' || tab.loadingState === 'loaded') {
1886
2063
  return state;
1887
2064
  }
1888
- return closeTabAndSave(state, focusedGroup.id, activeTabId);
2065
+ const editorUid = create$2();
2066
+ const newState = updateTab(state, tabId, {
2067
+ editorUid
2068
+ });
2069
+ return newState;
1889
2070
  };
1890
2071
 
1891
- const closeOtherTabs = (state, groupId) => {
1892
- const {
2072
+ /**
2073
+ * Called when switching tabs.
2074
+ * With reference nodes, attachment/detachment is handled automatically by virtual DOM rendering.
2075
+ * No attach/detach commands needed - virtual DOM will render the correct reference at each position.
2076
+ */
2077
+ const switchViewlet = (state, fromTabId, toTabId) => {
2078
+ // No commands needed - virtual DOM reference nodes handle attachment automatically
2079
+ // Virtual DOM will:
2080
+ // 1. Remove the old reference node from the previous active tab
2081
+ // 2. Add the new reference node for the now-active tab
2082
+ // This achieves the same effect as detach/attach without explicit commands
2083
+
2084
+ return {
2085
+ commands: [],
2086
+ newState: state
2087
+ };
2088
+ };
2089
+
2090
+ const findTabByEditorUid = (state, editorUid) => {
2091
+ const {
2092
+ layout
2093
+ } = state;
2094
+ const {
2095
+ groups
2096
+ } = layout;
2097
+ for (const group of groups) {
2098
+ const tab = group.tabs.find(t => t.editorUid === editorUid);
2099
+ if (tab) {
2100
+ return tab;
2101
+ }
2102
+ }
2103
+ return undefined;
2104
+ };
2105
+
2106
+ /**
2107
+ * Called when renderer reports viewlet finished creating.
2108
+ * With reference nodes, attachment is handled automatically by virtual DOM rendering.
2109
+ * No commands needed - state update is sufficient.
2110
+ */
2111
+ const handleViewletReady = (state, editorUid, title) => {
2112
+ if (editorUid === -1) {
2113
+ throw new Error('Invalid editorUid -1');
2114
+ }
2115
+ // Find the tab by viewletRequestId
2116
+ const tab = findTabByEditorUid(state, editorUid);
2117
+ if (!tab) {
2118
+ // Tab was closed, dispose viewlet
2119
+ return state;
2120
+ }
2121
+
2122
+ // Mark viewlet as ready and set instance id
2123
+ // Reference nodes will handle rendering at the correct position automatically
2124
+ const newState = updateTab(state, tab.id, {
2125
+ editorUid,
2126
+ loadingState: 'loaded',
2127
+ ...(title && {
2128
+ title
2129
+ })
2130
+ });
2131
+
2132
+ // No attach commands needed - virtual DOM reference nodes handle positioning
2133
+ return newState;
2134
+ };
2135
+
2136
+ /**
2137
+ * Dispose viewlet when tab is closed.
2138
+ */
2139
+ const disposeViewletForTab = (state, tabId) => {
2140
+ const tab = findTab(state, tabId);
2141
+ if (!tab || tab.editorUid === -1) {
2142
+ return {
2143
+ commands: [],
2144
+ newState: state
2145
+ };
2146
+ }
2147
+ const commands = [{
2148
+ instanceId: tab.editorUid,
2149
+ type: 'dispose'
2150
+ }];
2151
+ return {
2152
+ commands,
2153
+ newState: state
2154
+ };
2155
+ };
2156
+
2157
+ const handleCreate = async command => {
2158
+ // Safe to call - no visible side effects
2159
+
2160
+ const title = await createViewlet(command.viewletModuleId, command.editorUid, command.tabId, command.bounds, command.uri || '');
2161
+
2162
+ // After viewlet is created, mark it as ready
2163
+ // Attachment is handled automatically by virtual DOM reference nodes
2164
+ const {
2165
+ newState: state,
2166
+ oldState
2167
+ } = get(command.uid);
2168
+ const readyState = handleViewletReady(state, command.editorUid, title);
2169
+ set(command.uid, oldState, readyState);
2170
+ return readyState;
2171
+ };
2172
+
2173
+ const handleDetach = async command => {
2174
+ // Hides viewlet but keeps it alive
2175
+
2176
+ await invoke('Viewlet.detach', command.instanceId);
2177
+ };
2178
+
2179
+ const handleDispose = async command => {
2180
+ // Fully destroys viewlet
2181
+
2182
+ await invoke('Viewlet.dispose', command.instanceId);
2183
+ };
2184
+
2185
+ const handleSetBounds = async command => {
2186
+ await invoke('Viewlet.setBounds', command.instanceId, command.bounds);
2187
+ };
2188
+
2189
+ const executeViewletCommand = async command => {
2190
+ switch (command.type) {
2191
+ case 'attach':
2192
+ await handleAttach(command);
2193
+ return;
2194
+ case 'create':
2195
+ await handleCreate(command);
2196
+ return;
2197
+ case 'detach':
2198
+ await handleDetach(command);
2199
+ return;
2200
+ case 'dispose':
2201
+ await handleDispose(command);
2202
+ return;
2203
+ case 'setBounds':
2204
+ await handleSetBounds(command);
2205
+ return;
2206
+ }
2207
+ };
2208
+ const executeViewletCommands = async commands => {
2209
+ for (const command of commands) {
2210
+ await executeViewletCommand(command);
2211
+ }
2212
+ };
2213
+
2214
+ const findTabInState = (state, groupId, tabId) => {
2215
+ const {
2216
+ layout
2217
+ } = state;
2218
+ const group = layout.groups.find(g => g.id === groupId);
2219
+ return group?.tabs.find(t => t.id === tabId);
2220
+ };
2221
+
2222
+ const closeTabWithViewlet = async (state, groupId, tabId) => {
2223
+ const tab = findTabInState(state, groupId, tabId);
2224
+ const commands = [];
2225
+ if (tab && tab.editorUid !== -1) {
2226
+ const {
2227
+ commands: disposeCommands
2228
+ } = disposeViewletForTab(state, tabId);
2229
+ commands.push(...disposeCommands);
2230
+ }
2231
+ const newState = closeTab(state, groupId, tabId);
2232
+ const group = state.layout.groups.find(g => g.id === groupId);
2233
+ const wasActiveTab = group?.activeTabId === tabId;
2234
+ if (wasActiveTab) {
2235
+ const newGroup = newState.layout.groups.find(g => g.id === groupId);
2236
+ const newActiveTabId = newGroup?.activeTabId;
2237
+ if (newActiveTabId !== undefined) {
2238
+ const {
2239
+ commands: switchCommands,
2240
+ newState: switchedState
2241
+ } = switchViewlet(newState);
2242
+ commands.push(...switchCommands);
2243
+ await executeViewletCommands(commands);
2244
+ return switchedState;
2245
+ }
2246
+ }
2247
+ if (commands.length > 0) {
2248
+ await executeViewletCommands(commands);
2249
+ }
2250
+ return newState;
2251
+ };
2252
+
2253
+ const saveEditor = async editorUid => {
2254
+ return invoke('Editor.save', editorUid);
2255
+ };
2256
+
2257
+ const closeTabAndSave = async (state, groupId, tabId) => {
2258
+ const tab = findTabInState(state, groupId, tabId);
2259
+ if (!tab) {
2260
+ return state;
2261
+ }
2262
+ if (tab.editorUid !== -1 && tab.isDirty) {
2263
+ const editorState = await saveEditor(tab.editorUid);
2264
+ if (!editorState?.modified && tab.uri) {
2265
+ await handleModifiedStatusChange$1(tab.uri, false);
2266
+ }
2267
+ }
2268
+ if (tab.uri?.startsWith('simple-browser://')) {
2269
+ return closeTabWithViewlet(state, groupId, tabId);
2270
+ }
2271
+ return closeTab(state, groupId, tabId);
2272
+ };
2273
+
2274
+ const getFocusedGroup = state => {
2275
+ const {
2276
+ layout
2277
+ } = state;
2278
+ const {
2279
+ groups
2280
+ } = layout;
2281
+ return groups.find(group => group.focused);
2282
+ };
2283
+
2284
+ const closeActiveEditor = async state => {
2285
+ const focusedGroup = getFocusedGroup(state);
2286
+ if (!focusedGroup) {
2287
+ return state;
2288
+ }
2289
+ const {
2290
+ activeTabId
2291
+ } = focusedGroup;
2292
+ if (activeTabId === undefined) {
2293
+ return state;
2294
+ }
2295
+ return closeTabAndSave(state, focusedGroup.id, activeTabId);
2296
+ };
2297
+
2298
+ const closeAll$1 = state => {
2299
+ const entries = state.layout.groups.flatMap((group, groupIndex) => {
2300
+ return group.tabs.map((tab, tabIndex) => ({
2301
+ group,
2302
+ groupIndex,
2303
+ tab,
2304
+ tabIndex
2305
+ }));
2306
+ });
2307
+ return withEmptyGroups(addClosedTabs(state, entries));
2308
+ };
2309
+
2310
+ const redistributeSizesWithRemainder = groups => {
2311
+ const baseSize = Math.floor(100 / groups.length);
2312
+ const remainder = 100 % groups.length;
2313
+ return groups.map((group, index) => ({
2314
+ ...group,
2315
+ size: baseSize + (index === groups.length - 1 ? remainder : 0)
2316
+ }));
2317
+ };
2318
+
2319
+ const closeEditorGroup$1 = (state, groupId) => {
2320
+ if (Number.isNaN(groupId)) {
2321
+ return state;
2322
+ }
2323
+ const {
2324
+ layout
2325
+ } = state;
2326
+ const {
2327
+ activeGroupId,
2328
+ groups
2329
+ } = layout;
2330
+ const groupIndex = getGroupIndexById(state, groupId);
2331
+ if (groupIndex === -1 || groups.length <= 1) {
2332
+ return state;
2333
+ }
2334
+ const remainingGroups = groups.filter(group => group.id !== groupId);
2335
+ const redistributedGroups = redistributeSizesWithRemainder(remainingGroups);
2336
+ const newActiveGroupId = activeGroupId === groupId ? remainingGroups[0].id : activeGroupId;
2337
+ return withGroupsAndActiveGroup(state, redistributedGroups, newActiveGroupId);
2338
+ };
2339
+
2340
+ const isFocused = group => {
2341
+ return group.focused;
2342
+ };
2343
+ const closeFocusedTab = async state => {
2344
+ const {
2345
+ layout
2346
+ } = state;
2347
+ const {
2348
+ groups
2349
+ } = layout;
2350
+ const focusedGroup = groups.find(isFocused);
2351
+ if (!focusedGroup) {
2352
+ return state;
2353
+ }
2354
+ const {
2355
+ activeTabId
2356
+ } = focusedGroup;
2357
+ if (activeTabId === undefined) {
2358
+ return state;
2359
+ }
2360
+ return closeTabAndSave(state, focusedGroup.id, activeTabId);
2361
+ };
2362
+
2363
+ const closeOtherTabs = (state, groupId) => {
2364
+ const {
1893
2365
  layout
1894
2366
  } = state;
1895
2367
  const {
@@ -2098,359 +2570,90 @@ const copyRelativePath$1 = async (state, path) => {
2098
2570
  // TODO use clipboard worker
2099
2571
  const relativePath = await invoke('Workspace.pathBaseName', path);
2100
2572
  await invoke('ClipBoard.writeText', relativePath);
2101
- return state;
2102
- };
2103
-
2104
- const Horizontal = 1;
2105
- const Vertical = 2;
2106
- const isLayoutDirection = direction => {
2107
- return direction === Horizontal || direction === Vertical;
2108
- };
2109
- const normalizeLayoutDirection = direction => {
2110
- if (isLayoutDirection(direction)) {
2111
- return direction;
2112
- }
2113
- if (direction === 'horizontal') {
2114
- return Horizontal;
2115
- }
2116
- if (direction === 'vertical') {
2117
- return Vertical;
2118
- }
2119
- return undefined;
2120
- };
2121
-
2122
- const {
2123
- get,
2124
- getCommandIds,
2125
- getKeys: getKeys$1,
2126
- registerCommands,
2127
- set,
2128
- wrapCommand,
2129
- wrapGetter
2130
- } = create$f();
2131
-
2132
- const create$2 = (uid, uri, x, y, width, height, platform, assetDir, tabHeight = 35) => {
2133
- const state = {
2134
- assetDir,
2135
- closedTabs: [],
2136
- fileIconCache: {},
2137
- height,
2138
- homeDirUri: '',
2139
- iframes: [],
2140
- initial: true,
2141
- layout: {
2142
- activeGroupId: undefined,
2143
- direction: Horizontal,
2144
- groups: []
2145
- },
2146
- maxOpenEditorGroups: Infinity,
2147
- maxOpenEditors: Infinity,
2148
- minGroupHeightPx: 80,
2149
- minGroupWidthPx: 250,
2150
- platform,
2151
- splitButtonEnabled: false,
2152
- tabHeight,
2153
- uid,
2154
- width,
2155
- workspaceuri: uri,
2156
- x,
2157
- y
2158
- };
2159
- set(uid, state, state);
2160
- };
2161
-
2162
- const isEqual$1 = (oldState, newState) => {
2163
- return false;
2164
- };
2165
-
2166
- const isEqual = (oldState, newState) => {
2167
- return oldState.layout === newState.layout;
2168
- };
2169
-
2170
- const RenderItems = 4;
2171
- const RenderCss = 10;
2172
- const RenderIncremental = 11;
2173
-
2174
- const modules = [isEqual, isEqual$1];
2175
- const numbers = [RenderIncremental, RenderCss];
2176
-
2177
- const diff = (oldState, newState) => {
2178
- const diffResult = [];
2179
- for (let i = 0; i < modules.length; i++) {
2180
- const fn = modules[i];
2181
- if (!fn(oldState, newState)) {
2182
- diffResult.push(numbers[i]);
2183
- }
2184
- }
2185
- return diffResult;
2186
- };
2187
-
2188
- const diff2 = uid => {
2189
- const {
2190
- newState,
2191
- oldState
2192
- } = get(uid);
2193
- const result = diff(oldState, newState);
2194
- return result;
2195
- };
2196
-
2197
- const handleAttach = async command => {
2198
- // TODO find a better way to append editors
2199
- const parentNodeSelector = '.editor-groups-container, .EditorGroup';
2200
- await invoke('Layout.attachViewlet', parentNodeSelector, command.instanceId);
2201
- };
2202
-
2203
- const create$1 = () => {
2204
- return Math.random();
2205
- };
2206
-
2207
- const updateTab = (state, tabId, updates) => {
2208
- const {
2209
- layout
2210
- } = state;
2211
- const {
2212
- groups
2213
- } = layout;
2214
- const updatedGroups = groups.map(group => {
2215
- const tabIndex = group.tabs.findIndex(t => t.id === tabId);
2216
- if (tabIndex === -1) {
2217
- return group;
2218
- }
2219
- const updatedTabs = group.tabs.map((tab, index) => {
2220
- if (index === tabIndex) {
2221
- return {
2222
- ...tab,
2223
- ...updates
2224
- };
2225
- }
2226
- return tab;
2227
- });
2228
- return {
2229
- ...group,
2230
- tabs: updatedTabs
2231
- };
2232
- });
2233
- return {
2234
- ...state,
2235
- layout: {
2236
- ...layout,
2237
- groups: updatedGroups
2238
- }
2239
- };
2240
- };
2241
-
2242
- const findTab = (state, tabId) => {
2243
- const {
2244
- layout
2245
- } = state;
2246
- const {
2247
- groups
2248
- } = layout;
2249
- for (const group of groups) {
2250
- const tab = group.tabs.find(t => t.id === tabId);
2251
- if (tab) {
2252
- return tab;
2253
- }
2254
- }
2255
- return undefined;
2256
- };
2257
- const loadFileContent = async path => {
2258
- const content = await readFile(path);
2259
- return content;
2260
- };
2261
- const getLoadFileErrorMessage = error => {
2262
- if (!(error instanceof Error)) {
2263
- return 'Failed to load file content';
2264
- }
2265
- if (error.message.includes('EISDIR') || error.message.includes('illegal operation on a directory') || error.message.includes('is a directory')) {
2266
- return 'Expected a file but received a folder';
2267
- }
2268
- return error.message;
2269
- };
2270
- const loadTabContentAsync = async (tabId, path, requestId, getLatestState) => {
2271
- try {
2272
- await loadFileContent(path);
2273
-
2274
- // Check for race condition: get the latest state
2275
- const latestState = getLatestState();
2276
- const latestTab = findTab(latestState, tabId);
2277
-
2278
- // If the tab no longer exists, discard this result
2279
- if (!latestTab) {
2280
- return latestState;
2281
- }
2282
-
2283
- // If the tab is no longer in loading state, discard this result (newer request started)
2284
- if (latestTab.loadingState !== 'loading') {
2285
- return latestState;
2286
- }
2287
-
2288
- // Assign editorUid if tab doesn't have one yet
2289
- const editorUid = latestTab.editorUid === -1 ? create$1() : latestTab.editorUid;
2290
- return updateTab(latestState, tabId, {
2291
- editorUid,
2292
- errorMessage: undefined,
2293
- loadingState: 'loaded'
2294
- });
2295
- } catch (error) {
2296
- // Check for race condition before updating with error
2297
- const latestState = getLatestState();
2298
- const latestTab = findTab(latestState, tabId);
2299
- if (!latestTab) {
2300
- return latestState;
2301
- }
2302
-
2303
- // If the tab is no longer in loading state, discard this result (newer request started)
2304
- if (latestTab.loadingState !== 'loading') {
2305
- return latestState;
2306
- }
2307
- const errorMessage = getLoadFileErrorMessage(error);
2308
- return updateTab(latestState, tabId, {
2309
- errorMessage,
2310
- loadingState: 'error'
2311
- });
2312
- }
2313
- };
2314
-
2315
- /**
2316
- * SAFE: Create viewlet for a tab (no visible side effects)
2317
- * Can be called eagerly when tab is opened - the viewlet loads in the background.
2318
- */
2319
- const createViewletForTab = (state, tabId, viewletModuleId, bounds) => {
2320
- const tab = findTab(state, tabId);
2321
- if (!tab) {
2322
- return state;
2323
- }
2324
-
2325
- // If tab already has an editorUid or is loading/loaded, don't recreate
2326
- if (tab.editorUid !== -1 || tab.loadingState === 'loading' || tab.loadingState === 'loaded') {
2327
- return state;
2328
- }
2329
- const editorUid = create$1();
2330
- const newState = updateTab(state, tabId, {
2331
- editorUid
2332
- });
2333
- return newState;
2334
- };
2335
-
2336
- /**
2337
- * Called when switching tabs.
2338
- * With reference nodes, attachment/detachment is handled automatically by virtual DOM rendering.
2339
- * No attach/detach commands needed - virtual DOM will render the correct reference at each position.
2340
- */
2341
- const switchViewlet = (state, fromTabId, toTabId) => {
2342
- // No commands needed - virtual DOM reference nodes handle attachment automatically
2343
- // Virtual DOM will:
2344
- // 1. Remove the old reference node from the previous active tab
2345
- // 2. Add the new reference node for the now-active tab
2346
- // This achieves the same effect as detach/attach without explicit commands
2347
-
2348
- return {
2349
- commands: [],
2350
- newState: state
2351
- };
2352
- };
2353
-
2354
- const findTabByEditorUid = (state, editorUid) => {
2355
- const {
2356
- layout
2357
- } = state;
2358
- const {
2359
- groups
2360
- } = layout;
2361
- for (const group of groups) {
2362
- const tab = group.tabs.find(t => t.editorUid === editorUid);
2363
- if (tab) {
2364
- return tab;
2365
- }
2366
- }
2367
- return undefined;
2573
+ return state;
2368
2574
  };
2369
2575
 
2370
- /**
2371
- * Called when renderer reports viewlet finished creating.
2372
- * With reference nodes, attachment is handled automatically by virtual DOM rendering.
2373
- * No commands needed - state update is sufficient.
2374
- */
2375
- const handleViewletReady = (state, editorUid) => {
2376
- if (editorUid === -1) {
2377
- throw new Error('Invalid editorUid -1');
2576
+ const Horizontal = 1;
2577
+ const Vertical = 2;
2578
+ const isLayoutDirection = direction => {
2579
+ return direction === Horizontal || direction === Vertical;
2580
+ };
2581
+ const normalizeLayoutDirection = direction => {
2582
+ if (isLayoutDirection(direction)) {
2583
+ return direction;
2378
2584
  }
2379
- // Find the tab by viewletRequestId
2380
- const tab = findTabByEditorUid(state, editorUid);
2381
- if (!tab) {
2382
- // Tab was closed, dispose viewlet
2383
- return state;
2585
+ if (direction === 'horizontal') {
2586
+ return Horizontal;
2384
2587
  }
2385
-
2386
- // Mark viewlet as ready and set instance id
2387
- // Reference nodes will handle rendering at the correct position automatically
2388
- const newState = updateTab(state, tab.id, {
2389
- editorUid,
2390
- loadingState: 'loaded'
2391
- });
2392
-
2393
- // No attach commands needed - virtual DOM reference nodes handle positioning
2394
- return newState;
2588
+ if (direction === 'vertical') {
2589
+ return Vertical;
2590
+ }
2591
+ return undefined;
2395
2592
  };
2396
2593
 
2397
- const handleCreate = async command => {
2398
- // Safe to call - no visible side effects
2399
-
2400
- const instanceId = Math.random(); // TODO try to find a better way to get consistent integer ids (thread safe)
2401
-
2402
- await invoke('Layout.createViewlet', command.viewletModuleId, command.tabId, command.bounds, command.uri, instanceId);
2403
-
2404
- // After viewlet is created, mark it as ready
2405
- // Attachment is handled automatically by virtual DOM reference nodes
2406
- const {
2407
- newState: state,
2408
- oldState
2409
- } = get(command.uid);
2410
- const readyState = handleViewletReady(state, command.editorUid);
2411
- set(command.uid, oldState, readyState);
2412
- return readyState;
2594
+ const create$1 = (uid, uri, x, y, width, height, platform, assetDir, tabHeight = 35) => {
2595
+ const state = {
2596
+ assetDir,
2597
+ closedTabs: [],
2598
+ fileIconCache: {},
2599
+ height,
2600
+ homeDirUri: '',
2601
+ iframes: [],
2602
+ initial: true,
2603
+ layout: {
2604
+ activeGroupId: undefined,
2605
+ direction: Horizontal,
2606
+ groups: []
2607
+ },
2608
+ maxOpenEditorGroups: Infinity,
2609
+ maxOpenEditors: Infinity,
2610
+ minGroupHeightPx: 80,
2611
+ minGroupWidthPx: 250,
2612
+ platform,
2613
+ splitButtonEnabled: false,
2614
+ tabHeight,
2615
+ uid,
2616
+ width,
2617
+ workspaceuri: uri,
2618
+ x,
2619
+ y
2620
+ };
2621
+ set(uid, state, state);
2413
2622
  };
2414
2623
 
2415
- const handleDetach = async command => {
2416
- // Hides viewlet but keeps it alive
2417
-
2418
- await invoke('Viewlet.detach', command.instanceId);
2624
+ const isEqual$1 = (oldState, newState) => {
2625
+ return false;
2419
2626
  };
2420
2627
 
2421
- const handleDispose = async command => {
2422
- // Fully destroys viewlet
2423
-
2424
- await invoke('Viewlet.dispose', command.instanceId);
2628
+ const isEqual = (oldState, newState) => {
2629
+ return oldState.layout === newState.layout;
2425
2630
  };
2426
2631
 
2427
- const handleSetBounds = async command => {
2428
- await invoke('Viewlet.setBounds', command.instanceId, command.bounds);
2429
- };
2632
+ const RenderItems = 4;
2633
+ const RenderCss = 10;
2634
+ const RenderIncremental = 11;
2430
2635
 
2431
- const executeViewletCommand = async command => {
2432
- switch (command.type) {
2433
- case 'attach':
2434
- await handleAttach(command);
2435
- return;
2436
- case 'create':
2437
- await handleCreate(command);
2438
- return;
2439
- case 'detach':
2440
- await handleDetach(command);
2441
- return;
2442
- case 'dispose':
2443
- await handleDispose(command);
2444
- return;
2445
- case 'setBounds':
2446
- await handleSetBounds(command);
2447
- return;
2636
+ const modules = [isEqual, isEqual$1];
2637
+ const numbers = [RenderIncremental, RenderCss];
2638
+
2639
+ const diff = (oldState, newState) => {
2640
+ const diffResult = [];
2641
+ for (let i = 0; i < modules.length; i++) {
2642
+ const fn = modules[i];
2643
+ if (!fn(oldState, newState)) {
2644
+ diffResult.push(numbers[i]);
2645
+ }
2448
2646
  }
2647
+ return diffResult;
2449
2648
  };
2450
- const executeViewletCommands = async commands => {
2451
- for (const command of commands) {
2452
- await executeViewletCommand(command);
2453
- }
2649
+
2650
+ const diff2 = uid => {
2651
+ const {
2652
+ newState,
2653
+ oldState
2654
+ } = get(uid);
2655
+ const result = diff(oldState, newState);
2656
+ return result;
2454
2657
  };
2455
2658
 
2456
2659
  const requestIdState = {
@@ -2685,10 +2888,6 @@ const getUpdatedGroups = (groups, groupIndex, needsLoading, tabId) => {
2685
2888
  });
2686
2889
  };
2687
2890
 
2688
- const createViewlet = async (viewletModuleId, editorUid, tabId, bounds, uri) => {
2689
- await invoke('Layout.createViewlet', viewletModuleId, editorUid, tabId, bounds, uri);
2690
- };
2691
-
2692
2891
  const findTabById = (state, tabId) => {
2693
2892
  const {
2694
2893
  layout
@@ -2803,8 +3002,8 @@ const maybeCreateViewletForSelectedTab = async (state, newState, groupIndex, ind
2803
3002
  editorUid
2804
3003
  } = tabWithViewlet.tab;
2805
3004
  if (editorUid !== -1 && selectedTab.uri) {
2806
- await createViewlet(viewletModuleId, editorUid, tabId, bounds, selectedTab.uri);
2807
- stateWithViewlet = handleViewletReady(stateWithViewlet, editorUid);
3005
+ const title = await createViewlet(viewletModuleId, editorUid, tabId, bounds, selectedTab.uri);
3006
+ stateWithViewlet = handleViewletReady(stateWithViewlet, editorUid, title);
2808
3007
  set(uid, state, stateWithViewlet);
2809
3008
  }
2810
3009
  }
@@ -3348,9 +3547,9 @@ const createEmptyGroup$1 = (state, uri, requestId, preview = false, title = getL
3348
3547
  const {
3349
3548
  groups
3350
3549
  } = layout;
3351
- const groupId = create$1();
3352
- const tabId = create$1();
3353
- const editorUid = create$1();
3550
+ const groupId = create$2();
3551
+ const tabId = create$2();
3552
+ const editorUid = create$2();
3354
3553
  const newTab = {
3355
3554
  editorInput,
3356
3555
  editorType,
@@ -3391,7 +3590,7 @@ const openTab = (state, groupId, tab) => {
3391
3590
  };
3392
3591
  const newTab = 'id' in normalizedTab && normalizedTab.id !== undefined ? normalizedTab : {
3393
3592
  ...normalizedTab,
3394
- id: create$1()
3593
+ id: create$2()
3395
3594
  };
3396
3595
  const {
3397
3596
  layout
@@ -3478,8 +3677,8 @@ const ensureActiveGroup = (state, uri, preview = false, title = getLabel(uri), e
3478
3677
  }
3479
3678
 
3480
3679
  // Create a new tab with the URI in the active group
3481
- const tabId = create$1();
3482
- const editorUid = create$1();
3680
+ const tabId = create$2();
3681
+ const editorUid = create$2();
3483
3682
  const newTab = {
3484
3683
  editorInput,
3485
3684
  editorType,
@@ -3669,7 +3868,7 @@ const getFileIconsForTabs = async (tabs, fileIconCache) => {
3669
3868
  };
3670
3869
  };
3671
3870
 
3672
- const updateTabIcon = async (uid, state, readyState, tabId) => {
3871
+ const updateTabIcon = async (context, readyState, tabId) => {
3673
3872
  const newTab = findTabById(readyState, tabId);
3674
3873
  if (!newTab || !newTab.tab.uri) {
3675
3874
  return undefined;
@@ -3678,9 +3877,7 @@ const updateTabIcon = async (uid, state, readyState, tabId) => {
3678
3877
  const {
3679
3878
  newFileIconCache
3680
3879
  } = await getFileIconsForTabs([newTab.tab], readyState.fileIconCache);
3681
- const {
3682
- newState: stateBeforeIconUpdate
3683
- } = get(uid);
3880
+ const stateBeforeIconUpdate = context.getState();
3684
3881
  const icon = newFileIconCache[newTab.tab.uri] || '';
3685
3882
  const stateWithIcon = {
3686
3883
  ...stateBeforeIconUpdate,
@@ -3696,19 +3893,16 @@ const updateTabIcon = async (uid, state, readyState, tabId) => {
3696
3893
  }))
3697
3894
  }
3698
3895
  };
3699
- set(uid, state, stateWithIcon);
3700
- return stateWithIcon;
3896
+ return context.updateState(() => stateWithIcon);
3701
3897
  } catch {
3702
3898
  return undefined;
3703
3899
  }
3704
3900
  };
3705
3901
 
3706
- const openInput = async (state, options) => {
3902
+ const openInputWithContext = async (context, options) => {
3903
+ const state = context.getState();
3707
3904
  object(state);
3708
3905
  object(options);
3709
- const {
3710
- uid
3711
- } = state;
3712
3906
  const {
3713
3907
  editorInput
3714
3908
  } = options;
@@ -3716,40 +3910,40 @@ const openInput = async (state, options) => {
3716
3910
  const uri = getEditorInputUri(editorInput);
3717
3911
  const title = getEditorInputTitle(editorInput);
3718
3912
  const editorType = getEditorInputEditorType(editorInput);
3719
- const currentState = getCurrentState(state);
3913
+ const currentState = state;
3720
3914
  const existingTab = findTabByUri(currentState, uri);
3721
3915
  const shouldRetryExistingTab = !!existingTab && existingTab.tab.loadingState === 'error';
3722
3916
  if (existingTab && !shouldRetryExistingTab) {
3723
3917
  const focusedState = focusEditorGroup(currentState, existingTab.groupId);
3724
- return switchTab(focusedState, existingTab.groupId, existingTab.tab.id);
3918
+ const switchedState = switchTab(focusedState, existingTab.groupId, existingTab.tab.id);
3919
+ await context.updateState(() => switchedState);
3920
+ return;
3725
3921
  }
3726
3922
  const previousTabId = getActiveTabId(currentState);
3727
3923
  const {
3728
3924
  stateWithTab,
3729
3925
  tabId
3730
3926
  } = getStateWithTab(currentState, editorInput, existingTab, shouldRetryExistingTab, uri, preview, title, editorType);
3731
- set(uid, state, stateWithTab);
3927
+ await context.updateState(() => stateWithTab);
3732
3928
  if (await isDirectoryEditorInput(editorInput)) {
3733
- const {
3734
- newState: latestState
3735
- } = get(uid);
3929
+ const latestState = context.getState();
3736
3930
  const errorState = updateTab(latestState, tabId, {
3737
3931
  errorMessage: 'Expected a file but received a folder',
3738
3932
  loadingState: 'error'
3739
3933
  });
3740
- set(uid, state, errorState);
3741
- return errorState;
3934
+ await context.updateState(() => errorState);
3935
+ return;
3742
3936
  }
3743
3937
  try {
3744
3938
  const viewletModuleId = await getViewletModuleIdForEditorInput(editorInput);
3745
- const {
3746
- newState: stateAfterModuleId
3747
- } = get(uid);
3939
+ const stateAfterModuleId = context.getState();
3748
3940
  if (!viewletModuleId) {
3749
- return updateTab(stateAfterModuleId, tabId, {
3941
+ const unsupportedState = updateTab(stateAfterModuleId, tabId, {
3750
3942
  errorMessage: 'Could not determine editor type for this URI',
3751
3943
  loadingState: 'error'
3752
3944
  });
3945
+ await context.updateState(() => unsupportedState);
3946
+ return;
3753
3947
  }
3754
3948
  const bounds = {
3755
3949
  height: stateAfterModuleId.height - stateAfterModuleId.tabHeight,
@@ -3763,10 +3957,10 @@ const openInput = async (state, options) => {
3763
3957
  newState: switchedState
3764
3958
  } = switchViewlet(intermediateState, previousTabId, tabId);
3765
3959
  intermediateState = switchedState;
3766
- set(uid, state, intermediateState);
3960
+ await context.updateState(() => intermediateState);
3767
3961
  const tabWithViewlet = findTabById(intermediateState, tabId);
3768
3962
  if (!tabWithViewlet) {
3769
- return intermediateState;
3963
+ return;
3770
3964
  }
3771
3965
  const {
3772
3966
  editorUid
@@ -3774,33 +3968,42 @@ const openInput = async (state, options) => {
3774
3968
  if (editorUid === -1) {
3775
3969
  throw new Error('invalid editorUid');
3776
3970
  }
3777
- await createViewlet(viewletModuleId, editorUid, tabId, bounds, uri);
3778
- const {
3779
- newState: latestState
3780
- } = get(uid);
3781
- const readyState = handleViewletReady(latestState, editorUid);
3782
- set(uid, state, readyState);
3783
- const stateWithIcon = await updateTabIcon(uid, state, readyState, tabId);
3971
+ const renderedTitle = await createViewlet(viewletModuleId, editorUid, tabId, bounds, uri);
3972
+ const latestState = context.getState();
3973
+ const readyState = handleViewletReady(latestState, editorUid, renderedTitle);
3974
+ await context.updateState(() => readyState);
3975
+ const stateWithIcon = await updateTabIcon(context, readyState, tabId);
3784
3976
  if (stateWithIcon) {
3785
- return stateWithIcon;
3977
+ return;
3786
3978
  }
3787
- const {
3788
- newState: finalState
3789
- } = get(uid);
3790
- return finalState;
3791
3979
  } catch (error) {
3792
- const {
3793
- newState: latestState
3794
- } = get(uid);
3980
+ const latestState = context.getState();
3795
3981
  const errorMessage = error instanceof Error ? error.message : 'Failed to open URI';
3796
3982
  const errorState = updateTab(latestState, tabId, {
3797
3983
  errorMessage,
3798
3984
  loadingState: 'error'
3799
3985
  });
3800
- set(uid, state, errorState);
3801
- return errorState;
3986
+ await context.updateState(() => errorState);
3802
3987
  }
3803
3988
  };
3989
+ const openInput = async (state, options) => {
3990
+ const {
3991
+ uid
3992
+ } = state;
3993
+ let currentState = getCurrentState(state);
3994
+ const context = {
3995
+ getState: () => get(uid)?.newState ?? currentState,
3996
+ updateState: updater => {
3997
+ const storedState = get(uid);
3998
+ const latestState = storedState?.newState ?? currentState;
3999
+ currentState = updater(latestState);
4000
+ set(uid, storedState?.oldState ?? state, currentState);
4001
+ return Promise.resolve(currentState);
4002
+ }
4003
+ };
4004
+ await openInputWithContext(context, options);
4005
+ return context.getState();
4006
+ };
3804
4007
 
3805
4008
  const getOptionUriOptions = options => {
3806
4009
  if (typeof options === 'string') {
@@ -3809,14 +4012,20 @@ const getOptionUriOptions = options => {
3809
4012
  return options.uri;
3810
4013
  };
3811
4014
 
3812
- const openUri = async (state, options) => {
4015
+ const getOpenInputOptions = options => {
3813
4016
  const uri = getOptionUriOptions(options);
3814
4017
  const preview = typeof options === 'string' ? false : options.preview ?? false;
3815
- return openInput(state, {
4018
+ return {
3816
4019
  editorInput: getNormalizedOpenEditorInput(uri),
3817
4020
  focus: typeof options === 'string' ? false : options.focus,
3818
4021
  preview
3819
- });
4022
+ };
4023
+ };
4024
+ const openUri = async (state, options) => {
4025
+ return openInput(state, getOpenInputOptions(options));
4026
+ };
4027
+ const openUriWithContext = async (context, options) => {
4028
+ await openInputWithContext(context, getOpenInputOptions(options));
3820
4029
  };
3821
4030
 
3822
4031
  const retryOpen = async state => {
@@ -4002,7 +4211,7 @@ const splitEditorGroup$1 = (state, groupId, direction) => {
4002
4211
  if (!sourceGroup) {
4003
4212
  return state;
4004
4213
  }
4005
- const newGroupId = create$1();
4214
+ const newGroupId = create$2();
4006
4215
  const splitLayoutDirection = getSplitLayoutDirection(direction);
4007
4216
  const baseNewGroup = {
4008
4217
  activeTabId: undefined,
@@ -4219,8 +4428,8 @@ const newFile = async state => {
4219
4428
  getActiveTabId(newState);
4220
4429
 
4221
4430
  // Create a new empty tab
4222
- const tabId = create$1();
4223
- const editorUid = create$1();
4431
+ const tabId = create$2();
4432
+ const editorUid = create$2();
4224
4433
  const newTab = {
4225
4434
  editorType: 'text',
4226
4435
  editorUid,
@@ -4265,13 +4474,13 @@ const newFile = async state => {
4265
4474
  if (actualEditorUid === -1) {
4266
4475
  throw new Error(`invalid editorUid`);
4267
4476
  }
4268
- await createViewlet(viewletModuleId, actualEditorUid, tabId, bounds, newTab.uri || '');
4477
+ const title = await createViewlet(viewletModuleId, actualEditorUid, tabId, bounds, newTab.uri || '');
4269
4478
 
4270
4479
  // After viewlet is created, get the latest state and mark it as ready
4271
4480
  const {
4272
4481
  newState: latestState
4273
4482
  } = get(uid);
4274
- const readyState = handleViewletReady(latestState, actualEditorUid);
4483
+ const readyState = handleViewletReady(latestState, actualEditorUid, title);
4275
4484
  return readyState;
4276
4485
  };
4277
4486
 
@@ -4366,6 +4575,9 @@ const handleModifiedStatusChange = (state, uri, newStatus) => {
4366
4575
  }
4367
4576
  };
4368
4577
  };
4578
+ const handleModifiedStatusChangeWithContext = async (context, uri, newStatus) => {
4579
+ await context.updateState(state => handleModifiedStatusChange(state, uri, newStatus));
4580
+ };
4369
4581
 
4370
4582
  const handleResize = async (state, dimensions) => {
4371
4583
  const {
@@ -4598,47 +4810,6 @@ const handleUriChange = async (state, oldUri, newUri) => {
4598
4810
  };
4599
4811
  };
4600
4812
 
4601
- const handleWorkspaceChange = state => {
4602
- const {
4603
- layout
4604
- } = state;
4605
- return {
4606
- ...state,
4607
- layout: {
4608
- ...layout,
4609
- activeGroupId: undefined,
4610
- groups: []
4611
- }
4612
- };
4613
- };
4614
-
4615
- const hasActiveTextEditor = state => {
4616
- const activeTab = getActiveTab(state);
4617
- return activeTab?.tab.editorInput?.type === 'editor';
4618
- };
4619
-
4620
- const id = 7201;
4621
- const sendMessagePortToExtensionHostWorker = async port => {
4622
- await sendMessagePortToExtensionHostWorker$1(port, id);
4623
- };
4624
-
4625
- const createExtensionHostRpc = async () => {
4626
- try {
4627
- const rpc = await create$8({
4628
- commandMap: {},
4629
- send: sendMessagePortToExtensionHostWorker
4630
- });
4631
- return rpc;
4632
- } catch (error) {
4633
- throw new VError(error, `Failed to create extension host rpc`);
4634
- }
4635
- };
4636
-
4637
- const initialize = async () => {
4638
- const rpc = await createExtensionHostRpc();
4639
- set$3(rpc);
4640
- };
4641
-
4642
4813
  const toFileUri = path => {
4643
4814
  if (!path) {
4644
4815
  return '';
@@ -4748,15 +4919,22 @@ const tryRestoreLayout = savedState => {
4748
4919
 
4749
4920
  const createViewlets = async (layout, viewletModuleIds, bounds) => {
4750
4921
  const editorUids = {};
4922
+ const titles = {};
4751
4923
  for (const group of layout.groups) {
4752
4924
  const activeTab = group.tabs.find(tab => tab.id === group.activeTabId);
4753
4925
  if (activeTab && viewletModuleIds[activeTab.id]) {
4754
- const editorUid = activeTab.editorUid === -1 ? create$1() : activeTab.editorUid;
4926
+ const editorUid = activeTab.editorUid === -1 ? create$2() : activeTab.editorUid;
4755
4927
  editorUids[activeTab.id] = editorUid;
4756
- await createViewlet(viewletModuleIds[activeTab.id], editorUid, activeTab.id, bounds, activeTab.uri);
4928
+ const title = await createViewlet(viewletModuleIds[activeTab.id], editorUid, activeTab.id, bounds, activeTab.uri);
4929
+ if (title) {
4930
+ titles[activeTab.id] = title;
4931
+ }
4757
4932
  }
4758
4933
  }
4759
- return editorUids;
4934
+ return {
4935
+ editorUids,
4936
+ titles
4937
+ };
4760
4938
  };
4761
4939
 
4762
4940
  const getViewletModuleIds = async layout => {
@@ -4833,7 +5011,10 @@ const restoreAndCreateEditors = async (state, restoredLayout) => {
4833
5011
  const viewletModuleIds = await getViewletModuleIds(newState.layout);
4834
5012
 
4835
5013
  // Create viewlets and get editor UIDs
4836
- const editorUids = await createViewlets(newState.layout, viewletModuleIds, bounds);
5014
+ const {
5015
+ editorUids,
5016
+ titles
5017
+ } = await createViewlets(newState.layout, viewletModuleIds, bounds);
4837
5018
 
4838
5019
  // Update tabs with editor UIDs
4839
5020
  newState = updateTabs(newState, editorUids);
@@ -4844,7 +5025,7 @@ const restoreAndCreateEditors = async (state, restoredLayout) => {
4844
5025
  if (activeTab && viewletModuleIds[activeTab.id]) {
4845
5026
  const editorUid = editorUids[activeTab.id];
4846
5027
  newState = createViewletForTab(newState, activeTab.id);
4847
- newState = handleViewletReady(newState, editorUid);
5028
+ newState = handleViewletReady(newState, editorUid, titles[activeTab.id]);
4848
5029
  }
4849
5030
  }
4850
5031
  return newState;
@@ -4887,6 +5068,37 @@ const loadContent = async (state, savedState) => {
4887
5068
  };
4888
5069
  };
4889
5070
 
5071
+ const handleWorkspaceChange = async (state, _workspacePath, savedState) => {
5072
+ return loadContent(state, savedState);
5073
+ };
5074
+
5075
+ const hasActiveTextEditor = state => {
5076
+ const activeTab = getActiveTab(state);
5077
+ return activeTab?.tab.editorInput?.type === 'editor';
5078
+ };
5079
+
5080
+ const id = 7201;
5081
+ const sendMessagePortToExtensionHostWorker = async port => {
5082
+ await sendMessagePortToExtensionHostWorker$1(port, id);
5083
+ };
5084
+
5085
+ const createExtensionHostRpc = async () => {
5086
+ try {
5087
+ const rpc = await create$8({
5088
+ commandMap: {},
5089
+ send: sendMessagePortToExtensionHostWorker
5090
+ });
5091
+ return rpc;
5092
+ } catch (error) {
5093
+ throw new VError(error, `Failed to create extension host rpc`);
5094
+ }
5095
+ };
5096
+
5097
+ const initialize = async () => {
5098
+ const rpc = await createExtensionHostRpc();
5099
+ set$3(rpc);
5100
+ };
5101
+
4890
5102
  const hasTargetGroup = groupId => {
4891
5103
  return groupId !== undefined && groupId >= 0;
4892
5104
  };
@@ -4899,15 +5111,15 @@ const getMenuEntryArgs = groupId => {
4899
5111
  };
4900
5112
 
4901
5113
  const emptyObject = {};
4902
- const RE_PLACEHOLDER = /\{(PH\d+)\}/g;
4903
5114
  const i18nString = (key, placeholders = emptyObject) => {
4904
5115
  if (placeholders === emptyObject) {
4905
5116
  return key;
4906
5117
  }
4907
- const replacer = (match, rest) => {
4908
- return placeholders[rest];
4909
- };
4910
- return key.replaceAll(RE_PLACEHOLDER, replacer);
5118
+ let result = key;
5119
+ for (const [placeholder, replacement] of Object.entries(placeholders)) {
5120
+ result = result.split(`{${placeholder}}`).join(String(replacement));
5121
+ }
5122
+ return result;
4911
5123
  };
4912
5124
 
4913
5125
  const Close = 'Close';
@@ -5260,26 +5472,26 @@ const newWindow = async state => {
5260
5472
  return state;
5261
5473
  };
5262
5474
 
5263
- const openUris = async (state, uris) => {
5475
+ const openUrisWithContext = async (context, uris) => {
5264
5476
  if (uris.length === 0) {
5265
- return state;
5477
+ return;
5266
5478
  }
5479
+ await openUriWithContext(context, uris[0]);
5267
5480
  if (uris.length === 1) {
5268
- return openUri(state, uris[0]);
5481
+ return;
5269
5482
  }
5270
- let currentState = await openUri(state, uris[0]);
5483
+ let currentState = context.getState();
5271
5484
  const firstTab = findTabByUri(currentState, uris[0]);
5272
5485
  for (const uri of uris.slice(1)) {
5273
5486
  const existingTab = findTabByUri(currentState, uri);
5274
- if (existingTab) {
5275
- continue;
5487
+ if (!existingTab) {
5488
+ currentState = ensureActiveGroup(currentState, uri);
5276
5489
  }
5277
- currentState = ensureActiveGroup(currentState, uri);
5278
5490
  }
5279
- if (!firstTab) {
5280
- return currentState;
5491
+ if (firstTab) {
5492
+ currentState = switchTab(currentState, firstTab.groupId, firstTab.tab.id);
5281
5493
  }
5282
- return switchTab(currentState, firstTab.groupId, firstTab.tab.id);
5494
+ await context.updateState(() => currentState);
5283
5495
  };
5284
5496
 
5285
5497
  const refresh = state => {
@@ -6350,7 +6562,7 @@ const createEmptyGroup = () => {
6350
6562
  return {
6351
6563
  activeTabId: undefined,
6352
6564
  focused: false,
6353
- id: create$1(),
6565
+ id: create$2(),
6354
6566
  isEmpty: true,
6355
6567
  size: 100,
6356
6568
  tabs: []
@@ -6525,7 +6737,7 @@ const splitDown = (state, groupId) => {
6525
6737
 
6526
6738
  // If there are no groups, create an initial empty group first
6527
6739
  if (groups.length === 0) {
6528
- const initialGroupId = create$1();
6740
+ const initialGroupId = create$2();
6529
6741
  const initialGroup = {
6530
6742
  activeTabId: undefined,
6531
6743
  focused: true,
@@ -6560,7 +6772,7 @@ const splitLeft = (state, groupId) => {
6560
6772
  groups
6561
6773
  } = layout;
6562
6774
  if (groups.length === 0) {
6563
- const initialGroupId = create$1();
6775
+ const initialGroupId = create$2();
6564
6776
  const initialGroup = {
6565
6777
  activeTabId: undefined,
6566
6778
  focused: true,
@@ -6594,7 +6806,7 @@ const splitRight = (state, groupId) => {
6594
6806
 
6595
6807
  // If there are no groups, create an initial empty group first
6596
6808
  if (groups.length === 0) {
6597
- const initialGroupId = create$1();
6809
+ const initialGroupId = create$2();
6598
6810
  const initialGroup = {
6599
6811
  activeTabId: undefined,
6600
6812
  focused: true,
@@ -6625,7 +6837,7 @@ const splitUp = (state, groupId) => {
6625
6837
  groups
6626
6838
  } = layout;
6627
6839
  if (groups.length === 0) {
6628
- const initialGroupId = create$1();
6840
+ const initialGroupId = create$2();
6629
6841
  const initialGroup = {
6630
6842
  activeTabId: undefined,
6631
6843
  focused: true,
@@ -6652,99 +6864,99 @@ const splitUp = (state, groupId) => {
6652
6864
  };
6653
6865
 
6654
6866
  const commandMap = {
6655
- 'Main.closeActiveEditor': wrapCommand(closeActiveEditor),
6656
- 'Main.closeAll': wrapCommand(closeAll$1),
6657
- 'Main.closeAllEditors': wrapCommand(closeAll$1),
6658
- 'Main.closeFocusedTab': wrapCommand(closeFocusedTab),
6659
- 'Main.closeOthers': wrapCommand(closeOtherTabs),
6660
- 'Main.closeSaved': wrapCommand(closeSaved$1),
6661
- 'Main.closeTabsByUris': wrapCommand(closeTabsByUris),
6662
- 'Main.closeTabsRight': wrapCommand(closeTabsRight),
6663
- 'Main.copyPath': wrapCommand(copyPath$1),
6664
- 'Main.copyRelativePath': wrapCommand(copyRelativePath$1),
6665
- 'Main.focusNext': wrapCommand(focusNextTab),
6666
- 'Main.focusNextTab': wrapCommand(focusNextTab),
6667
- 'Main.focusPrevious': wrapCommand(focusPreviousTab),
6668
- 'Main.focusPreviousTab': wrapCommand(focusPreviousTab),
6669
- 'Main.handleModifiedStatusChange': wrapCommand(handleModifiedStatusChange),
6670
- 'Main.handleTabContextMenu': wrapCommand(handleTabContextMenu),
6867
+ 'Main.closeActiveEditor': wrapSerialCommand(closeActiveEditor),
6868
+ 'Main.closeAll': wrapSerialCommand(closeAll$1),
6869
+ 'Main.closeAllEditors': wrapSerialCommand(closeAll$1),
6870
+ 'Main.closeFocusedTab': wrapSerialCommand(closeFocusedTab),
6871
+ 'Main.closeOthers': wrapSerialCommand(closeOtherTabs),
6872
+ 'Main.closeSaved': wrapSerialCommand(closeSaved$1),
6873
+ 'Main.closeTabsByUris': wrapSerialCommand(closeTabsByUris),
6874
+ 'Main.closeTabsRight': wrapSerialCommand(closeTabsRight),
6875
+ 'Main.copyPath': wrapSerialCommand(copyPath$1),
6876
+ 'Main.copyRelativePath': wrapSerialCommand(copyRelativePath$1),
6877
+ 'Main.focusNext': wrapSerialCommand(focusNextTab),
6878
+ 'Main.focusNextTab': wrapSerialCommand(focusNextTab),
6879
+ 'Main.focusPrevious': wrapSerialCommand(focusPreviousTab),
6880
+ 'Main.focusPreviousTab': wrapSerialCommand(focusPreviousTab),
6881
+ 'Main.handleModifiedStatusChange': wrapAsyncCommand(handleModifiedStatusChangeWithContext),
6882
+ 'Main.handleTabContextMenu': wrapSerialCommand(handleTabContextMenu),
6671
6883
  'Main.hasActiveTextEditor': wrapGetter(hasActiveTextEditor),
6672
- 'Main.openInput': wrapCommand(openInput),
6673
- 'Main.openUri': wrapCommand(openUri),
6674
- 'Main.openUris': wrapCommand(openUris),
6675
- 'Main.restoreClosedTab': wrapCommand(restoreClosedTab),
6676
- 'Main.save': wrapCommand(save),
6884
+ 'Main.openInput': wrapSerialAsyncCommand(openInputWithContext),
6885
+ 'Main.openUri': wrapSerialAsyncCommand(openUriWithContext),
6886
+ 'Main.openUris': wrapSerialAsyncCommand(openUrisWithContext),
6887
+ 'Main.restoreClosedTab': wrapSerialCommand(restoreClosedTab),
6888
+ 'Main.save': wrapSerialCommand(save),
6677
6889
  'Main.saveState': wrapGetter(saveState),
6678
- 'Main.splitRight': wrapCommand(splitRight),
6679
- 'MainArea.closeActiveEditor': wrapCommand(closeActiveEditor),
6680
- 'MainArea.closeAll': wrapCommand(closeAll$1),
6681
- 'MainArea.closeAllEditors': wrapCommand(closeAll$1),
6682
- 'MainArea.closeEditorGroup': wrapCommand(closeEditorGroup$1),
6683
- 'MainArea.closeFocusedTab': wrapCommand(closeFocusedTab),
6684
- 'MainArea.closeOthers': wrapCommand(closeOtherTabs),
6685
- 'MainArea.closeSaved': wrapCommand(closeSaved$1),
6686
- 'MainArea.closeTabsByUris': wrapCommand(closeTabsByUris),
6687
- 'MainArea.closeTabsRight': wrapCommand(closeTabsRight),
6688
- 'MainArea.copyIntoNewWindow': wrapCommand(copyIntoNewWindow$1),
6689
- 'MainArea.copyPath': wrapCommand(copyPath$1),
6690
- 'MainArea.copyRelativePath': wrapCommand(copyRelativePath$1),
6691
- 'MainArea.create': create$2,
6890
+ 'Main.splitRight': wrapSerialCommand(splitRight),
6891
+ 'MainArea.closeActiveEditor': wrapSerialCommand(closeActiveEditor),
6892
+ 'MainArea.closeAll': wrapSerialCommand(closeAll$1),
6893
+ 'MainArea.closeAllEditors': wrapSerialCommand(closeAll$1),
6894
+ 'MainArea.closeEditorGroup': wrapSerialCommand(closeEditorGroup$1),
6895
+ 'MainArea.closeFocusedTab': wrapSerialCommand(closeFocusedTab),
6896
+ 'MainArea.closeOthers': wrapSerialCommand(closeOtherTabs),
6897
+ 'MainArea.closeSaved': wrapSerialCommand(closeSaved$1),
6898
+ 'MainArea.closeTabsByUris': wrapSerialCommand(closeTabsByUris),
6899
+ 'MainArea.closeTabsRight': wrapSerialCommand(closeTabsRight),
6900
+ 'MainArea.copyIntoNewWindow': wrapSerialCommand(copyIntoNewWindow$1),
6901
+ 'MainArea.copyPath': wrapSerialCommand(copyPath$1),
6902
+ 'MainArea.copyRelativePath': wrapSerialCommand(copyRelativePath$1),
6903
+ 'MainArea.create': create$1,
6692
6904
  'MainArea.diff2': diff2,
6693
- 'MainArea.flipEditorLayout': wrapCommand(flipLayout),
6694
- 'MainArea.focusNext': wrapCommand(focusNextTab),
6695
- 'MainArea.focusNextTab': wrapCommand(focusNextTab),
6696
- 'MainArea.focusPrevious': wrapCommand(focusPreviousTab),
6697
- 'MainArea.focusPreviousTab': wrapCommand(focusPreviousTab),
6905
+ 'MainArea.flipEditorLayout': wrapSerialCommand(flipLayout),
6906
+ 'MainArea.focusNext': wrapSerialCommand(focusNextTab),
6907
+ 'MainArea.focusNextTab': wrapSerialCommand(focusNextTab),
6908
+ 'MainArea.focusPrevious': wrapSerialCommand(focusPreviousTab),
6909
+ 'MainArea.focusPreviousTab': wrapSerialCommand(focusPreviousTab),
6698
6910
  'MainArea.getCommandIds': getCommandIds,
6699
6911
  'MainArea.getMenuEntries': wrapGetter(getMenuEntries),
6700
6912
  'MainArea.getMenuIds': getMenuIds,
6701
- 'MainArea.handleClick': wrapCommand(handleClick),
6702
- 'MainArea.handleClickAction': wrapCommand(handleClickAction),
6703
- 'MainArea.handleClickCloseTab': wrapCommand(handleClickCloseTab),
6704
- 'MainArea.handleClickTab': wrapCommand(handleClickTab),
6705
- 'MainArea.handleClickTogglePreview': wrapCommand(handleClickTogglePreview),
6706
- 'MainArea.handleContextMenu': wrapCommand(handleContextMenu),
6707
- 'MainArea.handleDoubleClick': wrapCommand(handleDoubleClick),
6708
- 'MainArea.handleHeaderDoubleClick': wrapCommand(handleHeaderDoubleClick),
6709
- 'MainArea.handleIconThemeChange': wrapCommand(handleIconThemeChange),
6710
- 'MainArea.handleModifiedStatusChange': wrapCommand(handleModifiedStatusChange),
6913
+ 'MainArea.handleClick': wrapSerialCommand(handleClick),
6914
+ 'MainArea.handleClickAction': wrapSerialCommand(handleClickAction),
6915
+ 'MainArea.handleClickCloseTab': wrapSerialCommand(handleClickCloseTab),
6916
+ 'MainArea.handleClickTab': wrapSerialCommand(handleClickTab),
6917
+ 'MainArea.handleClickTogglePreview': wrapSerialCommand(handleClickTogglePreview),
6918
+ 'MainArea.handleContextMenu': wrapSerialCommand(handleContextMenu),
6919
+ 'MainArea.handleDoubleClick': wrapSerialCommand(handleDoubleClick),
6920
+ 'MainArea.handleHeaderDoubleClick': wrapSerialCommand(handleHeaderDoubleClick),
6921
+ 'MainArea.handleIconThemeChange': wrapSerialCommand(handleIconThemeChange),
6922
+ 'MainArea.handleModifiedStatusChange': wrapAsyncCommand(handleModifiedStatusChangeWithContext),
6711
6923
  'MainArea.handleResize': wrapGetter(handleResize),
6712
6924
  // TODO would need to have a function that returns newstate as well as commands
6713
- 'MainArea.handleSashPointerDown': wrapCommand(handleSashPointerDown),
6714
- 'MainArea.handleSashPointerMove': wrapCommand(handleSashPointerMove),
6715
- 'MainArea.handleSashPointerUp': wrapCommand(handleSashPointerUp),
6716
- 'MainArea.handleTabContextMenu': wrapCommand(handleTabContextMenu),
6717
- 'MainArea.handleUriChange': wrapCommand(handleUriChange),
6718
- 'MainArea.handleWorkspaceChange': wrapCommand(handleWorkspaceChange),
6925
+ 'MainArea.handleSashPointerDown': wrapSerialCommand(handleSashPointerDown),
6926
+ 'MainArea.handleSashPointerMove': wrapSerialCommand(handleSashPointerMove),
6927
+ 'MainArea.handleSashPointerUp': wrapSerialCommand(handleSashPointerUp),
6928
+ 'MainArea.handleTabContextMenu': wrapSerialCommand(handleTabContextMenu),
6929
+ 'MainArea.handleUriChange': wrapSerialCommand(handleUriChange),
6930
+ 'MainArea.handleWorkspaceChange': wrapSerialCommand(handleWorkspaceChange),
6719
6931
  'MainArea.hasActiveTextEditor': wrapGetter(hasActiveTextEditor),
6720
6932
  'MainArea.initialize': initialize,
6721
- 'MainArea.loadContent': wrapCommand(loadContent),
6722
- 'MainArea.moveIntoNewWindow': wrapCommand(moveIntoNewWindow),
6723
- 'MainArea.newFile': wrapCommand(newFile),
6724
- 'MainArea.newWindow': wrapCommand(newWindow),
6725
- 'MainArea.openInput': wrapCommand(openInput),
6726
- 'MainArea.openUri': wrapCommand(openUri),
6727
- 'MainArea.openUris': wrapCommand(openUris),
6728
- 'MainArea.refresh': wrapCommand(refresh),
6933
+ 'MainArea.loadContent': wrapSerialCommand(loadContent),
6934
+ 'MainArea.moveIntoNewWindow': wrapSerialCommand(moveIntoNewWindow),
6935
+ 'MainArea.newFile': wrapSerialCommand(newFile),
6936
+ 'MainArea.newWindow': wrapSerialCommand(newWindow),
6937
+ 'MainArea.openInput': wrapSerialAsyncCommand(openInputWithContext),
6938
+ 'MainArea.openUri': wrapSerialAsyncCommand(openUriWithContext),
6939
+ 'MainArea.openUris': wrapSerialAsyncCommand(openUrisWithContext),
6940
+ 'MainArea.refresh': wrapSerialCommand(refresh),
6729
6941
  'MainArea.render2': render2,
6730
6942
  'MainArea.renderEventListeners': renderEventListeners,
6731
6943
  'MainArea.resize': wrapGetter(handleResize),
6732
- 'MainArea.restoreClosedTab': wrapCommand(restoreClosedTab),
6733
- 'MainArea.save': wrapCommand(save),
6944
+ 'MainArea.restoreClosedTab': wrapSerialCommand(restoreClosedTab),
6945
+ 'MainArea.save': wrapSerialCommand(save),
6734
6946
  'MainArea.saveState': wrapGetter(saveState),
6735
- 'MainArea.selectTab': wrapCommand(selectTab),
6736
- 'MainArea.setEditorLayoutGrid': wrapCommand(setEditorLayoutGrid),
6737
- 'MainArea.setEditorLayoutSingle': wrapCommand(setEditorLayoutSingle),
6738
- 'MainArea.setEditorLayoutThreeColumns': wrapCommand(setEditorLayoutThreeColumns),
6739
- 'MainArea.setEditorLayoutThreeRows': wrapCommand(setEditorLayoutThreeRows),
6740
- 'MainArea.setEditorLayoutTwoColumns': wrapCommand(setEditorLayoutTwoColumns),
6741
- 'MainArea.setEditorLayoutTwoColumnsBottom': wrapCommand(setEditorLayoutTwoColumnsBottom),
6742
- 'MainArea.setEditorLayoutTwoRows': wrapCommand(setEditorLayoutTwoRows),
6743
- 'MainArea.setEditorLayoutTwoRowsRight': wrapCommand(setEditorLayoutTwoRowsRight),
6744
- 'MainArea.splitDown': wrapCommand(splitDown),
6745
- 'MainArea.splitLeft': wrapCommand(splitLeft),
6746
- 'MainArea.splitRight': wrapCommand(splitRight),
6747
- 'MainArea.splitUp': wrapCommand(splitUp),
6947
+ 'MainArea.selectTab': wrapSerialCommand(selectTab),
6948
+ 'MainArea.setEditorLayoutGrid': wrapSerialCommand(setEditorLayoutGrid),
6949
+ 'MainArea.setEditorLayoutSingle': wrapSerialCommand(setEditorLayoutSingle),
6950
+ 'MainArea.setEditorLayoutThreeColumns': wrapSerialCommand(setEditorLayoutThreeColumns),
6951
+ 'MainArea.setEditorLayoutThreeRows': wrapSerialCommand(setEditorLayoutThreeRows),
6952
+ 'MainArea.setEditorLayoutTwoColumns': wrapSerialCommand(setEditorLayoutTwoColumns),
6953
+ 'MainArea.setEditorLayoutTwoColumnsBottom': wrapSerialCommand(setEditorLayoutTwoColumnsBottom),
6954
+ 'MainArea.setEditorLayoutTwoRows': wrapSerialCommand(setEditorLayoutTwoRows),
6955
+ 'MainArea.setEditorLayoutTwoRowsRight': wrapSerialCommand(setEditorLayoutTwoRowsRight),
6956
+ 'MainArea.splitDown': wrapSerialCommand(splitDown),
6957
+ 'MainArea.splitLeft': wrapSerialCommand(splitLeft),
6958
+ 'MainArea.splitRight': wrapSerialCommand(splitRight),
6959
+ 'MainArea.splitUp': wrapSerialCommand(splitUp),
6748
6960
  'MainArea.terminate': terminate
6749
6961
  };
6750
6962