@lvce-editor/main-area-worker 3.1.0 → 5.0.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.
- package/dist/mainAreaWorkerMain.js +460 -80
- package/package.json +1 -1
|
@@ -102,14 +102,15 @@ const {
|
|
|
102
102
|
get: get$2,
|
|
103
103
|
getCommandIds,
|
|
104
104
|
registerCommands,
|
|
105
|
-
set: set$
|
|
105
|
+
set: set$4,
|
|
106
106
|
wrapCommand,
|
|
107
107
|
wrapGetter
|
|
108
108
|
} = create$7();
|
|
109
109
|
|
|
110
|
-
const create$6 = (uid, uri, x, y, width, height, platform, assetDir) => {
|
|
110
|
+
const create$6 = (uid, uri, x, y, width, height, platform, assetDir, tabHeight = 35) => {
|
|
111
111
|
const state = {
|
|
112
112
|
assetDir,
|
|
113
|
+
fileIconCache: {},
|
|
113
114
|
height,
|
|
114
115
|
layout: {
|
|
115
116
|
activeGroupId: undefined,
|
|
@@ -117,12 +118,13 @@ const create$6 = (uid, uri, x, y, width, height, platform, assetDir) => {
|
|
|
117
118
|
groups: []
|
|
118
119
|
},
|
|
119
120
|
platform,
|
|
121
|
+
tabHeight,
|
|
120
122
|
uid,
|
|
121
123
|
width,
|
|
122
124
|
x,
|
|
123
125
|
y
|
|
124
126
|
};
|
|
125
|
-
set$
|
|
127
|
+
set$4(uid, state, state);
|
|
126
128
|
};
|
|
127
129
|
|
|
128
130
|
const isEqual = (oldState, newState) => {
|
|
@@ -154,14 +156,7 @@ const diff2 = uid => {
|
|
|
154
156
|
return result;
|
|
155
157
|
};
|
|
156
158
|
|
|
157
|
-
const Button$1 =
|
|
158
|
-
const Div = 4;
|
|
159
|
-
const Span = 8;
|
|
160
|
-
const Text = 12;
|
|
161
|
-
const Img = 17;
|
|
162
|
-
const Pre = 51;
|
|
163
|
-
|
|
164
|
-
const Button = 'event.button';
|
|
159
|
+
const Button$1 = 'event.button';
|
|
165
160
|
const ClientX = 'event.clientX';
|
|
166
161
|
const ClientY = 'event.clientY';
|
|
167
162
|
const TargetName = 'event.target.name';
|
|
@@ -171,9 +166,6 @@ const Tab = 13;
|
|
|
171
166
|
const Separator = 1;
|
|
172
167
|
const None = 0;
|
|
173
168
|
|
|
174
|
-
const ExtensionHostWorker = 44;
|
|
175
|
-
const RendererWorker = 1;
|
|
176
|
-
|
|
177
169
|
const SetDom2 = 'Viewlet.setDom2';
|
|
178
170
|
|
|
179
171
|
const getMenuIds = () => {
|
|
@@ -187,6 +179,10 @@ const handleClick = async (state, name) => {
|
|
|
187
179
|
return state;
|
|
188
180
|
};
|
|
189
181
|
|
|
182
|
+
const ExtensionHostWorker = 44;
|
|
183
|
+
const IconThemeWorker = 7009;
|
|
184
|
+
const RendererWorker = 1;
|
|
185
|
+
|
|
190
186
|
const normalizeLine = line => {
|
|
191
187
|
if (line.startsWith('Error: ')) {
|
|
192
188
|
return line.slice('Error: '.length);
|
|
@@ -1152,6 +1148,53 @@ const listen$1 = async (module, options) => {
|
|
|
1152
1148
|
const ipc = module.wrap(rawIpc);
|
|
1153
1149
|
return ipc;
|
|
1154
1150
|
};
|
|
1151
|
+
|
|
1152
|
+
/* eslint-disable @typescript-eslint/no-misused-promises */
|
|
1153
|
+
|
|
1154
|
+
const createSharedLazyRpc = factory => {
|
|
1155
|
+
let rpcPromise;
|
|
1156
|
+
const getOrCreate = () => {
|
|
1157
|
+
if (!rpcPromise) {
|
|
1158
|
+
rpcPromise = factory();
|
|
1159
|
+
}
|
|
1160
|
+
return rpcPromise;
|
|
1161
|
+
};
|
|
1162
|
+
return {
|
|
1163
|
+
async dispose() {
|
|
1164
|
+
const rpc = await getOrCreate();
|
|
1165
|
+
await rpc.dispose();
|
|
1166
|
+
},
|
|
1167
|
+
async invoke(method, ...params) {
|
|
1168
|
+
const rpc = await getOrCreate();
|
|
1169
|
+
return rpc.invoke(method, ...params);
|
|
1170
|
+
},
|
|
1171
|
+
async invokeAndTransfer(method, ...params) {
|
|
1172
|
+
const rpc = await getOrCreate();
|
|
1173
|
+
return rpc.invokeAndTransfer(method, ...params);
|
|
1174
|
+
},
|
|
1175
|
+
async send(method, ...params) {
|
|
1176
|
+
const rpc = await getOrCreate();
|
|
1177
|
+
rpc.send(method, ...params);
|
|
1178
|
+
}
|
|
1179
|
+
};
|
|
1180
|
+
};
|
|
1181
|
+
const create$j = async ({
|
|
1182
|
+
commandMap,
|
|
1183
|
+
isMessagePortOpen,
|
|
1184
|
+
send
|
|
1185
|
+
}) => {
|
|
1186
|
+
return createSharedLazyRpc(() => {
|
|
1187
|
+
return create$3({
|
|
1188
|
+
commandMap,
|
|
1189
|
+
isMessagePortOpen,
|
|
1190
|
+
send
|
|
1191
|
+
});
|
|
1192
|
+
});
|
|
1193
|
+
};
|
|
1194
|
+
const LazyTransferMessagePortRpcParent = {
|
|
1195
|
+
__proto__: null,
|
|
1196
|
+
create: create$j
|
|
1197
|
+
};
|
|
1155
1198
|
const create$5 = async ({
|
|
1156
1199
|
commandMap,
|
|
1157
1200
|
isMessagePortOpen = true,
|
|
@@ -1224,7 +1267,7 @@ const createMockRpc = ({
|
|
|
1224
1267
|
};
|
|
1225
1268
|
|
|
1226
1269
|
const rpcs = Object.create(null);
|
|
1227
|
-
const set$
|
|
1270
|
+
const set$3 = (id, rpc) => {
|
|
1228
1271
|
rpcs[id] = rpc;
|
|
1229
1272
|
};
|
|
1230
1273
|
const get = id => {
|
|
@@ -1257,7 +1300,7 @@ const create$1 = rpcId => {
|
|
|
1257
1300
|
const mockRpc = createMockRpc({
|
|
1258
1301
|
commandMap
|
|
1259
1302
|
});
|
|
1260
|
-
set$
|
|
1303
|
+
set$3(rpcId, mockRpc);
|
|
1261
1304
|
// @ts-ignore
|
|
1262
1305
|
mockRpc[Symbol.dispose] = () => {
|
|
1263
1306
|
remove(rpcId);
|
|
@@ -1266,15 +1309,24 @@ const create$1 = rpcId => {
|
|
|
1266
1309
|
return mockRpc;
|
|
1267
1310
|
},
|
|
1268
1311
|
set(rpc) {
|
|
1269
|
-
set$
|
|
1312
|
+
set$3(rpcId, rpc);
|
|
1270
1313
|
}
|
|
1271
1314
|
};
|
|
1272
1315
|
};
|
|
1273
1316
|
|
|
1274
1317
|
const {
|
|
1275
|
-
set: set$
|
|
1318
|
+
set: set$2
|
|
1276
1319
|
} = create$1(ExtensionHostWorker);
|
|
1277
1320
|
|
|
1321
|
+
const {
|
|
1322
|
+
invoke: invoke$1,
|
|
1323
|
+
set: set$1
|
|
1324
|
+
} = create$1(IconThemeWorker);
|
|
1325
|
+
const getIcons = async iconRequests => {
|
|
1326
|
+
// @ts-ignore
|
|
1327
|
+
return invoke$1('IconTheme.getIcons', iconRequests);
|
|
1328
|
+
};
|
|
1329
|
+
|
|
1278
1330
|
const {
|
|
1279
1331
|
invoke,
|
|
1280
1332
|
invokeAndTransfer,
|
|
@@ -1288,6 +1340,11 @@ const showContextMenu2 = async (uid, menuId, x, y, args) => {
|
|
|
1288
1340
|
// @ts-ignore
|
|
1289
1341
|
await invoke('ContextMenu.show2', uid, menuId, x, y, args);
|
|
1290
1342
|
};
|
|
1343
|
+
const sendMessagePortToIconThemeWorker = async (port, rpcId) => {
|
|
1344
|
+
const command = 'IconTheme.handleMessagePort';
|
|
1345
|
+
// @ts-ignore
|
|
1346
|
+
await invokeAndTransfer('SendMessagePortToExtensionHostWorker.sendMessagePortToIconThemeWorker', port, command, rpcId);
|
|
1347
|
+
};
|
|
1291
1348
|
const sendMessagePortToExtensionHostWorker$1 = async (port, rpcId = 0) => {
|
|
1292
1349
|
const command = 'HandleMessagePort.handleMessagePort2';
|
|
1293
1350
|
await invokeAndTransfer('SendMessagePortToExtensionHostWorker.sendMessagePortToExtensionHostWorker', port, command, rpcId);
|
|
@@ -1498,7 +1555,7 @@ const handleCreate = async command => {
|
|
|
1498
1555
|
oldState
|
|
1499
1556
|
} = get$2(command.uid);
|
|
1500
1557
|
const readyState = handleViewletReady(state, command.editorUid);
|
|
1501
|
-
set$
|
|
1558
|
+
set$4(command.uid, oldState, readyState);
|
|
1502
1559
|
return readyState;
|
|
1503
1560
|
};
|
|
1504
1561
|
|
|
@@ -1624,6 +1681,30 @@ const handleClickCloseTab = (state, rawGroupIndex, rawIndex) => {
|
|
|
1624
1681
|
return closeTab(state, groupId, tabId);
|
|
1625
1682
|
};
|
|
1626
1683
|
|
|
1684
|
+
const createViewlet = async (viewletModuleId, editorUid, tabId, bounds, uri) => {
|
|
1685
|
+
// @ts-ignore
|
|
1686
|
+
await invoke('Layout.createViewlet', viewletModuleId, editorUid, tabId, bounds, uri);
|
|
1687
|
+
};
|
|
1688
|
+
|
|
1689
|
+
const findTabById = (state, tabId) => {
|
|
1690
|
+
const {
|
|
1691
|
+
layout
|
|
1692
|
+
} = state;
|
|
1693
|
+
const {
|
|
1694
|
+
groups
|
|
1695
|
+
} = layout;
|
|
1696
|
+
for (const group of groups) {
|
|
1697
|
+
const tab = group.tabs.find(t => t.id === tabId);
|
|
1698
|
+
if (tab) {
|
|
1699
|
+
return {
|
|
1700
|
+
groupId: group.id,
|
|
1701
|
+
tab
|
|
1702
|
+
};
|
|
1703
|
+
}
|
|
1704
|
+
}
|
|
1705
|
+
return undefined;
|
|
1706
|
+
};
|
|
1707
|
+
|
|
1627
1708
|
// Counter for request IDs to handle race conditions
|
|
1628
1709
|
let requestIdCounter = 0;
|
|
1629
1710
|
const getNextRequestId = () => {
|
|
@@ -1635,7 +1716,7 @@ const startContentLoading = async (oldState, state, tabId, path, requestId) => {
|
|
|
1635
1716
|
const getLatestState = () => {
|
|
1636
1717
|
return get$2(state.uid).newState;
|
|
1637
1718
|
};
|
|
1638
|
-
set$
|
|
1719
|
+
set$4(state.uid, oldState, state);
|
|
1639
1720
|
const newState = await loadTabContentAsync(tabId, path, requestId, getLatestState);
|
|
1640
1721
|
return newState;
|
|
1641
1722
|
} catch {
|
|
@@ -1765,12 +1846,43 @@ const selectTab = async (state, groupIndex, index) => {
|
|
|
1765
1846
|
};
|
|
1766
1847
|
const createdState = createViewletForTab(newState, tabId, viewletModuleId, bounds);
|
|
1767
1848
|
newState = createdState;
|
|
1849
|
+
|
|
1850
|
+
// Store updated state before creating viewlet
|
|
1851
|
+
set$4(uid, state, newState);
|
|
1852
|
+
|
|
1853
|
+
// Execute viewlet commands if any
|
|
1854
|
+
if (switchCommands.length > 0) {
|
|
1855
|
+
await executeViewletCommands(switchCommands);
|
|
1856
|
+
}
|
|
1857
|
+
|
|
1858
|
+
// Get the tab to extract editorUid for viewlet creation
|
|
1859
|
+
const tabWithViewlet = findTabById(newState, tabId);
|
|
1860
|
+
if (tabWithViewlet) {
|
|
1861
|
+
const {
|
|
1862
|
+
editorUid
|
|
1863
|
+
} = tabWithViewlet.tab;
|
|
1864
|
+
if (editorUid !== -1 && newTab.uri) {
|
|
1865
|
+
// Create the actual viewlet instance
|
|
1866
|
+
await createViewlet(viewletModuleId, editorUid, tabId, bounds, newTab.uri);
|
|
1867
|
+
|
|
1868
|
+
// Mark viewlet as ready
|
|
1869
|
+
newState = handleViewletReady(newState, editorUid);
|
|
1870
|
+
set$4(uid, state, newState);
|
|
1871
|
+
}
|
|
1872
|
+
}
|
|
1873
|
+
|
|
1874
|
+
// Start loading content in the background if needed
|
|
1875
|
+
if (needsLoading && tab.uri) {
|
|
1876
|
+
const latestState = await startContentLoading(state, newState, tabId, tab.uri, requestId);
|
|
1877
|
+
return latestState;
|
|
1878
|
+
}
|
|
1879
|
+
return newState;
|
|
1768
1880
|
}
|
|
1769
1881
|
} catch {
|
|
1770
1882
|
// Viewlet creation is optional - silently ignore if RendererWorker isn't available
|
|
1771
1883
|
}
|
|
1772
1884
|
}
|
|
1773
|
-
set$
|
|
1885
|
+
set$4(uid, state, newState);
|
|
1774
1886
|
|
|
1775
1887
|
// Execute viewlet commands if any
|
|
1776
1888
|
if (switchCommands.length > 0) {
|
|
@@ -1829,7 +1941,7 @@ const createExtensionHostRpc = async () => {
|
|
|
1829
1941
|
|
|
1830
1942
|
const initialize = async () => {
|
|
1831
1943
|
const rpc = await createExtensionHostRpc();
|
|
1832
|
-
set$
|
|
1944
|
+
set$2(rpc);
|
|
1833
1945
|
};
|
|
1834
1946
|
|
|
1835
1947
|
const getMaxIdFromLayout = layout => {
|
|
@@ -1891,15 +2003,254 @@ const tryRestoreLayout = savedState => {
|
|
|
1891
2003
|
return layout;
|
|
1892
2004
|
};
|
|
1893
2005
|
|
|
2006
|
+
const getIconsCached = (dirents, fileIconCache) => {
|
|
2007
|
+
return dirents.map(dirent => fileIconCache[dirent]);
|
|
2008
|
+
};
|
|
2009
|
+
|
|
2010
|
+
const getBasename$1 = uri => {
|
|
2011
|
+
const lastSlashIndex = uri.lastIndexOf('/');
|
|
2012
|
+
if (lastSlashIndex === -1) {
|
|
2013
|
+
return uri;
|
|
2014
|
+
}
|
|
2015
|
+
return uri.slice(lastSlashIndex + 1);
|
|
2016
|
+
};
|
|
2017
|
+
const getMissingTabs = (tabs, fileIconCache) => {
|
|
2018
|
+
const missingTabs = [];
|
|
2019
|
+
for (const tab of tabs) {
|
|
2020
|
+
if (tab.uri && !(tab.uri in fileIconCache)) {
|
|
2021
|
+
missingTabs.push(tab);
|
|
2022
|
+
}
|
|
2023
|
+
}
|
|
2024
|
+
return missingTabs;
|
|
2025
|
+
};
|
|
2026
|
+
const tabToIconRequest = tab => {
|
|
2027
|
+
const uri = tab.uri || '';
|
|
2028
|
+
return {
|
|
2029
|
+
name: getBasename$1(uri),
|
|
2030
|
+
path: uri,
|
|
2031
|
+
type: 0 // file type
|
|
2032
|
+
};
|
|
2033
|
+
};
|
|
2034
|
+
const getMissingIconRequestsForTabs = (tabs, fileIconCache) => {
|
|
2035
|
+
const missingRequests = getMissingTabs(tabs, fileIconCache);
|
|
2036
|
+
const iconRequests = missingRequests.map(tabToIconRequest);
|
|
2037
|
+
return iconRequests;
|
|
2038
|
+
};
|
|
2039
|
+
|
|
2040
|
+
const Directory = 3;
|
|
2041
|
+
const DirectoryExpanded = 4;
|
|
2042
|
+
|
|
2043
|
+
const getSimpleIconRequestType = direntType => {
|
|
2044
|
+
if (direntType === Directory || direntType === DirectoryExpanded) {
|
|
2045
|
+
return 2;
|
|
2046
|
+
}
|
|
2047
|
+
return 1;
|
|
2048
|
+
};
|
|
2049
|
+
|
|
2050
|
+
const toSimpleIconRequest = request => {
|
|
2051
|
+
return {
|
|
2052
|
+
name: request.name,
|
|
2053
|
+
type: getSimpleIconRequestType(request.type)
|
|
2054
|
+
};
|
|
2055
|
+
};
|
|
2056
|
+
|
|
2057
|
+
const requestFileIcons = async requests => {
|
|
2058
|
+
if (requests.length === 0) {
|
|
2059
|
+
return [];
|
|
2060
|
+
}
|
|
2061
|
+
const simpleRequests = requests.map(toSimpleIconRequest);
|
|
2062
|
+
const icons = await getIcons(simpleRequests);
|
|
2063
|
+
return icons;
|
|
2064
|
+
};
|
|
2065
|
+
|
|
2066
|
+
const updateIconCache = (iconCache, missingRequests, newIcons) => {
|
|
2067
|
+
if (missingRequests.length === 0) {
|
|
2068
|
+
return iconCache;
|
|
2069
|
+
}
|
|
2070
|
+
const newFileIconCache = {
|
|
2071
|
+
...iconCache
|
|
2072
|
+
};
|
|
2073
|
+
for (let i = 0; i < missingRequests.length; i++) {
|
|
2074
|
+
const request = missingRequests[i];
|
|
2075
|
+
const icon = newIcons[i];
|
|
2076
|
+
newFileIconCache[request.path] = icon;
|
|
2077
|
+
}
|
|
2078
|
+
return newFileIconCache;
|
|
2079
|
+
};
|
|
2080
|
+
|
|
2081
|
+
const getFileIconsForTabs = async (tabs, fileIconCache) => {
|
|
2082
|
+
const missingRequests = getMissingIconRequestsForTabs(tabs, fileIconCache);
|
|
2083
|
+
const newIcons = await requestFileIcons(missingRequests);
|
|
2084
|
+
const newFileIconCache = updateIconCache(fileIconCache, missingRequests, newIcons);
|
|
2085
|
+
const tabUris = tabs.map(tab => tab.uri || '');
|
|
2086
|
+
const icons = getIconsCached(tabUris, newFileIconCache);
|
|
2087
|
+
return {
|
|
2088
|
+
icons,
|
|
2089
|
+
newFileIconCache
|
|
2090
|
+
};
|
|
2091
|
+
};
|
|
2092
|
+
|
|
2093
|
+
const getAllTabs = layout => {
|
|
2094
|
+
const allTabs = [];
|
|
2095
|
+
for (const group of layout.groups) {
|
|
2096
|
+
allTabs.push(...group.tabs);
|
|
2097
|
+
}
|
|
2098
|
+
return allTabs;
|
|
2099
|
+
};
|
|
2100
|
+
|
|
2101
|
+
const loadFileIcons = async state => {
|
|
2102
|
+
try {
|
|
2103
|
+
const allTabs = getAllTabs(state.layout);
|
|
2104
|
+
const {
|
|
2105
|
+
newFileIconCache
|
|
2106
|
+
} = await getFileIconsForTabs(allTabs, state.fileIconCache);
|
|
2107
|
+
|
|
2108
|
+
// Update tabs with their icons
|
|
2109
|
+
const updatedLayout = {
|
|
2110
|
+
...state.layout,
|
|
2111
|
+
groups: state.layout.groups.map(group => ({
|
|
2112
|
+
...group,
|
|
2113
|
+
tabs: group.tabs.map(tab => ({
|
|
2114
|
+
...tab,
|
|
2115
|
+
icon: newFileIconCache[tab.uri || '']
|
|
2116
|
+
}))
|
|
2117
|
+
}))
|
|
2118
|
+
};
|
|
2119
|
+
return {
|
|
2120
|
+
fileIconCache: newFileIconCache,
|
|
2121
|
+
updatedLayout
|
|
2122
|
+
};
|
|
2123
|
+
} catch {
|
|
2124
|
+
// If icon request fails, continue without icons
|
|
2125
|
+
return {
|
|
2126
|
+
fileIconCache: state.fileIconCache,
|
|
2127
|
+
updatedLayout: state.layout
|
|
2128
|
+
};
|
|
2129
|
+
}
|
|
2130
|
+
};
|
|
2131
|
+
|
|
2132
|
+
const getViewletModuleId = async uri => {
|
|
2133
|
+
// Query RendererWorker for viewlet module ID (optional, may fail in tests)
|
|
2134
|
+
let viewletModuleId;
|
|
2135
|
+
try {
|
|
2136
|
+
// @ts-ignore
|
|
2137
|
+
viewletModuleId = await invoke('Layout.getModuleId', uri);
|
|
2138
|
+
} catch {
|
|
2139
|
+
// Viewlet creation is optional - silently ignore if RendererWorker isn't available
|
|
2140
|
+
}
|
|
2141
|
+
return viewletModuleId;
|
|
2142
|
+
};
|
|
2143
|
+
|
|
2144
|
+
const TAB_HEIGHT = 35;
|
|
2145
|
+
|
|
2146
|
+
// Get viewlet module IDs for active tabs in each group
|
|
2147
|
+
const getViewletModuleIds = async layout => {
|
|
2148
|
+
const viewletModuleIds = {};
|
|
2149
|
+
for (const group of layout.groups) {
|
|
2150
|
+
const activeTab = group.tabs.find(tab => tab.id === group.activeTabId);
|
|
2151
|
+
if (activeTab && activeTab.uri) {
|
|
2152
|
+
const viewletModuleId = await getViewletModuleId(activeTab.uri);
|
|
2153
|
+
if (viewletModuleId) {
|
|
2154
|
+
viewletModuleIds[activeTab.id] = viewletModuleId;
|
|
2155
|
+
}
|
|
2156
|
+
}
|
|
2157
|
+
}
|
|
2158
|
+
return viewletModuleIds;
|
|
2159
|
+
};
|
|
2160
|
+
|
|
2161
|
+
// Create viewlets for the active tabs
|
|
2162
|
+
const createViewlets = async (layout, viewletModuleIds, bounds) => {
|
|
2163
|
+
const editorUids = {};
|
|
2164
|
+
for (const group of layout.groups) {
|
|
2165
|
+
const activeTab = group.tabs.find(tab => tab.id === group.activeTabId);
|
|
2166
|
+
if (activeTab && viewletModuleIds[activeTab.id]) {
|
|
2167
|
+
const editorUid = activeTab.editorUid === -1 ? create() : activeTab.editorUid;
|
|
2168
|
+
editorUids[activeTab.id] = editorUid;
|
|
2169
|
+
await createViewlet(viewletModuleIds[activeTab.id], editorUid, activeTab.id, bounds, activeTab.uri);
|
|
2170
|
+
}
|
|
2171
|
+
}
|
|
2172
|
+
return editorUids;
|
|
2173
|
+
};
|
|
2174
|
+
|
|
2175
|
+
// Update tabs with editor UIDs
|
|
2176
|
+
const updateTabs = (state, editorUids) => {
|
|
2177
|
+
const updatedGroups = state.layout.groups.map(group => {
|
|
2178
|
+
return {
|
|
2179
|
+
...group,
|
|
2180
|
+
tabs: group.tabs.map(tab => {
|
|
2181
|
+
if (editorUids[tab.id]) {
|
|
2182
|
+
return {
|
|
2183
|
+
...tab,
|
|
2184
|
+
editorUid: editorUids[tab.id]
|
|
2185
|
+
};
|
|
2186
|
+
}
|
|
2187
|
+
return tab;
|
|
2188
|
+
})
|
|
2189
|
+
};
|
|
2190
|
+
});
|
|
2191
|
+
return {
|
|
2192
|
+
...state,
|
|
2193
|
+
layout: {
|
|
2194
|
+
...state.layout,
|
|
2195
|
+
groups: updatedGroups
|
|
2196
|
+
}
|
|
2197
|
+
};
|
|
2198
|
+
};
|
|
2199
|
+
const restoreAndCreateEditors = async (state, restoredLayout) => {
|
|
2200
|
+
let newState = {
|
|
2201
|
+
...state,
|
|
2202
|
+
layout: restoredLayout
|
|
2203
|
+
};
|
|
2204
|
+
const bounds = {
|
|
2205
|
+
height: newState.height - TAB_HEIGHT,
|
|
2206
|
+
width: newState.width,
|
|
2207
|
+
x: newState.x,
|
|
2208
|
+
y: newState.y + TAB_HEIGHT
|
|
2209
|
+
};
|
|
2210
|
+
|
|
2211
|
+
// Get viewlet module IDs for all active tabs
|
|
2212
|
+
const viewletModuleIds = await getViewletModuleIds(newState.layout);
|
|
2213
|
+
|
|
2214
|
+
// Create viewlets and get editor UIDs
|
|
2215
|
+
const editorUids = await createViewlets(newState.layout, viewletModuleIds, bounds);
|
|
2216
|
+
|
|
2217
|
+
// Update tabs with editor UIDs
|
|
2218
|
+
newState = updateTabs(newState, editorUids);
|
|
2219
|
+
|
|
2220
|
+
// Create viewlets in the lifecycle and mark them as ready
|
|
2221
|
+
for (const group of newState.layout.groups) {
|
|
2222
|
+
const activeTab = group.tabs.find(tab => tab.id === group.activeTabId);
|
|
2223
|
+
if (activeTab && viewletModuleIds[activeTab.id]) {
|
|
2224
|
+
const editorUid = editorUids[activeTab.id];
|
|
2225
|
+
newState = createViewletForTab(newState, activeTab.id);
|
|
2226
|
+
newState = handleViewletReady(newState, editorUid);
|
|
2227
|
+
}
|
|
2228
|
+
}
|
|
2229
|
+
return newState;
|
|
2230
|
+
};
|
|
2231
|
+
|
|
1894
2232
|
const loadContent = async (state, savedState) => {
|
|
1895
2233
|
const restoredLayout = tryRestoreLayout(savedState);
|
|
1896
2234
|
if (restoredLayout) {
|
|
1897
2235
|
const maxId = getMaxIdFromLayout(restoredLayout);
|
|
1898
2236
|
setMinId(maxId);
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
2237
|
+
|
|
2238
|
+
// Restore and create editors
|
|
2239
|
+
const editorState = await restoreAndCreateEditors(state, restoredLayout);
|
|
2240
|
+
|
|
2241
|
+
// Load file icons with the updated editor state
|
|
2242
|
+
const {
|
|
2243
|
+
fileIconCache,
|
|
2244
|
+
updatedLayout
|
|
2245
|
+
} = await loadFileIcons(editorState);
|
|
2246
|
+
|
|
2247
|
+
// Merge the results
|
|
2248
|
+
const finalState = {
|
|
2249
|
+
...editorState,
|
|
2250
|
+
fileIconCache,
|
|
2251
|
+
layout: updatedLayout
|
|
1902
2252
|
};
|
|
2253
|
+
return finalState;
|
|
1903
2254
|
}
|
|
1904
2255
|
return {
|
|
1905
2256
|
...state,
|
|
@@ -2019,11 +2370,6 @@ const getMenuEntries = async (state, props) => {
|
|
|
2019
2370
|
}
|
|
2020
2371
|
};
|
|
2021
2372
|
|
|
2022
|
-
const createViewlet = async (viewletModuleId, editorUid, tabId, bounds, uri) => {
|
|
2023
|
-
// @ts-ignore
|
|
2024
|
-
await invoke('Layout.createViewlet', viewletModuleId, editorUid, tabId, bounds, uri);
|
|
2025
|
-
};
|
|
2026
|
-
|
|
2027
2373
|
const getBasename = uri => {
|
|
2028
2374
|
const lastSlashIndex = uri.lastIndexOf('/');
|
|
2029
2375
|
if (lastSlashIndex === -1) {
|
|
@@ -2051,11 +2397,13 @@ const createEmptyGroup = (state, uri, requestId) => {
|
|
|
2051
2397
|
const groupId = create();
|
|
2052
2398
|
const title = getLabel(uri);
|
|
2053
2399
|
const tabId = create();
|
|
2400
|
+
const editorUid = create();
|
|
2054
2401
|
const newTab = {
|
|
2055
2402
|
content: '',
|
|
2056
2403
|
editorType: 'text',
|
|
2057
|
-
editorUid
|
|
2404
|
+
editorUid,
|
|
2058
2405
|
errorMessage: '',
|
|
2406
|
+
icon: '',
|
|
2059
2407
|
id: tabId,
|
|
2060
2408
|
isDirty: false,
|
|
2061
2409
|
language: '',
|
|
@@ -2130,11 +2478,13 @@ const ensureActiveGroup = (state, uri) => {
|
|
|
2130
2478
|
// Create a new tab with the URI in the active group
|
|
2131
2479
|
const title = getLabel(uri);
|
|
2132
2480
|
const tabId = create();
|
|
2481
|
+
const editorUid = create();
|
|
2133
2482
|
const newTab = {
|
|
2134
2483
|
content: '',
|
|
2135
2484
|
editorType: 'text',
|
|
2136
|
-
editorUid
|
|
2485
|
+
editorUid,
|
|
2137
2486
|
errorMessage: '',
|
|
2487
|
+
icon: '',
|
|
2138
2488
|
id: tabId,
|
|
2139
2489
|
isDirty: false,
|
|
2140
2490
|
language: '',
|
|
@@ -2149,25 +2499,6 @@ const ensureActiveGroup = (state, uri) => {
|
|
|
2149
2499
|
return newState;
|
|
2150
2500
|
};
|
|
2151
2501
|
|
|
2152
|
-
const findTabById = (state, tabId) => {
|
|
2153
|
-
const {
|
|
2154
|
-
layout
|
|
2155
|
-
} = state;
|
|
2156
|
-
const {
|
|
2157
|
-
groups
|
|
2158
|
-
} = layout;
|
|
2159
|
-
for (const group of groups) {
|
|
2160
|
-
const tab = group.tabs.find(t => t.id === tabId);
|
|
2161
|
-
if (tab) {
|
|
2162
|
-
return {
|
|
2163
|
-
groupId: group.id,
|
|
2164
|
-
tab
|
|
2165
|
-
};
|
|
2166
|
-
}
|
|
2167
|
-
}
|
|
2168
|
-
return undefined;
|
|
2169
|
-
};
|
|
2170
|
-
|
|
2171
2502
|
const findTabByUri = (state, uri) => {
|
|
2172
2503
|
const {
|
|
2173
2504
|
layout
|
|
@@ -2233,18 +2564,6 @@ const getOptionUriOptions = options => {
|
|
|
2233
2564
|
return uri;
|
|
2234
2565
|
};
|
|
2235
2566
|
|
|
2236
|
-
const getViewletModuleId = async uri => {
|
|
2237
|
-
// Query RendererWorker for viewlet module ID (optional, may fail in tests)
|
|
2238
|
-
let viewletModuleId;
|
|
2239
|
-
try {
|
|
2240
|
-
// @ts-ignore
|
|
2241
|
-
viewletModuleId = await invoke('Layout.getModuleId', uri);
|
|
2242
|
-
} catch {
|
|
2243
|
-
// Viewlet creation is optional - silently ignore if RendererWorker isn't available
|
|
2244
|
-
}
|
|
2245
|
-
return viewletModuleId;
|
|
2246
|
-
};
|
|
2247
|
-
|
|
2248
2567
|
const switchTab = (state, groupId, tabId) => {
|
|
2249
2568
|
const {
|
|
2250
2569
|
layout
|
|
@@ -2314,7 +2633,7 @@ const openUri = async (state, options) => {
|
|
|
2314
2633
|
newState: switchedState
|
|
2315
2634
|
} = switchViewlet(intermediateState1);
|
|
2316
2635
|
intermediateState1 = switchedState;
|
|
2317
|
-
set$
|
|
2636
|
+
set$4(uid, state, intermediateState1);
|
|
2318
2637
|
|
|
2319
2638
|
// @ts-ignore
|
|
2320
2639
|
|
|
@@ -2339,6 +2658,36 @@ const openUri = async (state, options) => {
|
|
|
2339
2658
|
|
|
2340
2659
|
// Attachment is handled automatically by virtual DOM reference nodes
|
|
2341
2660
|
const readyState = handleViewletReady(latestState, editorUid);
|
|
2661
|
+
|
|
2662
|
+
// Request file icon for the newly opened tab
|
|
2663
|
+
try {
|
|
2664
|
+
const newTab = findTabById(readyState, tabId);
|
|
2665
|
+
if (newTab && newTab.tab.uri) {
|
|
2666
|
+
const {
|
|
2667
|
+
newFileIconCache
|
|
2668
|
+
} = await getFileIconsForTabs([newTab.tab], readyState.fileIconCache);
|
|
2669
|
+
const icon = newFileIconCache[newTab.tab.uri] || '';
|
|
2670
|
+
|
|
2671
|
+
// Update the tab with the icon
|
|
2672
|
+
const stateWithIcon = {
|
|
2673
|
+
...readyState,
|
|
2674
|
+
fileIconCache: newFileIconCache,
|
|
2675
|
+
layout: {
|
|
2676
|
+
...readyState.layout,
|
|
2677
|
+
groups: readyState.layout.groups.map(group => ({
|
|
2678
|
+
...group,
|
|
2679
|
+
tabs: group.tabs.map(tab => tab.id === tabId ? {
|
|
2680
|
+
...tab,
|
|
2681
|
+
icon
|
|
2682
|
+
} : tab)
|
|
2683
|
+
}))
|
|
2684
|
+
}
|
|
2685
|
+
};
|
|
2686
|
+
return stateWithIcon;
|
|
2687
|
+
}
|
|
2688
|
+
} catch {
|
|
2689
|
+
// If icon request fails, continue without icon
|
|
2690
|
+
}
|
|
2342
2691
|
return readyState;
|
|
2343
2692
|
};
|
|
2344
2693
|
|
|
@@ -2348,6 +2697,13 @@ const refresh = state => {
|
|
|
2348
2697
|
};
|
|
2349
2698
|
};
|
|
2350
2699
|
|
|
2700
|
+
const Button = 1;
|
|
2701
|
+
const Div = 4;
|
|
2702
|
+
const Span = 8;
|
|
2703
|
+
const Text = 12;
|
|
2704
|
+
const Img = 17;
|
|
2705
|
+
const Pre = 51;
|
|
2706
|
+
|
|
2351
2707
|
const text = data => {
|
|
2352
2708
|
return {
|
|
2353
2709
|
childCount: 0,
|
|
@@ -2359,17 +2715,18 @@ const text = data => {
|
|
|
2359
2715
|
const CSS_CLASSES = {
|
|
2360
2716
|
EDITOR_GROUPS_CONTAINER: 'editor-groups-container'};
|
|
2361
2717
|
|
|
2362
|
-
const
|
|
2718
|
+
const renderContent = content => {
|
|
2363
2719
|
return [{
|
|
2364
2720
|
childCount: 1,
|
|
2365
|
-
className: 'TextEditor
|
|
2721
|
+
className: 'TextEditor',
|
|
2366
2722
|
type: Div
|
|
2367
2723
|
}, {
|
|
2368
2724
|
childCount: 1,
|
|
2369
|
-
className: 'EditorContent
|
|
2370
|
-
type:
|
|
2371
|
-
}, text(
|
|
2725
|
+
className: 'EditorContent',
|
|
2726
|
+
type: Pre
|
|
2727
|
+
}, text(content)];
|
|
2372
2728
|
};
|
|
2729
|
+
|
|
2373
2730
|
const renderError = errorMessage => {
|
|
2374
2731
|
return [{
|
|
2375
2732
|
childCount: 1,
|
|
@@ -2381,17 +2738,19 @@ const renderError = errorMessage => {
|
|
|
2381
2738
|
type: Div
|
|
2382
2739
|
}, text(`Error: ${errorMessage}`)];
|
|
2383
2740
|
};
|
|
2384
|
-
|
|
2741
|
+
|
|
2742
|
+
const renderLoading = () => {
|
|
2385
2743
|
return [{
|
|
2386
2744
|
childCount: 1,
|
|
2387
|
-
className: 'TextEditor',
|
|
2745
|
+
className: 'TextEditor TextEditor--loading',
|
|
2388
2746
|
type: Div
|
|
2389
2747
|
}, {
|
|
2390
2748
|
childCount: 1,
|
|
2391
|
-
className: 'EditorContent',
|
|
2392
|
-
type:
|
|
2393
|
-
}, text(
|
|
2749
|
+
className: 'EditorContent EditorContent--loading',
|
|
2750
|
+
type: Div
|
|
2751
|
+
}, text('Loading...')];
|
|
2394
2752
|
};
|
|
2753
|
+
|
|
2395
2754
|
const renderViewletReference = tab => {
|
|
2396
2755
|
return [{
|
|
2397
2756
|
childCount: 0,
|
|
@@ -2400,6 +2759,7 @@ const renderViewletReference = tab => {
|
|
|
2400
2759
|
uid: tab.editorUid
|
|
2401
2760
|
}];
|
|
2402
2761
|
};
|
|
2762
|
+
|
|
2403
2763
|
const renderEditor = tab => {
|
|
2404
2764
|
if (!tab) {
|
|
2405
2765
|
// Keep backward compatible behavior: render empty content
|
|
@@ -2446,7 +2806,7 @@ const renderTab = (tab, isActive, tabIndex, groupIndex) => {
|
|
|
2446
2806
|
}, {
|
|
2447
2807
|
childCount: 0,
|
|
2448
2808
|
className: 'TabIcon',
|
|
2449
|
-
src:
|
|
2809
|
+
src: tab.icon,
|
|
2450
2810
|
type: Img
|
|
2451
2811
|
}, {
|
|
2452
2812
|
childCount: 1,
|
|
@@ -2458,7 +2818,7 @@ const renderTab = (tab, isActive, tabIndex, groupIndex) => {
|
|
|
2458
2818
|
'data-groupIndex': groupIndex,
|
|
2459
2819
|
'data-index': tabIndex,
|
|
2460
2820
|
onClick: HandleClickClose,
|
|
2461
|
-
type: Button
|
|
2821
|
+
type: Button
|
|
2462
2822
|
}, text('×')];
|
|
2463
2823
|
};
|
|
2464
2824
|
|
|
@@ -2530,7 +2890,7 @@ const render2 = (uid, diffResult) => {
|
|
|
2530
2890
|
newState,
|
|
2531
2891
|
oldState
|
|
2532
2892
|
} = get$2(uid);
|
|
2533
|
-
set$
|
|
2893
|
+
set$4(uid, newState, newState);
|
|
2534
2894
|
const commands = applyRender(oldState, newState, diffResult);
|
|
2535
2895
|
return commands;
|
|
2536
2896
|
};
|
|
@@ -2547,7 +2907,7 @@ const renderEventListeners = () => {
|
|
|
2547
2907
|
params: ['handleClickTab', 'event.target.dataset.groupIndex', 'event.target.dataset.index']
|
|
2548
2908
|
}, {
|
|
2549
2909
|
name: HandleTabContextMenu,
|
|
2550
|
-
params: ['handleTabContextMenu', Button, ClientX, ClientY],
|
|
2910
|
+
params: ['handleTabContextMenu', Button$1, ClientX, ClientY],
|
|
2551
2911
|
preventDefault: true
|
|
2552
2912
|
}];
|
|
2553
2913
|
};
|
|
@@ -2586,11 +2946,31 @@ const commandMap = {
|
|
|
2586
2946
|
'MainArea.render2': render2,
|
|
2587
2947
|
'MainArea.renderEventListeners': renderEventListeners,
|
|
2588
2948
|
'MainArea.resize': wrapCommand(resize),
|
|
2589
|
-
'MainArea.saveState': saveState,
|
|
2949
|
+
'MainArea.saveState': wrapGetter(saveState),
|
|
2590
2950
|
'MainArea.selectTab': wrapCommand(selectTab),
|
|
2591
2951
|
'MainArea.terminate': terminate
|
|
2592
2952
|
};
|
|
2593
2953
|
|
|
2954
|
+
const send = port => {
|
|
2955
|
+
return sendMessagePortToIconThemeWorker(port, 0);
|
|
2956
|
+
};
|
|
2957
|
+
const createIconThemeWorkerRpc = async () => {
|
|
2958
|
+
try {
|
|
2959
|
+
const rpc = await LazyTransferMessagePortRpcParent.create({
|
|
2960
|
+
commandMap: {},
|
|
2961
|
+
send
|
|
2962
|
+
});
|
|
2963
|
+
return rpc;
|
|
2964
|
+
} catch (error) {
|
|
2965
|
+
throw new VError(error, `Failed to create icon theme worker rpc`);
|
|
2966
|
+
}
|
|
2967
|
+
};
|
|
2968
|
+
|
|
2969
|
+
const initializeIconThemeWorker = async () => {
|
|
2970
|
+
const rpc = await createIconThemeWorkerRpc();
|
|
2971
|
+
set$1(rpc);
|
|
2972
|
+
};
|
|
2973
|
+
|
|
2594
2974
|
const initializeRendererWorker = async () => {
|
|
2595
2975
|
const rpc = await WebWorkerRpcClient.create({
|
|
2596
2976
|
commandMap: commandMap
|
|
@@ -2600,7 +2980,7 @@ const initializeRendererWorker = async () => {
|
|
|
2600
2980
|
|
|
2601
2981
|
const listen = async () => {
|
|
2602
2982
|
registerCommands(commandMap);
|
|
2603
|
-
await initializeRendererWorker();
|
|
2983
|
+
await Promise.all([initializeRendererWorker(), initializeIconThemeWorker()]);
|
|
2604
2984
|
};
|
|
2605
2985
|
|
|
2606
2986
|
const main$2 = async () => {
|