@lvce-editor/main-area-worker 1.2.0 → 1.4.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 +397 -565
- package/package.json +1 -1
|
@@ -90,12 +90,24 @@ const getType = value => {
|
|
|
90
90
|
return Unknown;
|
|
91
91
|
}
|
|
92
92
|
};
|
|
93
|
+
const object = value => {
|
|
94
|
+
const type = getType(value);
|
|
95
|
+
if (type !== Object$1) {
|
|
96
|
+
throw new AssertionError('expected value to be of type object');
|
|
97
|
+
}
|
|
98
|
+
};
|
|
93
99
|
const number = value => {
|
|
94
100
|
const type = getType(value);
|
|
95
101
|
if (type !== Number$1) {
|
|
96
102
|
throw new AssertionError('expected value to be of type number');
|
|
97
103
|
}
|
|
98
104
|
};
|
|
105
|
+
const string = value => {
|
|
106
|
+
const type = getType(value);
|
|
107
|
+
if (type !== String) {
|
|
108
|
+
throw new AssertionError('expected value to be of type string');
|
|
109
|
+
}
|
|
110
|
+
};
|
|
99
111
|
|
|
100
112
|
const isMessagePort = value => {
|
|
101
113
|
return value && value instanceof MessagePort;
|
|
@@ -450,7 +462,7 @@ const getFirstEvent = (eventEmitter, eventMap) => {
|
|
|
450
462
|
return promise;
|
|
451
463
|
};
|
|
452
464
|
const Message$1 = 3;
|
|
453
|
-
const create$5 = async ({
|
|
465
|
+
const create$5$1 = async ({
|
|
454
466
|
isMessagePortOpen,
|
|
455
467
|
messagePort
|
|
456
468
|
}) => {
|
|
@@ -501,7 +513,7 @@ const wrap$5 = messagePort => {
|
|
|
501
513
|
};
|
|
502
514
|
const IpcParentWithMessagePort$1 = {
|
|
503
515
|
__proto__: null,
|
|
504
|
-
create: create$5,
|
|
516
|
+
create: create$5$1,
|
|
505
517
|
signal: signal$1,
|
|
506
518
|
wrap: wrap$5
|
|
507
519
|
};
|
|
@@ -720,7 +732,7 @@ const getErrorResponse = (id, error, preparePrettyError, logError) => {
|
|
|
720
732
|
const errorProperty = getErrorProperty(error, prettyError);
|
|
721
733
|
return create$1$2(id, errorProperty);
|
|
722
734
|
};
|
|
723
|
-
const create$
|
|
735
|
+
const create$5 = (message, result) => {
|
|
724
736
|
return {
|
|
725
737
|
jsonrpc: Two$1,
|
|
726
738
|
id: message.id,
|
|
@@ -729,7 +741,7 @@ const create$3 = (message, result) => {
|
|
|
729
741
|
};
|
|
730
742
|
const getSuccessResponse = (message, result) => {
|
|
731
743
|
const resultProperty = result ?? null;
|
|
732
|
-
return create$
|
|
744
|
+
return create$5(message, resultProperty);
|
|
733
745
|
};
|
|
734
746
|
const getErrorResponseSimple = (id, error) => {
|
|
735
747
|
return {
|
|
@@ -1031,6 +1043,7 @@ const createMockRpc = ({
|
|
|
1031
1043
|
const Button = 1;
|
|
1032
1044
|
const Div = 4;
|
|
1033
1045
|
const Span = 8;
|
|
1046
|
+
const Text = 12;
|
|
1034
1047
|
const Pre = 51;
|
|
1035
1048
|
|
|
1036
1049
|
const TargetName = 'event.target.name';
|
|
@@ -1052,7 +1065,7 @@ const remove = id => {
|
|
|
1052
1065
|
};
|
|
1053
1066
|
|
|
1054
1067
|
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
|
1055
|
-
const create$
|
|
1068
|
+
const create$3 = rpcId => {
|
|
1056
1069
|
return {
|
|
1057
1070
|
async dispose() {
|
|
1058
1071
|
const rpc = get$1(rpcId);
|
|
@@ -1090,12 +1103,12 @@ const create$2 = rpcId => {
|
|
|
1090
1103
|
|
|
1091
1104
|
const {
|
|
1092
1105
|
set: set$2
|
|
1093
|
-
} = create$
|
|
1106
|
+
} = create$3(ExtensionHostWorker);
|
|
1094
1107
|
|
|
1095
1108
|
const {
|
|
1096
1109
|
invokeAndTransfer,
|
|
1097
1110
|
set: set$1
|
|
1098
|
-
} = create$
|
|
1111
|
+
} = create$3(RendererWorker);
|
|
1099
1112
|
const sendMessagePortToExtensionHostWorker$1 = async (port, rpcId = 0) => {
|
|
1100
1113
|
const command = 'HandleMessagePort.handleMessagePort2';
|
|
1101
1114
|
await invokeAndTransfer('SendMessagePortToExtensionHostWorker.sendMessagePortToExtensionHostWorker', port, command, rpcId);
|
|
@@ -1105,7 +1118,7 @@ const toCommandId = key => {
|
|
|
1105
1118
|
const dotIndex = key.indexOf('.');
|
|
1106
1119
|
return key.slice(dotIndex + 1);
|
|
1107
1120
|
};
|
|
1108
|
-
const create$
|
|
1121
|
+
const create$2 = () => {
|
|
1109
1122
|
const states = Object.create(null);
|
|
1110
1123
|
const commandMapRef = {};
|
|
1111
1124
|
return {
|
|
@@ -1191,9 +1204,9 @@ const {
|
|
|
1191
1204
|
getCommandIds,
|
|
1192
1205
|
registerCommands,
|
|
1193
1206
|
set,
|
|
1194
|
-
wrapCommand} = create$
|
|
1207
|
+
wrapCommand} = create$2();
|
|
1195
1208
|
|
|
1196
|
-
const create = (uid, uri, x, y, width, height, platform, assetDir) => {
|
|
1209
|
+
const create$1 = (uid, uri, x, y, width, height, platform, assetDir) => {
|
|
1197
1210
|
const state = {
|
|
1198
1211
|
assetDir,
|
|
1199
1212
|
platform,
|
|
@@ -1263,13 +1276,381 @@ const initialize = async () => {
|
|
|
1263
1276
|
};
|
|
1264
1277
|
|
|
1265
1278
|
const loadContent = async state => {
|
|
1279
|
+
const tabs = [{
|
|
1280
|
+
content: '',
|
|
1281
|
+
editorType: 'text',
|
|
1282
|
+
id: '1',
|
|
1283
|
+
isDirty: false,
|
|
1284
|
+
title: 'tab 1'
|
|
1285
|
+
}, {
|
|
1286
|
+
content: '',
|
|
1287
|
+
editorType: 'text',
|
|
1288
|
+
id: '2',
|
|
1289
|
+
isDirty: false,
|
|
1290
|
+
title: 'tab 2'
|
|
1291
|
+
}];
|
|
1292
|
+
return {
|
|
1293
|
+
...state,
|
|
1294
|
+
layout: {
|
|
1295
|
+
activeGroupId: '0',
|
|
1296
|
+
direction: 'horizontal',
|
|
1297
|
+
groups: [{
|
|
1298
|
+
activeTabId: '',
|
|
1299
|
+
direction: 'horizontal',
|
|
1300
|
+
focused: false,
|
|
1301
|
+
id: '0',
|
|
1302
|
+
size: 300,
|
|
1303
|
+
tabs
|
|
1304
|
+
}]
|
|
1305
|
+
}
|
|
1306
|
+
};
|
|
1307
|
+
};
|
|
1308
|
+
|
|
1309
|
+
let idCounter = 0;
|
|
1310
|
+
const create = () => {
|
|
1311
|
+
idCounter++;
|
|
1312
|
+
return idCounter;
|
|
1313
|
+
};
|
|
1314
|
+
|
|
1315
|
+
const getTitle = (uri, homeDir) => {
|
|
1316
|
+
if (!uri) {
|
|
1317
|
+
return '';
|
|
1318
|
+
}
|
|
1319
|
+
return uri;
|
|
1320
|
+
};
|
|
1321
|
+
const getLabel = uri => {
|
|
1322
|
+
if (uri.startsWith('settings://')) {
|
|
1323
|
+
return 'Settings';
|
|
1324
|
+
}
|
|
1325
|
+
if (uri.startsWith('simple-browser://')) {
|
|
1326
|
+
return 'Simple Browser';
|
|
1327
|
+
}
|
|
1328
|
+
return uri;
|
|
1329
|
+
// return Workspace.pathBaseName(uri)
|
|
1330
|
+
};
|
|
1331
|
+
|
|
1332
|
+
/**
|
|
1333
|
+
*
|
|
1334
|
+
* @param {string} uri
|
|
1335
|
+
* @returns
|
|
1336
|
+
*/
|
|
1337
|
+
const getFileIcon = uri => {
|
|
1338
|
+
if (uri === 'app://keybindings') {
|
|
1339
|
+
return `MaskIconRecordKey`;
|
|
1340
|
+
}
|
|
1341
|
+
if (uri.startsWith('extension-detail://')) {
|
|
1342
|
+
return `MaskIconExtensions`;
|
|
1343
|
+
}
|
|
1344
|
+
return '';
|
|
1345
|
+
};
|
|
1346
|
+
|
|
1347
|
+
const Preview = 1 << 4;
|
|
1348
|
+
|
|
1349
|
+
// @ts-nocheck
|
|
1350
|
+
|
|
1351
|
+
const focusIndex = async (state, index) => {
|
|
1352
|
+
const {
|
|
1353
|
+
activeGroupIndex,
|
|
1354
|
+
groups,
|
|
1355
|
+
tabHeight,
|
|
1356
|
+
uid
|
|
1357
|
+
} = state;
|
|
1358
|
+
const group = groups[activeGroupIndex];
|
|
1359
|
+
const {
|
|
1360
|
+
editors
|
|
1361
|
+
} = group;
|
|
1362
|
+
const oldActiveIndex = group.activeIndex;
|
|
1363
|
+
if (index === oldActiveIndex) {
|
|
1364
|
+
return {
|
|
1365
|
+
commands: [],
|
|
1366
|
+
newState: state
|
|
1367
|
+
};
|
|
1368
|
+
}
|
|
1369
|
+
const newGroup = {
|
|
1370
|
+
...group,
|
|
1371
|
+
activeIndex: index
|
|
1372
|
+
};
|
|
1373
|
+
const newGroups = [...groups.slice(0, activeGroupIndex), newGroup, ...groups.slice(activeGroupIndex + 1)];
|
|
1374
|
+
const newState = {
|
|
1375
|
+
...state,
|
|
1376
|
+
groups: newGroups
|
|
1377
|
+
};
|
|
1378
|
+
const editor = editors[index];
|
|
1379
|
+
const {
|
|
1380
|
+
x
|
|
1381
|
+
} = group;
|
|
1382
|
+
const y = group.y + tabHeight;
|
|
1383
|
+
const {
|
|
1384
|
+
width
|
|
1385
|
+
} = group;
|
|
1386
|
+
const contentHeight = group.height - tabHeight;
|
|
1387
|
+
const id = await ViewletMap.getModuleId(editor.uri);
|
|
1388
|
+
const oldEditor = editors[oldActiveIndex];
|
|
1389
|
+
const oldId = await ViewletMap.getModuleId(oldEditor.uri);
|
|
1390
|
+
// @ts-ignore
|
|
1391
|
+
ViewletStates.getInstance(oldId);
|
|
1392
|
+
const previousUid = oldEditor.uid;
|
|
1393
|
+
number(previousUid);
|
|
1394
|
+
const disposeCommands = Viewlet.disposeFunctional(previousUid);
|
|
1395
|
+
const maybeHiddenEditorInstance = ViewletStates.getInstance(editor.uid);
|
|
1396
|
+
if (maybeHiddenEditorInstance) {
|
|
1397
|
+
const commands = Viewlet.showFunctional(editor.uid);
|
|
1398
|
+
const allCommands = [...disposeCommands, ...commands];
|
|
1399
|
+
return {
|
|
1400
|
+
commands: allCommands,
|
|
1401
|
+
newState
|
|
1402
|
+
};
|
|
1403
|
+
}
|
|
1404
|
+
const instanceUid = create();
|
|
1405
|
+
const instance = ViewletManager.create(ViewletModule.load, id, uid, editor.uri, x, y, width, contentHeight);
|
|
1406
|
+
instance.show = false;
|
|
1407
|
+
instance.setBounds = false;
|
|
1408
|
+
instance.uid = instanceUid;
|
|
1409
|
+
editor.uid = instanceUid;
|
|
1410
|
+
const resizeCommands = ['Viewlet.setBounds', instanceUid, x, tabHeight, width, contentHeight];
|
|
1411
|
+
|
|
1412
|
+
// @ts-ignore
|
|
1413
|
+
const commands = await ViewletManager.load(instance);
|
|
1414
|
+
// @ts-ignore
|
|
1415
|
+
commands.unshift(...disposeCommands);
|
|
1416
|
+
// @ts-ignore
|
|
1417
|
+
commands.push(resizeCommands);
|
|
1418
|
+
// @ts-ignore
|
|
1419
|
+
commands.push(['Viewlet.append', uid, instanceUid]);
|
|
1420
|
+
return {
|
|
1421
|
+
commands,
|
|
1422
|
+
newState
|
|
1423
|
+
};
|
|
1424
|
+
};
|
|
1425
|
+
|
|
1426
|
+
// @ts-nocheck
|
|
1427
|
+
const openUri = async (state, uri, focus = true, {
|
|
1428
|
+
preview = false,
|
|
1429
|
+
...context
|
|
1430
|
+
} = {}) => {
|
|
1431
|
+
object(state);
|
|
1432
|
+
string(uri);
|
|
1433
|
+
const {
|
|
1434
|
+
activeGroupIndex,
|
|
1435
|
+
groups,
|
|
1436
|
+
tabFontFamily,
|
|
1437
|
+
tabFontSize,
|
|
1438
|
+
tabFontWeight,
|
|
1439
|
+
tabHeight,
|
|
1440
|
+
tabLetterSpacing
|
|
1441
|
+
} = state;
|
|
1442
|
+
const {
|
|
1443
|
+
x
|
|
1444
|
+
} = state;
|
|
1445
|
+
const y = state.y + tabHeight;
|
|
1446
|
+
const {
|
|
1447
|
+
width
|
|
1448
|
+
} = state;
|
|
1449
|
+
const contentHeight = state.height - tabHeight;
|
|
1450
|
+
// @ts-ignore
|
|
1451
|
+
const moduleId = await ViewletMap.getModuleId(uri, context.opener);
|
|
1452
|
+
let activeGroup = groups[activeGroupIndex];
|
|
1453
|
+
activeGroup ||= {
|
|
1454
|
+
activeIndex: -1,
|
|
1455
|
+
editors: [],
|
|
1456
|
+
focusedIndex: -1,
|
|
1457
|
+
height: state.height,
|
|
1458
|
+
tabsUid: create(),
|
|
1459
|
+
uid: create(),
|
|
1460
|
+
width,
|
|
1461
|
+
x,
|
|
1462
|
+
y: 0
|
|
1463
|
+
};
|
|
1464
|
+
const {
|
|
1465
|
+
activeIndex,
|
|
1466
|
+
editors
|
|
1467
|
+
} = activeGroup;
|
|
1468
|
+
const previousEditor = editors[activeIndex];
|
|
1469
|
+
let disposeCommands;
|
|
1470
|
+
// @ts-ignore
|
|
1471
|
+
if (previousEditor && previousEditor.uri === uri && previousEditor.opener === context.opener) {
|
|
1472
|
+
return {
|
|
1473
|
+
commands: [],
|
|
1474
|
+
newState: state
|
|
1475
|
+
};
|
|
1476
|
+
}
|
|
1477
|
+
for (let i = 0; i < editors.length; i++) {
|
|
1478
|
+
const editor = editors[i];
|
|
1479
|
+
if (editor.uri === uri &&
|
|
1480
|
+
// @ts-ignore
|
|
1481
|
+
editor.opener === context.opener) {
|
|
1482
|
+
return focusIndex(state, i);
|
|
1483
|
+
}
|
|
1484
|
+
}
|
|
1485
|
+
// TODO editor needs to be disposed when closing
|
|
1486
|
+
// other tabs and closing all tabs
|
|
1487
|
+
if (previousEditor) {
|
|
1488
|
+
const previousUid = previousEditor.uid;
|
|
1489
|
+
disposeCommands = Viewlet.hideFunctional(previousUid);
|
|
1490
|
+
}
|
|
1491
|
+
const instanceUid = create();
|
|
1492
|
+
const instance = ViewletManager.create(ViewletModule.load, moduleId, state.uid, uri, activeGroup.x, y, activeGroup.width, contentHeight);
|
|
1493
|
+
instance.uid = instanceUid;
|
|
1494
|
+
// const oldActiveIndex = state.activeIndex
|
|
1495
|
+
const tabLabel = getLabel(uri);
|
|
1496
|
+
const tabWidth = MeasureTabWidth.measureTabWidth(tabLabel, tabFontWeight, tabFontSize, tabFontFamily, tabLetterSpacing);
|
|
1497
|
+
const tabTitle = getTitle(uri);
|
|
1498
|
+
const icon = getFileIcon(uri);
|
|
1499
|
+
const newEditor = {
|
|
1500
|
+
flags: Preview,
|
|
1501
|
+
icon,
|
|
1502
|
+
label: tabLabel,
|
|
1503
|
+
moduleId,
|
|
1504
|
+
tabWidth,
|
|
1505
|
+
title: tabTitle,
|
|
1506
|
+
uid: instanceUid,
|
|
1507
|
+
uri
|
|
1508
|
+
};
|
|
1509
|
+
const newEditors = [...activeGroup.editors, newEditor];
|
|
1510
|
+
const newActiveIndex = newEditors.length - 1;
|
|
1511
|
+
const newGroup = {
|
|
1512
|
+
...activeGroup,
|
|
1513
|
+
activeIndex: newActiveIndex,
|
|
1514
|
+
editors: newEditors
|
|
1515
|
+
};
|
|
1516
|
+
const newGroups = [...groups.slice(0, activeGroupIndex), newGroup, ...groups.slice(activeGroupIndex + 1)];
|
|
1517
|
+
// @ts-ignore
|
|
1518
|
+
instance.show = false;
|
|
1519
|
+
instance.setBounds = false;
|
|
1520
|
+
ViewletStates.setState(state.uid, {
|
|
1521
|
+
...state,
|
|
1522
|
+
activeGroupIndex: 0,
|
|
1523
|
+
groups: newGroups,
|
|
1524
|
+
pendingUid: instanceUid
|
|
1525
|
+
});
|
|
1526
|
+
if (context) {
|
|
1527
|
+
instance.args = [context];
|
|
1528
|
+
}
|
|
1529
|
+
// @ts-ignore
|
|
1530
|
+
const commands = await ViewletManager.load(instance, focus);
|
|
1531
|
+
commands.push(['Viewlet.setBounds', instanceUid, activeGroup.x, tabHeight, activeGroup.width, contentHeight]);
|
|
1532
|
+
let {
|
|
1533
|
+
tabsUid
|
|
1534
|
+
} = state;
|
|
1535
|
+
if (tabsUid === -1) {
|
|
1536
|
+
tabsUid = create();
|
|
1537
|
+
}
|
|
1538
|
+
if (disposeCommands) {
|
|
1539
|
+
commands.push(...disposeCommands);
|
|
1540
|
+
}
|
|
1541
|
+
commands.push(['Viewlet.append', state.uid, instanceUid]);
|
|
1542
|
+
if (focus) {
|
|
1543
|
+
commands.push(['Viewlet.focus', instanceUid]);
|
|
1544
|
+
}
|
|
1545
|
+
const latestState = ViewletStates.getState(state.uid);
|
|
1546
|
+
const latestPendingUid = latestState.pendingUid;
|
|
1547
|
+
if (latestPendingUid !== instanceUid) {
|
|
1548
|
+
return {
|
|
1549
|
+
commands: [],
|
|
1550
|
+
newState: state
|
|
1551
|
+
};
|
|
1552
|
+
}
|
|
1553
|
+
if (!ViewletStates.hasInstance(instanceUid)) {
|
|
1554
|
+
return {
|
|
1555
|
+
commands,
|
|
1556
|
+
newState: state
|
|
1557
|
+
};
|
|
1558
|
+
}
|
|
1559
|
+
return {
|
|
1560
|
+
commands,
|
|
1561
|
+
newState: {
|
|
1562
|
+
...state,
|
|
1563
|
+
groups: newGroups,
|
|
1564
|
+
tabsUid
|
|
1565
|
+
}
|
|
1566
|
+
};
|
|
1567
|
+
};
|
|
1568
|
+
|
|
1569
|
+
const text = data => {
|
|
1266
1570
|
return {
|
|
1267
|
-
|
|
1571
|
+
childCount: 0,
|
|
1572
|
+
text: data,
|
|
1573
|
+
type: Text
|
|
1268
1574
|
};
|
|
1269
1575
|
};
|
|
1270
1576
|
|
|
1577
|
+
const CSS_CLASSES = {
|
|
1578
|
+
EDITOR_GROUPS_CONTAINER: 'editor-groups-container'};
|
|
1579
|
+
|
|
1580
|
+
const renderTab = (tab, isActive) => {
|
|
1581
|
+
return [{
|
|
1582
|
+
childCount: 2,
|
|
1583
|
+
className: 'MainTab',
|
|
1584
|
+
type: Div
|
|
1585
|
+
}, {
|
|
1586
|
+
childCount: 1,
|
|
1587
|
+
className: 'TabTitle',
|
|
1588
|
+
type: Span
|
|
1589
|
+
}, text(tab.isDirty ? `*${tab.title}` : tab.title), {
|
|
1590
|
+
childCount: 1,
|
|
1591
|
+
className: 'TabCloseButton',
|
|
1592
|
+
type: Button
|
|
1593
|
+
}, text('×')];
|
|
1594
|
+
};
|
|
1595
|
+
const renderTabBar = group => {
|
|
1596
|
+
return [{
|
|
1597
|
+
childCount: group.tabs.length,
|
|
1598
|
+
className: 'MainTabs',
|
|
1599
|
+
type: Div
|
|
1600
|
+
}, ...group.tabs.flatMap(tab => renderTab(tab))];
|
|
1601
|
+
};
|
|
1602
|
+
const renderEditor = tab => {
|
|
1603
|
+
if (!tab) {
|
|
1604
|
+
return [text('Tab not found')];
|
|
1605
|
+
}
|
|
1606
|
+
if (tab.editorType === 'custom') {
|
|
1607
|
+
return [{
|
|
1608
|
+
childCount: 1,
|
|
1609
|
+
className: 'CustomEditor',
|
|
1610
|
+
type: Div
|
|
1611
|
+
}, text(`Custom Editor: ${tab.customEditorId}`)];
|
|
1612
|
+
}
|
|
1613
|
+
return [{
|
|
1614
|
+
childCount: 1,
|
|
1615
|
+
className: 'TextEditor',
|
|
1616
|
+
type: Div
|
|
1617
|
+
}, {
|
|
1618
|
+
childCount: 1,
|
|
1619
|
+
className: 'EditorContent',
|
|
1620
|
+
type: Pre
|
|
1621
|
+
}, text(tab.content || '')];
|
|
1622
|
+
};
|
|
1623
|
+
const renderEditorGroup = group => {
|
|
1624
|
+
const activeTab = group.tabs.find(tab => tab.id === group.activeTabId);
|
|
1625
|
+
return [{
|
|
1626
|
+
childCount: 2,
|
|
1627
|
+
className: 'EditorGroup',
|
|
1628
|
+
type: Div
|
|
1629
|
+
}, ...renderTabBar(group), {
|
|
1630
|
+
childCount: activeTab ? 1 : 1,
|
|
1631
|
+
className: 'EditorContainer',
|
|
1632
|
+
type: Div
|
|
1633
|
+
}, ...renderEditor(activeTab)];
|
|
1634
|
+
};
|
|
1635
|
+
const getMainAreaVirtualDom = layout => {
|
|
1636
|
+
return [{
|
|
1637
|
+
childCount: 1,
|
|
1638
|
+
className: 'Main',
|
|
1639
|
+
type: Div
|
|
1640
|
+
}, {
|
|
1641
|
+
childCount: layout.groups.length,
|
|
1642
|
+
className: CSS_CLASSES.EDITOR_GROUPS_CONTAINER,
|
|
1643
|
+
type: Div
|
|
1644
|
+
}, ...layout.groups.flatMap(renderEditorGroup)];
|
|
1645
|
+
};
|
|
1646
|
+
|
|
1271
1647
|
const renderItems = (oldState, newState) => {
|
|
1272
|
-
|
|
1648
|
+
const {
|
|
1649
|
+
layout,
|
|
1650
|
+
uid
|
|
1651
|
+
} = newState;
|
|
1652
|
+
const dom = getMainAreaVirtualDom(layout);
|
|
1653
|
+
return [SetDom2, uid, dom];
|
|
1273
1654
|
};
|
|
1274
1655
|
|
|
1275
1656
|
const getRenderer = diffType => {
|
|
@@ -1336,12 +1717,13 @@ const saveState = uid => {
|
|
|
1336
1717
|
};
|
|
1337
1718
|
|
|
1338
1719
|
const commandMap = {
|
|
1339
|
-
'MainArea.create': create,
|
|
1720
|
+
'MainArea.create': create$1,
|
|
1340
1721
|
'MainArea.diff2': diff2,
|
|
1341
1722
|
'MainArea.getCommandIds': getCommandIds,
|
|
1342
1723
|
'MainArea.handleClick': wrapCommand(handleClick),
|
|
1343
1724
|
'MainArea.initialize': initialize,
|
|
1344
1725
|
'MainArea.loadContent': wrapCommand(loadContent),
|
|
1726
|
+
'MainArea.openUri': wrapCommand(openUri),
|
|
1345
1727
|
'MainArea.render2': render2,
|
|
1346
1728
|
'MainArea.renderEventListeners': renderEventListeners,
|
|
1347
1729
|
'MainArea.resize': wrapCommand(resize),
|
|
@@ -1361,560 +1743,10 @@ const main$2 = async () => {
|
|
|
1361
1743
|
await listen();
|
|
1362
1744
|
};
|
|
1363
1745
|
|
|
1364
|
-
const closeEditorGroup = (state, groupId) => {
|
|
1365
|
-
const groupIndex = state.layout.groups.findIndex(group => group.id === groupId);
|
|
1366
|
-
if (groupIndex === -1 || state.layout.groups.length <= 1) {
|
|
1367
|
-
return state;
|
|
1368
|
-
}
|
|
1369
|
-
const remainingGroups = state.layout.groups.filter(group => group.id !== groupId);
|
|
1370
|
-
const redistributedGroups = remainingGroups.map((group, index) => ({
|
|
1371
|
-
...group,
|
|
1372
|
-
size: Math.round(100 / remainingGroups.length)
|
|
1373
|
-
}));
|
|
1374
|
-
const newActiveGroupId = state.layout.activeGroupId === groupId ? remainingGroups[0].id : state.layout.activeGroupId;
|
|
1375
|
-
return {
|
|
1376
|
-
...state,
|
|
1377
|
-
layout: {
|
|
1378
|
-
...state.layout,
|
|
1379
|
-
activeGroupId: newActiveGroupId,
|
|
1380
|
-
groups: redistributedGroups
|
|
1381
|
-
}
|
|
1382
|
-
};
|
|
1383
|
-
};
|
|
1384
|
-
|
|
1385
|
-
const closeTab = (state, groupId, tabId) => {
|
|
1386
|
-
const groups = state.layout.groups.map(group => {
|
|
1387
|
-
if (group.id === groupId) {
|
|
1388
|
-
const newTabs = group.tabs.filter(tab => tab.id !== tabId);
|
|
1389
|
-
let newActiveTabId = group.activeTabId;
|
|
1390
|
-
if (group.activeTabId === tabId) {
|
|
1391
|
-
const tabIndex = group.tabs.findIndex(tab => tab.id === tabId);
|
|
1392
|
-
if (newTabs.length > 0) {
|
|
1393
|
-
newActiveTabId = newTabs[Math.min(tabIndex, newTabs.length - 1)].id;
|
|
1394
|
-
} else {
|
|
1395
|
-
newActiveTabId = undefined;
|
|
1396
|
-
}
|
|
1397
|
-
}
|
|
1398
|
-
return {
|
|
1399
|
-
...group,
|
|
1400
|
-
activeTabId: newActiveTabId,
|
|
1401
|
-
tabs: newTabs
|
|
1402
|
-
};
|
|
1403
|
-
}
|
|
1404
|
-
return group;
|
|
1405
|
-
});
|
|
1406
|
-
return {
|
|
1407
|
-
...state,
|
|
1408
|
-
layout: {
|
|
1409
|
-
...state.layout,
|
|
1410
|
-
groups
|
|
1411
|
-
}
|
|
1412
|
-
};
|
|
1413
|
-
};
|
|
1414
|
-
|
|
1415
|
-
const focusEditorGroup = (state, groupId) => {
|
|
1416
|
-
const groups = state.layout.groups.map(group => ({
|
|
1417
|
-
...group,
|
|
1418
|
-
focused: group.id === groupId
|
|
1419
|
-
}));
|
|
1420
|
-
return {
|
|
1421
|
-
...state,
|
|
1422
|
-
layout: {
|
|
1423
|
-
...state.layout,
|
|
1424
|
-
activeGroupId: groupId,
|
|
1425
|
-
groups
|
|
1426
|
-
}
|
|
1427
|
-
};
|
|
1428
|
-
};
|
|
1429
|
-
|
|
1430
|
-
const CSS_CLASSES = {
|
|
1431
|
-
CUSTOM_EDITOR: 'custom-editor',
|
|
1432
|
-
EDITOR_CONTAINER: 'editor-container',
|
|
1433
|
-
EDITOR_CONTENT: 'editor-content',
|
|
1434
|
-
EDITOR_GROUP: 'editor-group',
|
|
1435
|
-
EDITOR_GROUP_FOCUSED: 'focused',
|
|
1436
|
-
EDITOR_GROUPS_CONTAINER: 'editor-groups-container',
|
|
1437
|
-
EMPTY_EDITOR: 'empty-editor',
|
|
1438
|
-
MAIN_AREA: 'main-area',
|
|
1439
|
-
TAB: 'tab',
|
|
1440
|
-
TAB_ACTIVE: 'active',
|
|
1441
|
-
TAB_BAR: 'tab-bar',
|
|
1442
|
-
TAB_CLOSE: 'tab-close',
|
|
1443
|
-
TAB_TITLE: 'tab-title',
|
|
1444
|
-
TEXT_EDITOR: 'text-editor'
|
|
1445
|
-
};
|
|
1446
|
-
const CSS_ATTRIBUTES = {
|
|
1447
|
-
DATA_ACTION: 'data-action',
|
|
1448
|
-
DATA_CUSTOM_EDITOR_ID: 'data-custom-editor-id',
|
|
1449
|
-
DATA_DIRECTION: 'data-direction',
|
|
1450
|
-
DATA_GROUP_ID: 'data-group-id',
|
|
1451
|
-
DATA_LANGUAGE: 'data-language',
|
|
1452
|
-
DATA_TAB_ID: 'data-tab-id'
|
|
1453
|
-
};
|
|
1454
|
-
const CSS_STYLES = {
|
|
1455
|
-
CUSTOM_EDITOR_STYLE: 'flex: 1; overflow: auto;',
|
|
1456
|
-
EDITOR_GROUP_BASE: 'display: flex; flex-direction: column; border-right: 1px solid var(--border-color);',
|
|
1457
|
-
EDITOR_GROUP_FOCUSED_STYLE: 'box-shadow: 0 0 0 1px var(--focus-border-color);',
|
|
1458
|
-
EMPTY_EDITOR_STYLE: 'flex: 1; display: flex; align-items: center; justify-content: center; color: var(--dimmed-color);',
|
|
1459
|
-
FLEX_COLUMN: 'display: flex; flex-direction: column; height: 100%;',
|
|
1460
|
-
FLEX_ROW: 'display: flex; flex-direction: row; height: 100%;',
|
|
1461
|
-
TAB_ACTIVE_STYLE: 'background: var(--tab-active-background); color: var(--tab-active-color);',
|
|
1462
|
-
TAB_BAR_BASE: 'display: flex; align-items: center; background: var(--tab-bar-background); border-bottom: 1px solid var(--border-color);',
|
|
1463
|
-
TAB_BASE: 'padding: 4px 8px; cursor: pointer; border-right: 1px solid var(--border-color); display: flex; align-items: center; gap: 4px;',
|
|
1464
|
-
TAB_CLOSE_STYLE: 'background: none; border: none; cursor: pointer; padding: 2px; border-radius: 2px; opacity: 0.7;',
|
|
1465
|
-
TEXT_EDITOR_STYLE: 'flex: 1; overflow: auto; font-family: var(--editor-font-family); font-size: var(--editor-font-size);'
|
|
1466
|
-
};
|
|
1467
|
-
const THEMES = {
|
|
1468
|
-
DARK: {
|
|
1469
|
-
'--border-color': '#3e3e42',
|
|
1470
|
-
'--dimmed-color': '#858585',
|
|
1471
|
-
'--editor-font-family': 'Consolas, Monaco, "Courier New", monospace',
|
|
1472
|
-
'--editor-font-size': '14px',
|
|
1473
|
-
'--focus-border-color': '#0078d4',
|
|
1474
|
-
'--tab-active-background': '#1e1e1e',
|
|
1475
|
-
'--tab-active-color': '#ffffff',
|
|
1476
|
-
'--tab-bar-background': '#252526',
|
|
1477
|
-
'--tab-close-hover-background': '#3e3e42'
|
|
1478
|
-
},
|
|
1479
|
-
LIGHT: {
|
|
1480
|
-
'--border-color': '#e1e1e1',
|
|
1481
|
-
'--dimmed-color': '#999999',
|
|
1482
|
-
'--editor-font-family': 'Consolas, Monaco, "Courier New", monospace',
|
|
1483
|
-
'--editor-font-size': '14px',
|
|
1484
|
-
'--focus-border-color': '#0078d4',
|
|
1485
|
-
'--tab-active-background': '#ffffff',
|
|
1486
|
-
'--tab-active-color': '#333333',
|
|
1487
|
-
'--tab-bar-background': '#f3f3f3',
|
|
1488
|
-
'--tab-close-hover-background': '#e1e1e1'
|
|
1489
|
-
}
|
|
1490
|
-
};
|
|
1491
|
-
const getThemeStyles = (theme = 'DARK') => {
|
|
1492
|
-
const themeVars = THEMES[theme];
|
|
1493
|
-
return Object.entries(themeVars).map(([key, value]) => `${key}: ${value};`).join(' ');
|
|
1494
|
-
};
|
|
1495
|
-
|
|
1496
|
-
const renderTab = (tab, isActive) => {
|
|
1497
|
-
return {
|
|
1498
|
-
attributes: {
|
|
1499
|
-
[CSS_ATTRIBUTES.DATA_TAB_ID]: tab.id,
|
|
1500
|
-
style: `${CSS_STYLES.TAB_BASE} ${isActive ? CSS_STYLES.TAB_ACTIVE_STYLE : ''}`
|
|
1501
|
-
},
|
|
1502
|
-
childCount: 2,
|
|
1503
|
-
children: [{
|
|
1504
|
-
childCount: 1,
|
|
1505
|
-
children: [tab.isDirty ? `*${tab.title}` : tab.title],
|
|
1506
|
-
className: CSS_CLASSES.TAB_TITLE,
|
|
1507
|
-
type: Span
|
|
1508
|
-
}, {
|
|
1509
|
-
attributes: {
|
|
1510
|
-
[CSS_ATTRIBUTES.DATA_ACTION]: 'close-tab',
|
|
1511
|
-
[CSS_ATTRIBUTES.DATA_TAB_ID]: tab.id,
|
|
1512
|
-
style: CSS_STYLES.TAB_CLOSE_STYLE
|
|
1513
|
-
},
|
|
1514
|
-
childCount: 1,
|
|
1515
|
-
children: ['×'],
|
|
1516
|
-
className: CSS_CLASSES.TAB_CLOSE,
|
|
1517
|
-
type: Button
|
|
1518
|
-
}],
|
|
1519
|
-
className: `${CSS_CLASSES.TAB} ${isActive ? CSS_CLASSES.TAB_ACTIVE : ''}`,
|
|
1520
|
-
type: Div
|
|
1521
|
-
};
|
|
1522
|
-
};
|
|
1523
|
-
const renderTabBar = group => {
|
|
1524
|
-
return {
|
|
1525
|
-
attributes: {
|
|
1526
|
-
[CSS_ATTRIBUTES.DATA_GROUP_ID]: group.id,
|
|
1527
|
-
style: CSS_STYLES.TAB_BAR_BASE
|
|
1528
|
-
},
|
|
1529
|
-
childCount: group.tabs.length,
|
|
1530
|
-
children: group.tabs.map(tab => renderTab(tab, tab.id === group.activeTabId)),
|
|
1531
|
-
className: CSS_CLASSES.TAB_BAR,
|
|
1532
|
-
type: Div
|
|
1533
|
-
};
|
|
1534
|
-
};
|
|
1535
|
-
const renderEditor = tab => {
|
|
1536
|
-
if (tab.editorType === 'custom') {
|
|
1537
|
-
return {
|
|
1538
|
-
attributes: {
|
|
1539
|
-
[CSS_ATTRIBUTES.DATA_CUSTOM_EDITOR_ID]: tab.customEditorId,
|
|
1540
|
-
[CSS_ATTRIBUTES.DATA_TAB_ID]: tab.id,
|
|
1541
|
-
style: CSS_STYLES.CUSTOM_EDITOR_STYLE
|
|
1542
|
-
},
|
|
1543
|
-
childCount: 1,
|
|
1544
|
-
children: [`Custom Editor: ${tab.customEditorId}`],
|
|
1545
|
-
className: CSS_CLASSES.CUSTOM_EDITOR,
|
|
1546
|
-
type: Div
|
|
1547
|
-
};
|
|
1548
|
-
}
|
|
1549
|
-
return {
|
|
1550
|
-
attributes: {
|
|
1551
|
-
[CSS_ATTRIBUTES.DATA_LANGUAGE]: tab.language || 'plaintext',
|
|
1552
|
-
[CSS_ATTRIBUTES.DATA_TAB_ID]: tab.id,
|
|
1553
|
-
style: CSS_STYLES.TEXT_EDITOR_STYLE
|
|
1554
|
-
},
|
|
1555
|
-
childCount: 1,
|
|
1556
|
-
children: [{
|
|
1557
|
-
childCount: 1,
|
|
1558
|
-
children: [tab.content || ''],
|
|
1559
|
-
className: CSS_CLASSES.EDITOR_CONTENT,
|
|
1560
|
-
type: Pre
|
|
1561
|
-
}],
|
|
1562
|
-
className: CSS_CLASSES.TEXT_EDITOR,
|
|
1563
|
-
type: Div
|
|
1564
|
-
};
|
|
1565
|
-
};
|
|
1566
|
-
const renderEditorGroup = group => {
|
|
1567
|
-
const activeTab = group.tabs.find(tab => tab.id === group.activeTabId);
|
|
1568
|
-
return {
|
|
1569
|
-
attributes: {
|
|
1570
|
-
[CSS_ATTRIBUTES.DATA_GROUP_ID]: group.id,
|
|
1571
|
-
style: `${CSS_STYLES.EDITOR_GROUP_BASE} flex: ${group.size}; ${group.focused ? CSS_STYLES.EDITOR_GROUP_FOCUSED_STYLE : ''}`
|
|
1572
|
-
},
|
|
1573
|
-
childCount: 2,
|
|
1574
|
-
children: [renderTabBar(group), {
|
|
1575
|
-
childCount: activeTab ? 1 : 1,
|
|
1576
|
-
children: activeTab ? [renderEditor(activeTab)] : [{
|
|
1577
|
-
attributes: {
|
|
1578
|
-
style: CSS_STYLES.EMPTY_EDITOR_STYLE
|
|
1579
|
-
},
|
|
1580
|
-
childCount: 1,
|
|
1581
|
-
children: ['No open tabs'],
|
|
1582
|
-
className: CSS_CLASSES.EMPTY_EDITOR,
|
|
1583
|
-
type: Div
|
|
1584
|
-
}],
|
|
1585
|
-
className: CSS_CLASSES.EDITOR_CONTAINER,
|
|
1586
|
-
type: Div
|
|
1587
|
-
}],
|
|
1588
|
-
className: `${CSS_CLASSES.EDITOR_GROUP} ${group.focused ? CSS_CLASSES.EDITOR_GROUP_FOCUSED : ''}`,
|
|
1589
|
-
type: Div
|
|
1590
|
-
};
|
|
1591
|
-
};
|
|
1592
|
-
const getMainAreaVirtualDom = state => {
|
|
1593
|
-
return [{
|
|
1594
|
-
attributes: {
|
|
1595
|
-
[CSS_ATTRIBUTES.DATA_DIRECTION]: state.layout.direction,
|
|
1596
|
-
style: getThemeStyles('DARK')
|
|
1597
|
-
},
|
|
1598
|
-
childCount: 1,
|
|
1599
|
-
children: [{
|
|
1600
|
-
attributes: {
|
|
1601
|
-
style: state.layout.direction === 'horizontal' ? CSS_STYLES.FLEX_ROW : CSS_STYLES.FLEX_COLUMN
|
|
1602
|
-
},
|
|
1603
|
-
childCount: state.layout.groups.length,
|
|
1604
|
-
children: state.layout.groups.map(renderEditorGroup),
|
|
1605
|
-
className: CSS_CLASSES.EDITOR_GROUPS_CONTAINER,
|
|
1606
|
-
type: Div
|
|
1607
|
-
}],
|
|
1608
|
-
className: CSS_CLASSES.MAIN_AREA,
|
|
1609
|
-
type: Div
|
|
1610
|
-
}];
|
|
1611
|
-
};
|
|
1612
|
-
|
|
1613
|
-
const splitEditorGroup = (state, groupId, direction) => {
|
|
1614
|
-
const sourceGroup = state.layout.groups.find(group => group.id === groupId);
|
|
1615
|
-
if (!sourceGroup) {
|
|
1616
|
-
return state;
|
|
1617
|
-
}
|
|
1618
|
-
const newGroupId = `group-${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;
|
|
1619
|
-
const isHorizontalSplit = direction === 'left' || direction === 'right';
|
|
1620
|
-
const newLayoutDirection = isHorizontalSplit ? 'horizontal' : 'vertical';
|
|
1621
|
-
const updatedGroups = state.layout.groups.map(group => {
|
|
1622
|
-
if (group.id === groupId) {
|
|
1623
|
-
return {
|
|
1624
|
-
...group,
|
|
1625
|
-
focused: false,
|
|
1626
|
-
size: 50
|
|
1627
|
-
};
|
|
1628
|
-
}
|
|
1629
|
-
return group;
|
|
1630
|
-
});
|
|
1631
|
-
const newGroup = {
|
|
1632
|
-
activeTabId: undefined,
|
|
1633
|
-
focused: true,
|
|
1634
|
-
id: newGroupId,
|
|
1635
|
-
size: 50,
|
|
1636
|
-
tabs: []
|
|
1637
|
-
};
|
|
1638
|
-
let reorderedGroups;
|
|
1639
|
-
if (direction === 'right' || direction === 'down') {
|
|
1640
|
-
reorderedGroups = [...updatedGroups, newGroup];
|
|
1641
|
-
} else {
|
|
1642
|
-
const sourceIndex = updatedGroups.findIndex(group => group.id === groupId);
|
|
1643
|
-
reorderedGroups = [...updatedGroups.slice(0, sourceIndex), newGroup, ...updatedGroups.slice(sourceIndex)];
|
|
1644
|
-
}
|
|
1645
|
-
return {
|
|
1646
|
-
...state,
|
|
1647
|
-
layout: {
|
|
1648
|
-
activeGroupId: newGroupId,
|
|
1649
|
-
direction: newLayoutDirection,
|
|
1650
|
-
groups: reorderedGroups
|
|
1651
|
-
}
|
|
1652
|
-
};
|
|
1653
|
-
};
|
|
1654
|
-
|
|
1655
|
-
const switchTab = (state, groupId, tabId) => {
|
|
1656
|
-
const groups = state.layout.groups.map(group => {
|
|
1657
|
-
if (group.id === groupId) {
|
|
1658
|
-
const tabExists = group.tabs.some(tab => tab.id === tabId);
|
|
1659
|
-
if (tabExists) {
|
|
1660
|
-
return {
|
|
1661
|
-
...group,
|
|
1662
|
-
activeTabId: tabId
|
|
1663
|
-
};
|
|
1664
|
-
}
|
|
1665
|
-
}
|
|
1666
|
-
return group;
|
|
1667
|
-
});
|
|
1668
|
-
return {
|
|
1669
|
-
...state,
|
|
1670
|
-
layout: {
|
|
1671
|
-
...state.layout,
|
|
1672
|
-
groups
|
|
1673
|
-
}
|
|
1674
|
-
};
|
|
1675
|
-
};
|
|
1676
|
-
|
|
1677
|
-
const handleMainAreaClick = (state, event) => {
|
|
1678
|
-
const {
|
|
1679
|
-
target
|
|
1680
|
-
} = event;
|
|
1681
|
-
if (!target.dataset) {
|
|
1682
|
-
return state;
|
|
1683
|
-
}
|
|
1684
|
-
const {
|
|
1685
|
-
dataset
|
|
1686
|
-
} = target;
|
|
1687
|
-
|
|
1688
|
-
// Handle tab click
|
|
1689
|
-
if (dataset.tabId) {
|
|
1690
|
-
const {
|
|
1691
|
-
groupId
|
|
1692
|
-
} = dataset;
|
|
1693
|
-
if (groupId) {
|
|
1694
|
-
return switchTab(state, groupId, dataset.tabId);
|
|
1695
|
-
}
|
|
1696
|
-
}
|
|
1697
|
-
|
|
1698
|
-
// Handle tab close button
|
|
1699
|
-
if (dataset.action === 'close-tab' && dataset.tabId) {
|
|
1700
|
-
const {
|
|
1701
|
-
groupId
|
|
1702
|
-
} = dataset;
|
|
1703
|
-
if (groupId) {
|
|
1704
|
-
return closeTab(state, groupId, dataset.tabId);
|
|
1705
|
-
}
|
|
1706
|
-
}
|
|
1707
|
-
|
|
1708
|
-
// Handle editor group focus
|
|
1709
|
-
if (dataset.groupId && !dataset.tabId) {
|
|
1710
|
-
return focusEditorGroup(state, dataset.groupId);
|
|
1711
|
-
}
|
|
1712
|
-
|
|
1713
|
-
// Handle split actions
|
|
1714
|
-
if (dataset.action?.startsWith('split-')) {
|
|
1715
|
-
const {
|
|
1716
|
-
groupId
|
|
1717
|
-
} = dataset;
|
|
1718
|
-
if (groupId) {
|
|
1719
|
-
const direction = dataset.action.replace('split-', '');
|
|
1720
|
-
return splitEditorGroup(state, groupId, direction);
|
|
1721
|
-
}
|
|
1722
|
-
}
|
|
1723
|
-
return state;
|
|
1724
|
-
};
|
|
1725
|
-
|
|
1726
|
-
const handleMainAreaKeyboard = (state, event) => {
|
|
1727
|
-
const {
|
|
1728
|
-
ctrlKey = false,
|
|
1729
|
-
key,
|
|
1730
|
-
metaKey = false,
|
|
1731
|
-
shiftKey = false
|
|
1732
|
-
} = event;
|
|
1733
|
-
const isCtrl = ctrlKey || metaKey;
|
|
1734
|
-
const activeGroup = state.layout.groups.find(group => group.focused);
|
|
1735
|
-
if (!activeGroup) {
|
|
1736
|
-
return state;
|
|
1737
|
-
}
|
|
1738
|
-
|
|
1739
|
-
// Tab navigation
|
|
1740
|
-
if (key === 'Tab' && isCtrl) {
|
|
1741
|
-
const groupIndex = state.layout.groups.findIndex(group => group.id === activeGroup.id);
|
|
1742
|
-
const nextGroupIndex = shiftKey ? (groupIndex - 1 + state.layout.groups.length) % state.layout.groups.length : (groupIndex + 1) % state.layout.groups.length;
|
|
1743
|
-
const nextGroup = state.layout.groups[nextGroupIndex];
|
|
1744
|
-
return focusEditorGroup(state, nextGroup.id);
|
|
1745
|
-
}
|
|
1746
|
-
|
|
1747
|
-
// Switch between tabs within group
|
|
1748
|
-
if (key === 'ArrowLeft' && isCtrl && !shiftKey) {
|
|
1749
|
-
const activeTabIndex = activeGroup.tabs.findIndex(tab => tab.id === activeGroup.activeTabId);
|
|
1750
|
-
if (activeTabIndex > 0) {
|
|
1751
|
-
const prevTab = activeGroup.tabs[activeTabIndex - 1];
|
|
1752
|
-
return switchTab(state, activeGroup.id, prevTab.id);
|
|
1753
|
-
}
|
|
1754
|
-
}
|
|
1755
|
-
if (key === 'ArrowRight' && isCtrl && !shiftKey) {
|
|
1756
|
-
const activeTabIndex = activeGroup.tabs.findIndex(tab => tab.id === activeGroup.activeTabId);
|
|
1757
|
-
if (activeTabIndex < activeGroup.tabs.length - 1) {
|
|
1758
|
-
const nextTab = activeGroup.tabs[activeTabIndex + 1];
|
|
1759
|
-
return switchTab(state, activeGroup.id, nextTab.id);
|
|
1760
|
-
}
|
|
1761
|
-
}
|
|
1762
|
-
|
|
1763
|
-
// Close current tab
|
|
1764
|
-
if (key === 'w' && isCtrl && activeGroup.activeTabId) {
|
|
1765
|
-
return closeTab(state, activeGroup.id, activeGroup.activeTabId);
|
|
1766
|
-
}
|
|
1767
|
-
|
|
1768
|
-
// Split editor
|
|
1769
|
-
if (key === '\\' && isCtrl) {
|
|
1770
|
-
const direction = shiftKey ? 'down' : 'right';
|
|
1771
|
-
return splitEditorGroup(state, activeGroup.id, direction);
|
|
1772
|
-
}
|
|
1773
|
-
return state;
|
|
1774
|
-
};
|
|
1775
|
-
|
|
1776
|
-
const moveTabToGroup = (state, sourceGroupId, targetGroupId, tabId, targetIndex) => {
|
|
1777
|
-
const sourceGroup = state.layout.groups.find(group => group.id === sourceGroupId);
|
|
1778
|
-
const targetGroup = state.layout.groups.find(group => group.id === targetGroupId);
|
|
1779
|
-
if (!sourceGroup || !targetGroup || sourceGroupId === targetGroupId) {
|
|
1780
|
-
return state;
|
|
1781
|
-
}
|
|
1782
|
-
const tabToMove = sourceGroup.tabs.find(tab => tab.id === tabId);
|
|
1783
|
-
if (!tabToMove) {
|
|
1784
|
-
return state;
|
|
1785
|
-
}
|
|
1786
|
-
const updatedGroups = state.layout.groups.map(group => {
|
|
1787
|
-
if (group.id === sourceGroupId) {
|
|
1788
|
-
const newTabs = group.tabs.filter(tab => tab.id !== tabId);
|
|
1789
|
-
let newActiveTabId = group.activeTabId;
|
|
1790
|
-
if (group.activeTabId === tabId) {
|
|
1791
|
-
if (newTabs.length > 0) {
|
|
1792
|
-
const removedIndex = group.tabs.findIndex(tab => tab.id === tabId);
|
|
1793
|
-
newActiveTabId = newTabs[Math.min(removedIndex, newTabs.length - 1)].id;
|
|
1794
|
-
} else {
|
|
1795
|
-
newActiveTabId = undefined;
|
|
1796
|
-
}
|
|
1797
|
-
}
|
|
1798
|
-
return {
|
|
1799
|
-
...group,
|
|
1800
|
-
activeTabId: newActiveTabId,
|
|
1801
|
-
tabs: newTabs
|
|
1802
|
-
};
|
|
1803
|
-
}
|
|
1804
|
-
if (group.id === targetGroupId) {
|
|
1805
|
-
const insertIndex = targetIndex === undefined ? group.tabs.length : targetIndex;
|
|
1806
|
-
const newTabs = [...group.tabs];
|
|
1807
|
-
newTabs.splice(insertIndex, 0, tabToMove);
|
|
1808
|
-
return {
|
|
1809
|
-
...group,
|
|
1810
|
-
activeTabId: tabId,
|
|
1811
|
-
tabs: newTabs
|
|
1812
|
-
};
|
|
1813
|
-
}
|
|
1814
|
-
return group;
|
|
1815
|
-
});
|
|
1816
|
-
return {
|
|
1817
|
-
...state,
|
|
1818
|
-
layout: {
|
|
1819
|
-
...state.layout,
|
|
1820
|
-
activeGroupId: targetGroupId,
|
|
1821
|
-
groups: updatedGroups
|
|
1822
|
-
}
|
|
1823
|
-
};
|
|
1824
|
-
};
|
|
1825
|
-
|
|
1826
|
-
const startTabDrag = (state, tabId, groupId) => {
|
|
1827
|
-
return {
|
|
1828
|
-
dragState: {
|
|
1829
|
-
draggedTabId: tabId,
|
|
1830
|
-
sourceGroupId: groupId
|
|
1831
|
-
},
|
|
1832
|
-
state
|
|
1833
|
-
};
|
|
1834
|
-
};
|
|
1835
|
-
const updateTabDrag = (state, dragState, targetGroupId, targetIndex) => {
|
|
1836
|
-
return {
|
|
1837
|
-
...dragState,
|
|
1838
|
-
targetGroupId,
|
|
1839
|
-
targetIndex
|
|
1840
|
-
};
|
|
1841
|
-
};
|
|
1842
|
-
const endTabDrag = (state, dragState) => {
|
|
1843
|
-
if (dragState.targetGroupId && dragState.targetGroupId !== dragState.sourceGroupId) {
|
|
1844
|
-
return moveTabToGroup(state, dragState.sourceGroupId, dragState.targetGroupId, dragState.draggedTabId, dragState.targetIndex);
|
|
1845
|
-
}
|
|
1846
|
-
return state;
|
|
1847
|
-
};
|
|
1848
|
-
|
|
1849
|
-
const openTab = (state, groupId, tab) => {
|
|
1850
|
-
const newTab = {
|
|
1851
|
-
...tab,
|
|
1852
|
-
id: `tab-${Date.now()}-${Math.random().toString(36).slice(2, 11)}`
|
|
1853
|
-
};
|
|
1854
|
-
const groups = state.layout.groups.map(group => {
|
|
1855
|
-
if (group.id === groupId) {
|
|
1856
|
-
return {
|
|
1857
|
-
...group,
|
|
1858
|
-
activeTabId: newTab.id,
|
|
1859
|
-
tabs: [...group.tabs, newTab]
|
|
1860
|
-
};
|
|
1861
|
-
}
|
|
1862
|
-
return group;
|
|
1863
|
-
});
|
|
1864
|
-
return {
|
|
1865
|
-
...state,
|
|
1866
|
-
layout: {
|
|
1867
|
-
...state.layout,
|
|
1868
|
-
groups
|
|
1869
|
-
}
|
|
1870
|
-
};
|
|
1871
|
-
};
|
|
1872
|
-
|
|
1873
|
-
const restoreMainAreaState = (savedState, currentState) => {
|
|
1874
|
-
try {
|
|
1875
|
-
const parsed = JSON.parse(savedState);
|
|
1876
|
-
return {
|
|
1877
|
-
...currentState,
|
|
1878
|
-
layout: parsed.layout
|
|
1879
|
-
};
|
|
1880
|
-
} catch (error) {
|
|
1881
|
-
console.error('Failed to restore main area state:', error);
|
|
1882
|
-
return currentState;
|
|
1883
|
-
}
|
|
1884
|
-
};
|
|
1885
|
-
|
|
1886
|
-
const saveMainAreaState = state => {
|
|
1887
|
-
return JSON.stringify({
|
|
1888
|
-
layout: state.layout,
|
|
1889
|
-
version: '1.0.0'
|
|
1890
|
-
});
|
|
1891
|
-
};
|
|
1892
|
-
|
|
1893
|
-
const mainAreaCommandMap = {
|
|
1894
|
-
'MainArea.closeEditorGroup': wrapCommand((state, groupId) => closeEditorGroup(state, groupId)),
|
|
1895
|
-
'MainArea.closeTab': wrapCommand((state, groupId, tabId) => closeTab(state, groupId, tabId)),
|
|
1896
|
-
'MainArea.create': () => {},
|
|
1897
|
-
'MainArea.endTabDrag': wrapCommand((state, dragState) => endTabDrag(state, dragState)),
|
|
1898
|
-
'MainArea.focusEditorGroup': wrapCommand((state, groupId) => focusEditorGroup(state, groupId)),
|
|
1899
|
-
'MainArea.getCommandIds': getCommandIds,
|
|
1900
|
-
'MainArea.getVirtualDom': state => getMainAreaVirtualDom(state),
|
|
1901
|
-
'MainArea.handleClick': wrapCommand((state, event) => handleMainAreaClick(state, event)),
|
|
1902
|
-
'MainArea.handleKeyboard': wrapCommand((state, event) => handleMainAreaKeyboard(state, event)),
|
|
1903
|
-
'MainArea.moveTabToGroup': wrapCommand((state, sourceGroupId, targetGroupId, tabId, targetIndex) => moveTabToGroup(state, sourceGroupId, targetGroupId, tabId, targetIndex)),
|
|
1904
|
-
'MainArea.openTab': wrapCommand((state, groupId, tab) => openTab(state, groupId, tab)),
|
|
1905
|
-
'MainArea.restoreState': wrapCommand((state, savedState) => restoreMainAreaState(savedState, state)),
|
|
1906
|
-
'MainArea.saveState': state => saveMainAreaState(state),
|
|
1907
|
-
'MainArea.splitEditorGroup': wrapCommand((state, groupId, direction) => splitEditorGroup(state, groupId, direction)),
|
|
1908
|
-
'MainArea.startTabDrag': (state, tabId, groupId) => startTabDrag(state, tabId, groupId),
|
|
1909
|
-
'MainArea.switchTab': wrapCommand((state, groupId, tabId) => switchTab(state, groupId, tabId)),
|
|
1910
|
-
'MainArea.terminate': terminate,
|
|
1911
|
-
'MainArea.updateTabDrag': (state, dragState, targetGroupId, targetIndex) => updateTabDrag(state, dragState, targetGroupId, targetIndex)
|
|
1912
|
-
};
|
|
1913
|
-
|
|
1914
1746
|
const main$1 = async () => {
|
|
1915
|
-
registerCommands(
|
|
1747
|
+
registerCommands(commandMap);
|
|
1916
1748
|
const rpc = await WebWorkerRpcClient.create({
|
|
1917
|
-
commandMap:
|
|
1749
|
+
commandMap: commandMap
|
|
1918
1750
|
});
|
|
1919
1751
|
set$1(rpc);
|
|
1920
1752
|
};
|