@lvce-editor/source-control-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.
@@ -1051,7 +1051,6 @@ const create2 = (id, uri, x, y, width, height, workspacePath) => {
1051
1051
  untracked: [],
1052
1052
  workingTree: [],
1053
1053
  inputValue: '',
1054
- displayItems: [],
1055
1054
  buttonIndex: -1,
1056
1055
  enabledProviderIds: [],
1057
1056
  isExpanded: true,
@@ -1062,7 +1061,8 @@ const create2 = (id, uri, x, y, width, height, workspacePath) => {
1062
1061
  gitRoot: '',
1063
1062
  itemHeight: 20,
1064
1063
  minimumSliderSize: 20,
1065
- workspacePath
1064
+ workspacePath,
1065
+ headerHeight: 40 // TODO
1066
1066
  };
1067
1067
  set$1(id, state, state);
1068
1068
  };
@@ -1071,7 +1071,7 @@ const RenderItems = 4;
1071
1071
 
1072
1072
  const diffType = RenderItems;
1073
1073
  const isEqual = (oldState, newState) => {
1074
- return oldState.allGroups === newState.allGroups && oldState.displayItems === newState.displayItems && oldState.items === newState.items && oldState.minLineY === newState.minLineY && oldState.maxLineY === newState.maxLineY && oldState.deltaY === newState.deltaY && oldState.buttonIndex === newState.buttonIndex && oldState.buttons === newState.buttons;
1074
+ return oldState.allGroups === newState.allGroups && oldState.items === newState.items && oldState.items === newState.items && oldState.minLineY === newState.minLineY && oldState.maxLineY === newState.maxLineY && oldState.deltaY === newState.deltaY && oldState.buttonIndex === newState.buttonIndex && oldState.buttons === newState.buttons;
1075
1075
  };
1076
1076
 
1077
1077
  const modules = [isEqual];
@@ -1097,7 +1097,7 @@ const diff2 = uid => {
1097
1097
  return result;
1098
1098
  };
1099
1099
 
1100
- const commandIds = ['acceptInput', 'focus', 'focusFirst', 'focusIndex', 'focusLast', 'focusNext', 'focusNone', 'focusPrevious', 'handleClick', 'handleClickAt', 'handleIconThemeChange', 'handleWheel'];
1100
+ const commandIds = ['acceptInput', 'handleMouseOut', 'focus', 'focusFirst', 'handleFocus', 'focusIndex', 'focusLast', 'focusNext', 'focusNone', 'focusPrevious', 'handleClick', 'handleClickAt', 'handleIconThemeChange', 'handleMouseOver', 'handleWheel', 'selectIndex', 'handleMouseOverAt'];
1101
1101
 
1102
1102
  const getCommandIds = () => {
1103
1103
  return commandIds;
@@ -1147,6 +1147,7 @@ const executeProvider = async ({
1147
1147
 
1148
1148
  const CommandExecute = 'ExtensionHostCommand.executeCommand';
1149
1149
  const SourceControlGetEnabledProviderIds = 'ExtensionHostSourceControl.getEnabledProviderIds';
1150
+ const SourceControlGetFileBefore = 'ExtensionHostSourceControl.GetFileBefore';
1150
1151
  const SourceControlGetGroups = 'ExtensionHostSourceControl.getGroups';
1151
1152
 
1152
1153
  const executeCommand = (id, ...args) => {
@@ -1161,7 +1162,7 @@ const Directory = 3;
1161
1162
  const DirectoryExpanded = 4;
1162
1163
  const File = 7;
1163
1164
 
1164
- const getFileIcon = ({
1165
+ const getFileIcon$1 = ({
1165
1166
  name
1166
1167
  }) => {
1167
1168
  return '';
@@ -1183,8 +1184,8 @@ const getDisplayItemsGroup = (group, isExpanded) => {
1183
1184
  throw new Error('Source control group is missing an items property');
1184
1185
  }
1185
1186
  const length = items.length;
1186
- const type = DirectoryExpanded ;
1187
- const icon = 'ChevronDown' ;
1187
+ const type = isExpanded ? DirectoryExpanded : Directory;
1188
+ const icon = isExpanded ? 'ChevronDown' : 'ChevronRight';
1188
1189
  if (length > 0) {
1189
1190
  displayItems.push({
1190
1191
  file: '',
@@ -1201,7 +1202,7 @@ const getDisplayItemsGroup = (group, isExpanded) => {
1201
1202
  groupId: id
1202
1203
  });
1203
1204
  }
1204
- {
1205
+ if (isExpanded) {
1205
1206
  for (let i = 0; i < length; i++) {
1206
1207
  const item = items[i];
1207
1208
  const {
@@ -1218,7 +1219,7 @@ const getDisplayItemsGroup = (group, isExpanded) => {
1218
1219
  detail: folderName,
1219
1220
  posInSet: i + 1,
1220
1221
  setSize: length,
1221
- icon: getFileIcon({
1222
+ icon: getFileIcon$1({
1222
1223
  name: file
1223
1224
  }),
1224
1225
  decorationIcon: icon,
@@ -1232,21 +1233,142 @@ const getDisplayItemsGroup = (group, isExpanded) => {
1232
1233
  }
1233
1234
  return displayItems;
1234
1235
  };
1236
+
1235
1237
  const getDisplayItems = (allGroups, isExpanded) => {
1236
1238
  const displayItems = [];
1237
1239
  for (const group of allGroups) {
1238
- const groupDisplayItems = getDisplayItemsGroup(group);
1240
+ const groupDisplayItems = getDisplayItemsGroup(group, isExpanded);
1239
1241
  displayItems.push(...groupDisplayItems);
1240
1242
  }
1241
1243
  return displayItems;
1242
1244
  };
1243
1245
 
1246
+ const getIconsCached = (dirents, fileIconCache) => {
1247
+ return dirents.map(dirent => fileIconCache[dirent]);
1248
+ };
1249
+
1250
+ const getMissingIconRequests = (dirents, fileIconCache) => {
1251
+ const missingRequests = [];
1252
+ for (const dirent of dirents) {
1253
+ if (!(dirent.file in fileIconCache)) {
1254
+ missingRequests.push({
1255
+ type: dirent.type,
1256
+ name: dirent.label,
1257
+ path: dirent.file
1258
+ });
1259
+ }
1260
+ }
1261
+ return missingRequests;
1262
+ };
1263
+
1264
+ const getPath = item => {
1265
+ return item.file;
1266
+ };
1267
+
1268
+ const getPaths = items => {
1269
+ return items.map(getPath);
1270
+ };
1271
+
1272
+ const getFileIcon = async name => {
1273
+ return invoke$1('IconTheme.getFileIcon', {
1274
+ name
1275
+ });
1276
+ };
1277
+
1278
+ const getFolderIcon = async name => {
1279
+ return invoke$1('IconTheme.getFolderIcon', {
1280
+ name
1281
+ });
1282
+ };
1283
+
1284
+ const requestFileIcons = async requests => {
1285
+ const promises = requests.map(request => request.type === File ? getFileIcon(request.name) : getFolderIcon(request.name));
1286
+ return Promise.all(promises);
1287
+ };
1288
+
1289
+ const updateIconCache = (iconCache, missingRequests, newIcons) => {
1290
+ if (missingRequests.length === 0) {
1291
+ return iconCache;
1292
+ }
1293
+ const newFileIconCache = {
1294
+ ...iconCache
1295
+ };
1296
+ for (let i = 0; i < missingRequests.length; i++) {
1297
+ const request = missingRequests[i];
1298
+ const icon = newIcons[i];
1299
+ newFileIconCache[request.path] = icon;
1300
+ }
1301
+ return newFileIconCache;
1302
+ };
1303
+
1304
+ const getFileIcons = async (dirents, fileIconCache) => {
1305
+ const missingRequests = getMissingIconRequests(dirents, fileIconCache);
1306
+ const newIcons = await requestFileIcons(missingRequests);
1307
+ const newFileIconCache = updateIconCache(fileIconCache, missingRequests, newIcons);
1308
+ const paths = getPaths(dirents);
1309
+ const icons = getIconsCached(paths, newFileIconCache);
1310
+ return {
1311
+ icons,
1312
+ newFileIconCache
1313
+ };
1314
+ };
1315
+
1244
1316
  const getFinalDeltaY = (height, itemHeight, itemsLength) => {
1245
1317
  const contentHeight = itemsLength * itemHeight;
1246
1318
  const finalDeltaY = Math.max(contentHeight - height, 0);
1247
1319
  return finalDeltaY;
1248
1320
  };
1249
1321
 
1322
+ const getFileBefore$1 = (providerId, path) => {
1323
+ return executeProvider({
1324
+ event: 'none',
1325
+ method: SourceControlGetFileBefore,
1326
+ params: [providerId, path]
1327
+ // noProviderFoundMessage: 'No source control provider found',
1328
+ });
1329
+ };
1330
+ const getGroups$2 = (providerId, path) => {
1331
+ return executeProvider({
1332
+ event: 'none',
1333
+ method: SourceControlGetGroups,
1334
+ params: [providerId, path]
1335
+ // noProviderFoundMessage: 'No source control provider found',
1336
+ });
1337
+ };
1338
+ const getEnabledProviderIds$1 = (scheme, root) => {
1339
+ return executeProvider({
1340
+ event: `onSourceControl:${scheme}`,
1341
+ method: SourceControlGetEnabledProviderIds,
1342
+ params: [scheme, root]
1343
+ // noProviderFoundMessage: 'No source control provider found',
1344
+ });
1345
+ };
1346
+
1347
+ const getFileBefore = (providerId, file) => {
1348
+ return getFileBefore$1(providerId, file);
1349
+ };
1350
+ const getEnabledProviderIds = (scheme, root) => {
1351
+ string(scheme);
1352
+ string(root);
1353
+ return getEnabledProviderIds$1(scheme, root);
1354
+ };
1355
+ const getGroups$1 = (providerId, root) => {
1356
+ return getGroups$2(providerId, root);
1357
+ };
1358
+
1359
+ const getGroups = async enabledProviderIds => {
1360
+ const allGroups = [];
1361
+ for (const providerId of enabledProviderIds) {
1362
+ // @ts-ignore
1363
+ const groups = await getGroups$1(providerId);
1364
+ allGroups.push(...groups);
1365
+ }
1366
+ return {
1367
+ allGroups,
1368
+ gitRoot: ''
1369
+ };
1370
+ };
1371
+
1250
1372
  const getListHeight = (itemsLength, itemHeight, maxHeight) => {
1251
1373
  number(itemsLength);
1252
1374
  number(itemHeight);
@@ -1290,32 +1412,6 @@ const getScrollBarSize = (size, contentSize, minimumSliderSize) => {
1290
1412
  return Math.max(Math.round(size ** 2 / contentSize), minimumSliderSize);
1291
1413
  };
1292
1414
 
1293
- const getGroups$2 = (providerId, path) => {
1294
- return executeProvider({
1295
- event: 'none',
1296
- method: SourceControlGetGroups,
1297
- params: [providerId, path]
1298
- // noProviderFoundMessage: 'No source control provider found',
1299
- });
1300
- };
1301
- const getEnabledProviderIds$1 = (scheme, root) => {
1302
- return executeProvider({
1303
- event: `onSourceControl:${scheme}`,
1304
- method: SourceControlGetEnabledProviderIds,
1305
- params: [scheme, root]
1306
- // noProviderFoundMessage: 'No source control provider found',
1307
- });
1308
- };
1309
-
1310
- const getEnabledProviderIds = (scheme, root) => {
1311
- string(scheme);
1312
- string(root);
1313
- return getEnabledProviderIds$1(scheme, root);
1314
- };
1315
- const getGroups$1 = (providerId, root) => {
1316
- return getGroups$2(providerId, root);
1317
- };
1318
-
1319
1415
  const getExtensions = async () => {
1320
1416
  return invoke('Extensions.getExtensions');
1321
1417
  };
@@ -1350,18 +1446,6 @@ const getSourceControlActions = async (providerId, groupId, type) => {
1350
1446
  return value;
1351
1447
  };
1352
1448
 
1353
- const getGroups = async enabledProviderIds => {
1354
- const allGroups = [];
1355
- for (const providerId of enabledProviderIds) {
1356
- // @ts-ignore
1357
- const groups = await getGroups$1(providerId);
1358
- allGroups.push(...groups);
1359
- }
1360
- return {
1361
- allGroups,
1362
- gitRoot: ''
1363
- };
1364
- };
1365
1449
  const getNewButtons = async (displayItems, providerId, buttonIndex) => {
1366
1450
  if (buttonIndex === -1) {
1367
1451
  return [];
@@ -1378,7 +1462,8 @@ const loadContent = async state => {
1378
1462
  itemHeight,
1379
1463
  height,
1380
1464
  minimumSliderSize,
1381
- workspacePath
1465
+ workspacePath,
1466
+ fileIconCache
1382
1467
  } = state;
1383
1468
  const root = workspacePath;
1384
1469
  const scheme = getProtocol(root);
@@ -1388,7 +1473,7 @@ const loadContent = async state => {
1388
1473
  gitRoot
1389
1474
  } = await getGroups(enabledProviderIds);
1390
1475
  const isExpanded = true;
1391
- const items = getDisplayItems(allGroups);
1476
+ const items = getDisplayItems(allGroups, isExpanded);
1392
1477
  const buttons = await getNewButtons(items, state.providerId, state.buttonIndex);
1393
1478
  const splitButtonEnabled = get();
1394
1479
  const total = items.length;
@@ -1398,6 +1483,10 @@ const loadContent = async state => {
1398
1483
  const numberOfVisible = getNumberOfVisibleItems(listHeight, itemHeight);
1399
1484
  const maxLineY = Math.min(numberOfVisible, total);
1400
1485
  const finalDeltaY = getFinalDeltaY(listHeight, itemHeight, total);
1486
+ const {
1487
+ icons,
1488
+ newFileIconCache
1489
+ } = await getFileIcons(items, fileIconCache);
1401
1490
  return {
1402
1491
  ...state,
1403
1492
  allGroups,
@@ -1410,7 +1499,9 @@ const loadContent = async state => {
1410
1499
  splitButtonEnabled,
1411
1500
  maxLineY,
1412
1501
  scrollBarHeight,
1413
- finalDeltaY
1502
+ finalDeltaY,
1503
+ icons,
1504
+ fileIconCache: newFileIconCache
1414
1505
  };
1415
1506
  };
1416
1507
 
@@ -1430,17 +1521,134 @@ const handleButtonClick = async (state, clickedIndex) => {
1430
1521
  return newState;
1431
1522
  };
1432
1523
 
1524
+ const getIndex = (state, eventX, eventY) => {
1525
+ const {
1526
+ headerHeight,
1527
+ y,
1528
+ itemHeight
1529
+ } = state;
1530
+ const relativeY = eventY - y - headerHeight;
1531
+ const index = Math.floor(relativeY / itemHeight);
1532
+ return index;
1533
+ };
1534
+
1535
+ const handleClickDirectory = async (state, item) => {
1536
+ const {
1537
+ allGroups
1538
+ } = state;
1539
+ const isExpanded = true;
1540
+ const displayItems = getDisplayItems(allGroups, isExpanded);
1541
+ const newMaxLineY = displayItems.length;
1542
+ return {
1543
+ ...state,
1544
+ items: displayItems,
1545
+ isExpanded,
1546
+ maxLineY: newMaxLineY
1547
+ };
1548
+ };
1549
+
1550
+ const handleClickDirectoryExpanded = async (state, item) => {
1551
+ const {
1552
+ allGroups,
1553
+ maxLineY
1554
+ } = state;
1555
+ const isExpanded = false;
1556
+ const displayItems = getDisplayItems(allGroups, isExpanded);
1557
+ const newMaxLineY = Math.min(displayItems.length, maxLineY);
1558
+ return {
1559
+ ...state,
1560
+ items: displayItems,
1561
+ isExpanded,
1562
+ maxLineY: newMaxLineY
1563
+ };
1564
+ };
1565
+
1566
+ const readFile = async (uri, encoding = 'utf8') => {
1567
+ const content = await invoke$1('FileSystem.readFile', uri);
1568
+ return content;
1569
+ };
1570
+
1571
+ const openUri = uri => {
1572
+ return invoke$1('Main.openUri', uri);
1573
+ };
1574
+
1575
+ const handleClickFile = async (state, item) => {
1576
+ const {
1577
+ enabledProviderIds,
1578
+ root
1579
+ } = state;
1580
+ const providerId = enabledProviderIds[0];
1581
+ const absolutePath = `${root}/${item.file}`;
1582
+ // TODO handle error
1583
+ const [fileBefore] = await Promise.all([getFileBefore(providerId, item.file), readFile(absolutePath)]);
1584
+ {
1585
+ await openUri(`inline-diff://data://${fileBefore}<->${absolutePath}`);
1586
+ }
1587
+ return state;
1588
+ };
1589
+
1590
+ const selectIndex = async (state, index) => {
1591
+ const {
1592
+ items
1593
+ } = state;
1594
+ if (index < 0 || index >= items.length) {
1595
+ return state;
1596
+ }
1597
+ const item = items[index];
1598
+ switch (item.type) {
1599
+ case Directory:
1600
+ return handleClickDirectory(state);
1601
+ case DirectoryExpanded:
1602
+ return handleClickDirectoryExpanded(state);
1603
+ case File:
1604
+ return handleClickFile(state, item);
1605
+ default:
1606
+ console.warn(`unknown item type: ${item.type}`);
1607
+ return state;
1608
+ }
1609
+ };
1610
+
1611
+ const handleClickAt = async (state, eventX, eventY) => {
1612
+ const index = getIndex(state, eventX, eventY);
1613
+ return selectIndex(state, index);
1614
+ };
1615
+
1433
1616
  const show = async (x, y, id, ...args) => {
1434
1617
  return invoke$1('ContextMenu.show', x, y, id, ...args);
1435
1618
  };
1436
1619
 
1437
- const SourceControl = 22;
1620
+ const SourceControl$1 = 22;
1438
1621
 
1439
1622
  const handleContextMenu = async (state, button, x, y) => {
1440
- await show(x, y, SourceControl);
1623
+ await show(x, y, SourceControl$1);
1624
+ return state;
1625
+ };
1626
+
1627
+ const handleFocus = async state => {
1441
1628
  return state;
1442
1629
  };
1443
1630
 
1631
+ const handleMouseOver = async (state, index) => {
1632
+ const {
1633
+ items,
1634
+ providerId,
1635
+ buttonIndex
1636
+ } = state;
1637
+ if (index === buttonIndex) {
1638
+ return state;
1639
+ }
1640
+ const item = items[index];
1641
+ if (!item) {
1642
+ return state;
1643
+ }
1644
+ const actions = await getSourceControlActions(providerId, item.groupId, item.type);
1645
+ return {
1646
+ ...state,
1647
+ buttonIndex: index,
1648
+ buttons: actions
1649
+ };
1650
+ };
1651
+
1444
1652
  const getPortTuple = () => {
1445
1653
  const {
1446
1654
  port1,
@@ -1482,17 +1690,6 @@ const initialize = async () => {
1482
1690
  set(ExtensionHostWorker, extensionHostRpc);
1483
1691
  };
1484
1692
 
1485
- const HandleClick = 'handleClick';
1486
- const HandleContextMenu = 'handleContextMenu';
1487
- const HandleMouseOut = 'handleMouseOut';
1488
- const HandleMouseOver = 'handleMouseOver';
1489
- const HandleWheel = 'handleWheel';
1490
-
1491
- const None = 'none';
1492
- const ToolBar = 'toolbar';
1493
- const Tree = 'tree';
1494
- const TreeItem$1 = 'treeitem';
1495
-
1496
1693
  const Actions = 'Actions';
1497
1694
  const Chevron = 'Chevron';
1498
1695
  const ChevronRight = 'ChevronRight';
@@ -1504,6 +1701,7 @@ const Label = 'Label';
1504
1701
  const LabelDetail = 'LabelDetail';
1505
1702
  const MaskIcon = 'MaskIcon';
1506
1703
  const MaskIconChevronDown = 'MaskIconChevronDown';
1704
+ const SourceControl = 'SourceControl';
1507
1705
  const SourceControlBadge = 'SourceControlBadge';
1508
1706
  const SourceControlButton = 'SourceControlButton';
1509
1707
  const SourceControlHeader = 'SourceControlHeader';
@@ -1516,9 +1714,41 @@ const SplitButtonDropDown = 'SplitButtonDropDown';
1516
1714
  const SplitButtonDropDownDisabled = 'SplitButtonDropDownDisabled';
1517
1715
  const SplitButtonSeparator = 'SplitButtonSeparator';
1518
1716
  const StrikeThrough = 'StrikeThrough';
1519
- const TreeItem = 'TreeItem';
1717
+ const TreeItem$1 = 'TreeItem';
1718
+ const Viewlet = 'Viewlet';
1520
1719
 
1521
- const emptySourceControlButtons = [];
1720
+ const HandleClickAt = 'handleClickAt';
1721
+ const HandleContextMenu = 'handleContextMenu';
1722
+ const HandleFocus = 'handleFocus';
1723
+ const HandleInput = 'handleInput';
1724
+ const HandleMouseOut = 'handleMouseOut';
1725
+ const HandleMouseOver = 'handleMouseOver';
1726
+ const HandleMouseOverAt = 'handleMouseOverAt';
1727
+ const HandleWheel = 'handleWheel';
1728
+
1729
+ const SourceControlInput$1 = 'SourceControlInput';
1730
+
1731
+ const emptyObject = {};
1732
+ const RE_PLACEHOLDER = /\{(PH\d+)\}/g;
1733
+ const i18nString = (key, placeholders = emptyObject) => {
1734
+ if (placeholders === emptyObject) {
1735
+ return key;
1736
+ }
1737
+ const replacer = (match, rest) => {
1738
+ return placeholders[rest];
1739
+ };
1740
+ return key.replaceAll(RE_PLACEHOLDER, replacer);
1741
+ };
1742
+
1743
+ const MessageEnterToCommitOnMaster = `Message (Enter) to commit on 'master'`;
1744
+ const SourceControlInput = 'Source Control Input';
1745
+
1746
+ const messageEnterToCommitOnMaster = () => {
1747
+ return i18nString(MessageEnterToCommitOnMaster);
1748
+ };
1749
+ const sourceControlInput = () => {
1750
+ return i18nString(SourceControlInput);
1751
+ };
1522
1752
 
1523
1753
  const Button$1 = 1;
1524
1754
  const Div = 4;
@@ -1526,32 +1756,32 @@ const Input = 6;
1526
1756
  const Span = 8;
1527
1757
  const Img = 17;
1528
1758
 
1529
- const Text = 12;
1530
- const text = data => {
1531
- return {
1532
- type: Text,
1533
- text: data,
1534
- childCount: 0
1535
- };
1536
- };
1537
-
1538
- const getBadgeVirtualDom = (className, count) => {
1759
+ const getSourceControlHeaderVirtualDom = () => {
1539
1760
  return [{
1540
1761
  type: Div,
1541
- className: `Badge ${className}`,
1762
+ className: SourceControlHeader,
1542
1763
  childCount: 1
1543
- }, text(`${count}`)];
1764
+ }, {
1765
+ type: Input,
1766
+ className: InputBox,
1767
+ ariaLabel: sourceControlInput(),
1768
+ autocapitalize: 'off',
1769
+ autocorrect: 'off',
1770
+ childCount: 0,
1771
+ name: SourceControlInput$1,
1772
+ onFocus: HandleFocus,
1773
+ onInput: HandleInput,
1774
+ placeholder: messageEnterToCommitOnMaster(),
1775
+ spellcheck: false
1776
+ }];
1544
1777
  };
1545
1778
 
1546
- const getFileIconVirtualDom = icon => {
1547
- return {
1548
- type: Img,
1549
- className: FileIcon,
1550
- src: icon,
1551
- role: None,
1552
- childCount: 0
1553
- };
1554
- };
1779
+ const None = 'none';
1780
+ const ToolBar = 'toolbar';
1781
+ const Tree = 'tree';
1782
+ const TreeItem = 'treeitem';
1783
+
1784
+ const emptySourceControlButtons = [];
1555
1785
 
1556
1786
  const getIconVirtualDom = (icon, type = Div) => {
1557
1787
  return {
@@ -1562,16 +1792,6 @@ const getIconVirtualDom = (icon, type = Div) => {
1562
1792
  };
1563
1793
  };
1564
1794
 
1565
- const PaddingLeft = '1rem';
1566
- const PaddingRight = '12px';
1567
-
1568
- const getLabelClassName = decorationStrikeThrough => {
1569
- let className = Label + ' Grow';
1570
- if (decorationStrikeThrough) {
1571
- className += ` ${StrikeThrough}`;
1572
- }
1573
- return className;
1574
- };
1575
1795
  const addButtons = (dom, buttons) => {
1576
1796
  if (buttons === emptySourceControlButtons) {
1577
1797
  return;
@@ -1591,6 +1811,38 @@ const addButtons = (dom, buttons) => {
1591
1811
  }, getIconVirtualDom(icon, Span));
1592
1812
  }
1593
1813
  };
1814
+
1815
+ const mergeClassNames = (...classNames) => {
1816
+ return classNames.filter(Boolean).join(' ');
1817
+ };
1818
+ const Text = 12;
1819
+ const text = data => {
1820
+ return {
1821
+ type: Text,
1822
+ text: data,
1823
+ childCount: 0
1824
+ };
1825
+ };
1826
+
1827
+ const getBadgeVirtualDom = (className, count) => {
1828
+ return [{
1829
+ type: Div,
1830
+ className: `Badge ${className}`,
1831
+ childCount: 1
1832
+ }, text(`${count}`)];
1833
+ };
1834
+
1835
+ const getLabelClassName = decorationStrikeThrough => {
1836
+ let className = Label + ' Grow';
1837
+ if (decorationStrikeThrough) {
1838
+ className += ` ${StrikeThrough}`;
1839
+ }
1840
+ return className;
1841
+ };
1842
+
1843
+ const PaddingLeft = '1rem';
1844
+ const PaddingRight = '12px';
1845
+
1594
1846
  const createItemDirectory = item => {
1595
1847
  const {
1596
1848
  posInSet,
@@ -1605,8 +1857,8 @@ const createItemDirectory = item => {
1605
1857
  const labelClassName = getLabelClassName(decorationStrikeThrough);
1606
1858
  const dom = [{
1607
1859
  type: Div,
1608
- className: TreeItem,
1609
- role: TreeItem$1,
1860
+ className: TreeItem$1,
1861
+ role: TreeItem,
1610
1862
  ariaExpanded: type === DirectoryExpanded,
1611
1863
  ariaPosInSet: posInSet,
1612
1864
  ariaSetSize: setSize,
@@ -1626,6 +1878,28 @@ const createItemDirectory = item => {
1626
1878
  dom.push(...getBadgeVirtualDom(SourceControlBadge, badgeCount));
1627
1879
  return dom;
1628
1880
  };
1881
+
1882
+ const getFileIconVirtualDom = icon => {
1883
+ return {
1884
+ type: Img,
1885
+ className: FileIcon,
1886
+ src: icon,
1887
+ role: None,
1888
+ childCount: 0
1889
+ };
1890
+ };
1891
+
1892
+ const chevron = {
1893
+ type: Div,
1894
+ className: Chevron,
1895
+ childCount: 1
1896
+ };
1897
+ const getIconsDom = (icon, fileIcon) => {
1898
+ if (icon === ChevronRight) {
1899
+ return [chevron, getIconVirtualDom(icon)];
1900
+ }
1901
+ return [getFileIconVirtualDom(fileIcon)];
1902
+ };
1629
1903
  const createItemOther = item => {
1630
1904
  const {
1631
1905
  posInSet,
@@ -1637,28 +1911,22 @@ const createItemOther = item => {
1637
1911
  decorationIconTitle,
1638
1912
  decorationStrikeThrough,
1639
1913
  detail,
1640
- buttons
1914
+ buttons,
1915
+ fileIcon
1641
1916
  } = item;
1642
1917
  const labelClassName = getLabelClassName(decorationStrikeThrough);
1643
- /**
1644
- * @type {any[]}
1645
- */
1646
1918
  const dom = [];
1647
1919
  dom.push({
1648
1920
  type: Div,
1649
- className: TreeItem,
1650
- role: TreeItem$1,
1921
+ className: TreeItem$1,
1922
+ role: TreeItem,
1651
1923
  ariaPosInSet: posInSet,
1652
1924
  ariaSetSize: setSize,
1653
1925
  title: file,
1654
1926
  childCount: 3,
1655
1927
  paddingLeft: '1rem',
1656
1928
  paddingRight: '12px'
1657
- }, ...(icon === ChevronRight ? [{
1658
- type: Div,
1659
- className: Chevron,
1660
- childCount: 1
1661
- }, getIconVirtualDom(icon)] : [getFileIconVirtualDom(icon)]));
1929
+ }, ...getIconsDom(icon, fileIcon));
1662
1930
  const labelDom = {
1663
1931
  type: Div,
1664
1932
  className: labelClassName,
@@ -1683,6 +1951,7 @@ const createItemOther = item => {
1683
1951
  });
1684
1952
  return dom;
1685
1953
  };
1954
+
1686
1955
  const getSourceControlItemVirtualDom = item => {
1687
1956
  switch (item.type) {
1688
1957
  case DirectoryExpanded:
@@ -1693,9 +1962,21 @@ const getSourceControlItemVirtualDom = item => {
1693
1962
  }
1694
1963
  };
1695
1964
 
1696
- const getSourceControlItemsVirtualDom$1 = (hasItems, buttonText) => {
1697
- const dom = [];
1698
- dom.push({
1965
+ const getSourceControlListVirtualDom = items => {
1966
+ return [{
1967
+ type: Div,
1968
+ className: SourceControlItems,
1969
+ role: Tree,
1970
+ childCount: items.length,
1971
+ onClick: HandleClickAt
1972
+ }, ...items.flatMap(getSourceControlItemVirtualDom)];
1973
+ };
1974
+
1975
+ const getSplitButtonVirtualDom = (hasItems, splitButtonEnabled, buttonText) => {
1976
+ if (!splitButtonEnabled || !hasItems) {
1977
+ return [];
1978
+ }
1979
+ return [{
1699
1980
  type: Div,
1700
1981
  className: `${SplitButton} ${hasItems ? '' : SplitButtonDisabled}`,
1701
1982
  childCount: 3
@@ -1717,93 +1998,41 @@ const getSourceControlItemsVirtualDom$1 = (hasItems, buttonText) => {
1717
1998
  type: Div,
1718
1999
  className: `${MaskIcon} ${MaskIconChevronDown}`,
1719
2000
  childCount: 0
1720
- });
1721
- return dom;
1722
- };
1723
-
1724
- const emptyObject = {};
1725
- const RE_PLACEHOLDER = /\{(PH\d+)\}/g;
1726
- const i18nString = (key, placeholders = emptyObject) => {
1727
- if (placeholders === emptyObject) {
1728
- return key;
1729
- }
1730
- const replacer = (match, rest) => {
1731
- return placeholders[rest];
1732
- };
1733
- return key.replaceAll(RE_PLACEHOLDER, replacer);
1734
- };
1735
-
1736
- const MessageEnterToCommitOnMaster = `Message (Enter) to commit on 'master'`;
1737
- const SourceControlInput = 'Source Control Input';
1738
-
1739
- const messageEnterToCommitOnMaster = () => {
1740
- return i18nString(MessageEnterToCommitOnMaster);
1741
- };
1742
- const sourceControlInput = () => {
1743
- return i18nString(SourceControlInput);
1744
- };
1745
-
1746
- const getSourceControlItemsVirtualDom = (items, splitButtonEnabled) => {
1747
- const dom = [];
1748
- dom.push({
1749
- type: Div,
1750
- className: SourceControlHeader,
1751
- childCount: 1
1752
- }, {
1753
- type: Input,
1754
- className: InputBox,
1755
- spellcheck: false,
1756
- autocapitalize: 'off',
1757
- autocorrect: 'off',
1758
- placeholder: messageEnterToCommitOnMaster(),
1759
- ariaLabel: sourceControlInput(),
1760
- childCount: 0,
1761
- onInput: 'handleInput',
1762
- onFocus: 'handleFocus'
1763
- });
1764
- if (splitButtonEnabled) {
1765
- const hasItems = items.length > 0;
1766
- dom.push(...getSourceControlItemsVirtualDom$1(hasItems, 'Commit'));
1767
- }
1768
- dom.push({
1769
- type: Div,
1770
- className: SourceControlItems,
1771
- role: Tree,
1772
- childCount: items.length
1773
- }, ...items.flatMap(getSourceControlItemVirtualDom));
1774
- return dom;
2001
+ }];
1775
2002
  };
1776
2003
 
1777
2004
  const getSourceControlVirtualDom = (items, splitButtonEnabled) => {
2005
+ const hasItems = items.length > 0;
1778
2006
  const dom = [{
1779
2007
  type: Div,
1780
- className: 'Viewlet SourceControl',
2008
+ className: mergeClassNames(Viewlet, SourceControl),
1781
2009
  tabIndex: 0,
1782
- onClick: HandleClick,
1783
2010
  onContextMenu: HandleContextMenu,
1784
2011
  onMouseOver: HandleMouseOver,
1785
2012
  onMouseOut: HandleMouseOut,
1786
2013
  onWheel: HandleWheel,
1787
2014
  childCount: splitButtonEnabled ? 3 : 2
1788
- }, ...getSourceControlItemsVirtualDom(items, splitButtonEnabled)];
2015
+ }, ...getSourceControlHeaderVirtualDom(), ...getSplitButtonVirtualDom(hasItems, splitButtonEnabled, 'Commit'), ...getSourceControlListVirtualDom(items)];
1789
2016
  return dom;
1790
2017
  };
1791
2018
 
1792
- const getVisibleSourceControlItems = (items, minLineY, maxLineY, buttons, buttonIndex) => {
2019
+ const getVisibleSourceControlItems = (items, minLineY, maxLineY, buttons, buttonIndex, icons) => {
1793
2020
  const visible = [];
1794
2021
  for (let i = minLineY; i < maxLineY; i++) {
1795
2022
  const item = items[i];
1796
2023
  const itemButtons = i === buttonIndex ? buttons : emptySourceControlButtons;
2024
+ const fileIcon = icons[i - minLineY];
1797
2025
  visible.push({
1798
2026
  ...item,
1799
- buttons: itemButtons
2027
+ buttons: itemButtons,
2028
+ fileIcon
1800
2029
  });
1801
2030
  }
1802
2031
  return visible;
1803
2032
  };
1804
2033
 
1805
2034
  const renderItems = (oldState, newState) => {
1806
- const visible = getVisibleSourceControlItems(newState.items, newState.minLineY, newState.maxLineY, newState.buttons, newState.buttonIndex);
2035
+ const visible = getVisibleSourceControlItems(newState.items, newState.minLineY, newState.maxLineY, newState.buttons, newState.buttonIndex, newState.icons);
1807
2036
  const dom = getSourceControlVirtualDom(visible, newState.splitButtonEnabled);
1808
2037
  return ['Viewlet.setDom2', dom];
1809
2038
  };
@@ -1885,6 +2114,29 @@ const renderEventListeners = () => {
1885
2114
  name: HandleWheel,
1886
2115
  params: ['handleWheel', 'event.deltaMode', 'event.deltaY'],
1887
2116
  passive: true
2117
+ }, {
2118
+ name: HandleFocus,
2119
+ params: ['handleFocus']
2120
+ }, {
2121
+ name: HandleClickAt,
2122
+ params: ['handleClickAt', 'event.clientX', 'event.clientY']
2123
+ }, {
2124
+ name: HandleMouseOverAt,
2125
+ params: ['handleMouseOverAt', 'event.clientX', 'event.clientY']
2126
+ }, {
2127
+ name: HandleMouseOver,
2128
+ params: ['handleMouseOver', 'event.clientX', 'event.clientY']
2129
+ }, {
2130
+ name: HandleInput,
2131
+ params: ['handleInput', 'event.target.value']
2132
+ }, {
2133
+ name: HandleContextMenu,
2134
+ params: ['handleContextMenu', 'event.button', 'event.clientX', 'event.clientY'],
2135
+ preventDefault: true
2136
+ }, {
2137
+ name: HandleWheel,
2138
+ params: ['handleWheel', 'event.deltaMode', 'event.deltaY'],
2139
+ passive: true
1888
2140
  }];
1889
2141
  };
1890
2142
 
@@ -1910,19 +2162,42 @@ const terminate = () => {
1910
2162
  globalThis.close();
1911
2163
  };
1912
2164
 
2165
+ const updateIcons = async state => {
2166
+ const {
2167
+ items,
2168
+ minLineY,
2169
+ maxLineY
2170
+ } = state;
2171
+ const visible = items.slice(minLineY, maxLineY);
2172
+ const {
2173
+ icons,
2174
+ newFileIconCache
2175
+ } = await getFileIcons(visible, Object.create(null));
2176
+ return {
2177
+ ...state,
2178
+ icons,
2179
+ fileIconCache: newFileIconCache
2180
+ };
2181
+ };
2182
+
1913
2183
  const commandMap = {
1914
2184
  'Initialize.initialize': initialize,
1915
2185
  'SourceControl.create2': create2,
1916
2186
  'SourceControl.diff2': diff2,
1917
2187
  'SourceControl.getCommandIds': getCommandIds,
1918
2188
  'SourceControl.handleButtonClick': wrapCommand(handleButtonClick),
2189
+ 'SourceControl.handleClickAt': wrapCommand(handleClickAt),
1919
2190
  'SourceControl.handleContextMenu': wrapCommand(handleContextMenu),
2191
+ 'SourceControl.handleMouseOver': wrapCommand(handleMouseOver),
1920
2192
  'SourceControl.loadContent': wrapCommand(loadContent),
2193
+ 'SourceControl.handleFocus': wrapCommand(handleFocus),
1921
2194
  'SourceControl.render2': render2,
1922
2195
  'SourceControl.renderActions2': renderActions,
1923
2196
  'SourceControl.renderEventListeners': renderEventListeners,
1924
2197
  'SourceControl.saveState': saveState,
1925
- 'SourceControl.terminate': terminate
2198
+ 'SourceControl.selectIndex': wrapCommand(selectIndex),
2199
+ 'SourceControl.terminate': terminate,
2200
+ 'SourceControl.updateIcons': wrapCommand(updateIcons)
1926
2201
  };
1927
2202
 
1928
2203
  const listen = async () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lvce-editor/source-control-worker",
3
- "version": "1.2.0",
3
+ "version": "1.4.0",
4
4
  "description": "Source Control Worker",
5
5
  "keywords": [
6
6
  "Lvce Editor"