@lvce-editor/explorer-view 1.4.0 → 1.6.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/README.md +2 -0
- package/dist/explorerViewWorkerMain.js +591 -231
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -847,6 +847,9 @@ const getFileIcon = ({
|
|
|
847
847
|
const getIcon = dirent => {
|
|
848
848
|
return '';
|
|
849
849
|
};
|
|
850
|
+
const getFolderIcon = dirent => {
|
|
851
|
+
return '';
|
|
852
|
+
};
|
|
850
853
|
|
|
851
854
|
// TODO use posInSet and setSize properties to compute more effectively
|
|
852
855
|
const computeExplorerRenamedDirent = (dirents, index, newName) => {
|
|
@@ -946,17 +949,50 @@ const computeExplorerRenamedDirent = (dirents, index, newName) => {
|
|
|
946
949
|
const None$3 = 0;
|
|
947
950
|
const CreateFile = 1;
|
|
948
951
|
const CreateFolder = 2;
|
|
949
|
-
const Rename = 3;
|
|
950
|
-
|
|
951
|
-
const
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
const
|
|
955
|
-
const
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
const
|
|
952
|
+
const Rename$1 = 3;
|
|
953
|
+
|
|
954
|
+
const state = {
|
|
955
|
+
rpc: undefined
|
|
956
|
+
};
|
|
957
|
+
const invoke = (method, ...params) => {
|
|
958
|
+
const rpc = state.rpc;
|
|
959
|
+
// @ts-ignore
|
|
960
|
+
return rpc.invoke(method, ...params);
|
|
961
|
+
};
|
|
962
|
+
const setRpc = rpc => {
|
|
963
|
+
state.rpc = rpc;
|
|
964
|
+
};
|
|
965
|
+
|
|
966
|
+
const remove = async dirent => {
|
|
967
|
+
return invoke('FileSystem.remove', dirent);
|
|
968
|
+
};
|
|
969
|
+
const readDirWithFileTypes = async uri => {
|
|
970
|
+
return invoke('FileSystem.readDirWithFileTypes', uri);
|
|
971
|
+
};
|
|
972
|
+
const getPathSeparator$1 = async root => {
|
|
973
|
+
return invoke('FileSystem.getPathSeparator', root);
|
|
974
|
+
};
|
|
975
|
+
const getRealPath = async path => {
|
|
976
|
+
return invoke('FileSystem.getRealPath', path);
|
|
977
|
+
};
|
|
978
|
+
const stat = async dirent => {
|
|
979
|
+
return invoke('FileSystem.stat', dirent);
|
|
980
|
+
};
|
|
981
|
+
const createFile = async uri => {
|
|
982
|
+
return invoke('FileSystem.createFile', uri);
|
|
983
|
+
};
|
|
984
|
+
const writeFile = async (uri, content) => {
|
|
985
|
+
return invoke('FileSystem.writeFile', uri, content);
|
|
986
|
+
};
|
|
987
|
+
const mkdir = async uri => {
|
|
988
|
+
return invoke('FileSystem.mkdir', uri);
|
|
989
|
+
};
|
|
990
|
+
const rename$1 = async (oldUri, newUri) => {
|
|
991
|
+
return invoke('FileSystem.rename', oldUri, newUri);
|
|
992
|
+
};
|
|
993
|
+
const copy$1 = async (oldUri, newUri) => {
|
|
994
|
+
return invoke('FileSystem.copy', oldUri, newUri);
|
|
995
|
+
};
|
|
960
996
|
|
|
961
997
|
const dirname = (pathSeparator, path) => {
|
|
962
998
|
const index = path.lastIndexOf(pathSeparator);
|
|
@@ -1099,13 +1135,57 @@ const acceptEdit = state => {
|
|
|
1099
1135
|
return acceptCreate(state, File, createFile);
|
|
1100
1136
|
case CreateFolder:
|
|
1101
1137
|
return acceptCreate(state, Directory, mkdir);
|
|
1102
|
-
case Rename:
|
|
1138
|
+
case Rename$1:
|
|
1103
1139
|
return acceptRename(state);
|
|
1104
1140
|
default:
|
|
1105
1141
|
return state;
|
|
1106
1142
|
}
|
|
1107
1143
|
};
|
|
1108
1144
|
|
|
1145
|
+
const cancelEdit = state => {
|
|
1146
|
+
const {
|
|
1147
|
+
editingIndex
|
|
1148
|
+
} = state;
|
|
1149
|
+
return {
|
|
1150
|
+
...state,
|
|
1151
|
+
focusedIndex: editingIndex,
|
|
1152
|
+
focused: true,
|
|
1153
|
+
editingIndex: -1,
|
|
1154
|
+
editingValue: '',
|
|
1155
|
+
editingType: None$3
|
|
1156
|
+
};
|
|
1157
|
+
};
|
|
1158
|
+
|
|
1159
|
+
const isTopLevel$1 = dirent => {
|
|
1160
|
+
return dirent.depth === 1;
|
|
1161
|
+
};
|
|
1162
|
+
|
|
1163
|
+
const IsTopLevel = {
|
|
1164
|
+
__proto__: null,
|
|
1165
|
+
isTopLevel: isTopLevel$1
|
|
1166
|
+
};
|
|
1167
|
+
|
|
1168
|
+
const toCollapsedDirent = dirent => {
|
|
1169
|
+
if (dirent.type === DirectoryExpanded) {
|
|
1170
|
+
return {
|
|
1171
|
+
...dirent,
|
|
1172
|
+
type: Directory
|
|
1173
|
+
};
|
|
1174
|
+
}
|
|
1175
|
+
return dirent;
|
|
1176
|
+
};
|
|
1177
|
+
|
|
1178
|
+
const collapseAll$1 = state => {
|
|
1179
|
+
const {
|
|
1180
|
+
items
|
|
1181
|
+
} = state;
|
|
1182
|
+
const newDirents = items.filter(IsTopLevel).map(toCollapsedDirent);
|
|
1183
|
+
return {
|
|
1184
|
+
...state,
|
|
1185
|
+
items: newDirents
|
|
1186
|
+
};
|
|
1187
|
+
};
|
|
1188
|
+
|
|
1109
1189
|
const getFocusedDirent$1 = state => {
|
|
1110
1190
|
const {
|
|
1111
1191
|
focusedIndex,
|
|
@@ -1121,24 +1201,15 @@ const copyPath$1 = async state => {
|
|
|
1121
1201
|
return state;
|
|
1122
1202
|
};
|
|
1123
1203
|
|
|
1124
|
-
const state = {
|
|
1125
|
-
rpc: undefined
|
|
1126
|
-
};
|
|
1127
|
-
const invoke = (method, ...params) => {
|
|
1128
|
-
const rpc = state.rpc;
|
|
1129
|
-
// @ts-ignore
|
|
1130
|
-
return rpc.invoke(method, ...params);
|
|
1131
|
-
};
|
|
1132
|
-
const setRpc = rpc => {
|
|
1133
|
-
state.rpc = rpc;
|
|
1134
|
-
};
|
|
1135
|
-
|
|
1136
1204
|
const writeText = async text => {
|
|
1137
1205
|
await invoke('ClipBoard.writeText', /* text */text);
|
|
1138
1206
|
};
|
|
1139
1207
|
const readNativeFiles = async () => {
|
|
1140
1208
|
return invoke('ClipBoard.readNativeFiles');
|
|
1141
1209
|
};
|
|
1210
|
+
const writeNativeFiles = async (type, files) => {
|
|
1211
|
+
return invoke('ClipBoard.writeNativeFiles', type, files);
|
|
1212
|
+
};
|
|
1142
1213
|
|
|
1143
1214
|
const copyRelativePath$1 = async state => {
|
|
1144
1215
|
const dirent = getFocusedDirent$1(state);
|
|
@@ -1292,7 +1363,7 @@ const hasSymbolicLinks = rawDirents => {
|
|
|
1292
1363
|
return rawDirents.some(isSymbolicLink);
|
|
1293
1364
|
};
|
|
1294
1365
|
const getChildDirentsRaw = async uri => {
|
|
1295
|
-
const rawDirents = await readDirWithFileTypes();
|
|
1366
|
+
const rawDirents = await readDirWithFileTypes(uri);
|
|
1296
1367
|
array(rawDirents);
|
|
1297
1368
|
if (hasSymbolicLinks(rawDirents)) {
|
|
1298
1369
|
return resolveSymbolicLinks(uri, rawDirents);
|
|
@@ -1386,6 +1457,7 @@ const makeExpanded = dirent => {
|
|
|
1386
1457
|
}
|
|
1387
1458
|
return dirent;
|
|
1388
1459
|
};
|
|
1460
|
+
|
|
1389
1461
|
const expandRecursively = async state => {
|
|
1390
1462
|
const {
|
|
1391
1463
|
items,
|
|
@@ -1542,29 +1614,12 @@ const focusPrevious = state => {
|
|
|
1542
1614
|
}
|
|
1543
1615
|
};
|
|
1544
1616
|
|
|
1545
|
-
const
|
|
1546
|
-
const Tree = 'tree';
|
|
1547
|
-
const TreeItem$1 = 'treeitem';
|
|
1548
|
-
|
|
1549
|
-
const Button$1 = 'Button';
|
|
1550
|
-
const ButtonPrimary = 'ButtonPrimary';
|
|
1551
|
-
const Explorer$1 = 'Explorer';
|
|
1552
|
-
const FileIcon = 'FileIcon';
|
|
1553
|
-
const InputBox = 'InputBox';
|
|
1554
|
-
const Label = 'Label';
|
|
1555
|
-
const TreeItem = 'TreeItem';
|
|
1556
|
-
const TreeItemActive = 'TreeItemActive';
|
|
1557
|
-
const Viewlet = 'Viewlet';
|
|
1558
|
-
const Welcome = 'Welcome';
|
|
1559
|
-
const WelcomeMessage = 'WelcomeMessage';
|
|
1617
|
+
const Button$2 = 1;
|
|
1560
1618
|
|
|
1561
|
-
const
|
|
1562
|
-
const
|
|
1563
|
-
const
|
|
1564
|
-
const
|
|
1565
|
-
const HandleFocus = 'handleFocus';
|
|
1566
|
-
const HandlePointerDown = 'handlePointerDown';
|
|
1567
|
-
const HandleWheel = 'handleWheel';
|
|
1619
|
+
const CollapseAll = 'CollapseAll';
|
|
1620
|
+
const NewFile$1 = 'NewFile';
|
|
1621
|
+
const NewFolder$1 = 'NewFolder';
|
|
1622
|
+
const Refresh = 'Refresh';
|
|
1568
1623
|
|
|
1569
1624
|
const emptyObject = {};
|
|
1570
1625
|
const RE_PLACEHOLDER = /\{(PH\d+)\}/g;
|
|
@@ -1578,72 +1633,126 @@ const i18nString = (key, placeholders = emptyObject) => {
|
|
|
1578
1633
|
return key.replaceAll(RE_PLACEHOLDER, replacer);
|
|
1579
1634
|
};
|
|
1580
1635
|
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
const
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
};
|
|
1604
|
-
const newFile = () => {
|
|
1605
|
-
return i18nString(UiStrings.NewFile);
|
|
1606
|
-
};
|
|
1607
|
-
const newFolder = () => {
|
|
1608
|
-
return i18nString(UiStrings.NewFolder);
|
|
1636
|
+
const NewFile = 'New File...';
|
|
1637
|
+
const NewFolder = 'New Folder...';
|
|
1638
|
+
const OpenContainingFolder = 'Open Containing Folder';
|
|
1639
|
+
const OpenInIntegratedTerminal = 'Open in integrated Terminal';
|
|
1640
|
+
const Cut$1 = 'Cut';
|
|
1641
|
+
const Copy$1 = 'Copy';
|
|
1642
|
+
const Paste = 'Paste';
|
|
1643
|
+
const CopyPath = 'Copy Path';
|
|
1644
|
+
const CopyRelativePath = 'Copy Relative Path';
|
|
1645
|
+
const Rename = 'Rename';
|
|
1646
|
+
const Delete$1 = 'Delete';
|
|
1647
|
+
const RefreshExplorer = 'Refresh Explorer';
|
|
1648
|
+
const CollapseAllFoldersInExplorer = 'Collapse All Folders in Explorer';
|
|
1649
|
+
const FilesExplorer = 'Files Explorer';
|
|
1650
|
+
const YouHaveNotYetOpenedAFolder = 'You have not yet opened a folder';
|
|
1651
|
+
const OpenFolder = 'Open folder';
|
|
1652
|
+
|
|
1653
|
+
const newFile$1 = () => {
|
|
1654
|
+
return i18nString(NewFile);
|
|
1655
|
+
};
|
|
1656
|
+
const newFolder$1 = () => {
|
|
1657
|
+
return i18nString(NewFolder);
|
|
1609
1658
|
};
|
|
1610
1659
|
const openContainingFolder$1 = () => {
|
|
1611
|
-
return i18nString(
|
|
1660
|
+
return i18nString(OpenContainingFolder);
|
|
1612
1661
|
};
|
|
1613
1662
|
const openInIntegratedTerminal = () => {
|
|
1614
|
-
return i18nString(
|
|
1663
|
+
return i18nString(OpenInIntegratedTerminal);
|
|
1615
1664
|
};
|
|
1616
1665
|
const cut = () => {
|
|
1617
|
-
return i18nString(
|
|
1666
|
+
return i18nString(Cut$1);
|
|
1618
1667
|
};
|
|
1619
1668
|
const copy = () => {
|
|
1620
|
-
return i18nString(
|
|
1669
|
+
return i18nString(Copy$1);
|
|
1621
1670
|
};
|
|
1622
1671
|
const paste = () => {
|
|
1623
|
-
return i18nString(
|
|
1672
|
+
return i18nString(Paste);
|
|
1624
1673
|
};
|
|
1625
1674
|
const copyPath = () => {
|
|
1626
|
-
return i18nString(
|
|
1675
|
+
return i18nString(CopyPath);
|
|
1627
1676
|
};
|
|
1628
1677
|
const copyRelativePath = () => {
|
|
1629
|
-
return i18nString(
|
|
1678
|
+
return i18nString(CopyRelativePath);
|
|
1630
1679
|
};
|
|
1631
1680
|
const rename = () => {
|
|
1632
|
-
return i18nString(
|
|
1681
|
+
return i18nString(Rename);
|
|
1633
1682
|
};
|
|
1634
1683
|
const deleteItem = () => {
|
|
1635
|
-
return i18nString(
|
|
1684
|
+
return i18nString(Delete$1);
|
|
1685
|
+
};
|
|
1686
|
+
const refresh = () => {
|
|
1687
|
+
return i18nString(RefreshExplorer);
|
|
1688
|
+
};
|
|
1689
|
+
const collapseAll = () => {
|
|
1690
|
+
return i18nString(CollapseAllFoldersInExplorer);
|
|
1636
1691
|
};
|
|
1637
1692
|
const filesExplorer = () => {
|
|
1638
|
-
return i18nString(
|
|
1693
|
+
return i18nString(FilesExplorer);
|
|
1639
1694
|
};
|
|
1640
1695
|
const youHaveNotYetOpenedAFolder = () => {
|
|
1641
|
-
return i18nString(
|
|
1696
|
+
return i18nString(YouHaveNotYetOpenedAFolder);
|
|
1642
1697
|
};
|
|
1643
1698
|
const openFolder$1 = () => {
|
|
1644
|
-
return i18nString(
|
|
1699
|
+
return i18nString(OpenFolder);
|
|
1700
|
+
};
|
|
1701
|
+
|
|
1702
|
+
const getActions = root => {
|
|
1703
|
+
if (!root) {
|
|
1704
|
+
return [];
|
|
1705
|
+
}
|
|
1706
|
+
return [{
|
|
1707
|
+
type: Button$2,
|
|
1708
|
+
id: newFile$1(),
|
|
1709
|
+
icon: NewFile$1,
|
|
1710
|
+
command: 'newFile'
|
|
1711
|
+
}, {
|
|
1712
|
+
type: Button$2,
|
|
1713
|
+
id: newFolder$1(),
|
|
1714
|
+
icon: NewFolder$1,
|
|
1715
|
+
command: 'newFolder'
|
|
1716
|
+
}, {
|
|
1717
|
+
type: Button$2,
|
|
1718
|
+
id: refresh(),
|
|
1719
|
+
icon: Refresh,
|
|
1720
|
+
command: 'refresh'
|
|
1721
|
+
}, {
|
|
1722
|
+
type: Button$2,
|
|
1723
|
+
id: collapseAll(),
|
|
1724
|
+
icon: CollapseAll,
|
|
1725
|
+
command: 'collapseAll'
|
|
1726
|
+
}];
|
|
1645
1727
|
};
|
|
1646
1728
|
|
|
1729
|
+
const None$2 = 'none';
|
|
1730
|
+
const ToolBar = 'toolbar';
|
|
1731
|
+
const Tree = 'tree';
|
|
1732
|
+
const TreeItem$1 = 'treeitem';
|
|
1733
|
+
|
|
1734
|
+
const Actions = 'Actions';
|
|
1735
|
+
const Button$1 = 'Button';
|
|
1736
|
+
const ButtonPrimary = 'ButtonPrimary';
|
|
1737
|
+
const Explorer$1 = 'Explorer';
|
|
1738
|
+
const FileIcon = 'FileIcon';
|
|
1739
|
+
const IconButton = 'IconButton';
|
|
1740
|
+
const InputBox = 'InputBox';
|
|
1741
|
+
const Label = 'Label';
|
|
1742
|
+
const TreeItem = 'TreeItem';
|
|
1743
|
+
const TreeItemActive = 'TreeItemActive';
|
|
1744
|
+
const Viewlet = 'Viewlet';
|
|
1745
|
+
const Welcome = 'Welcome';
|
|
1746
|
+
const WelcomeMessage = 'WelcomeMessage';
|
|
1747
|
+
|
|
1748
|
+
const HandleBlur = 'handleBlur';
|
|
1749
|
+
const HandleClick = 'handleClick';
|
|
1750
|
+
const handleClickOpenFolder$1 = 'handleClickOpenFolder';
|
|
1751
|
+
const HandleContextMenu = 'handleContextMenu';
|
|
1752
|
+
const HandleFocus = 'handleFocus';
|
|
1753
|
+
const HandlePointerDown = 'handlePointerDown';
|
|
1754
|
+
const HandleWheel = 'handleWheel';
|
|
1755
|
+
|
|
1647
1756
|
const Button = 1;
|
|
1648
1757
|
const Div = 4;
|
|
1649
1758
|
const Input = 6;
|
|
@@ -1951,13 +2060,13 @@ const menuEntrySeparator = {
|
|
|
1951
2060
|
|
|
1952
2061
|
const menuEntryNewFile = {
|
|
1953
2062
|
id: 'newFile',
|
|
1954
|
-
label: newFile(),
|
|
2063
|
+
label: newFile$1(),
|
|
1955
2064
|
flags: None$1,
|
|
1956
2065
|
command: 'Explorer.newFile'
|
|
1957
2066
|
};
|
|
1958
2067
|
const menuEntryNewFolder = {
|
|
1959
2068
|
id: 'newFolder',
|
|
1960
|
-
label: newFolder(),
|
|
2069
|
+
label: newFolder$1(),
|
|
1961
2070
|
flags: None$1,
|
|
1962
2071
|
command: 'Explorer.newFolder'
|
|
1963
2072
|
};
|
|
@@ -2208,8 +2317,8 @@ const handleClickDirectoryExpanded$1 = (state, dirent, index, keepFocus) => {
|
|
|
2208
2317
|
};
|
|
2209
2318
|
};
|
|
2210
2319
|
const handleClickSymLink$1 = async (state, dirent, index) => {
|
|
2211
|
-
await getRealPath();
|
|
2212
|
-
const type = await stat();
|
|
2320
|
+
const realPath = await getRealPath(dirent.path);
|
|
2321
|
+
const type = await stat(realPath);
|
|
2213
2322
|
switch (type) {
|
|
2214
2323
|
case File:
|
|
2215
2324
|
return handleClickFile$1(state, dirent, index);
|
|
@@ -2258,6 +2367,40 @@ const getIndexFromPosition = (state, eventX, eventY) => {
|
|
|
2258
2367
|
return index;
|
|
2259
2368
|
};
|
|
2260
2369
|
|
|
2370
|
+
const handleClickDirectory = async (state, dirent, index, keepFocus) => {
|
|
2371
|
+
dirent.type = DirectoryExpanding;
|
|
2372
|
+
// TODO handle error
|
|
2373
|
+
const dirents = await getChildDirents(state.pathSeparator, dirent);
|
|
2374
|
+
const state2 = state;
|
|
2375
|
+
if (!state2) {
|
|
2376
|
+
return state;
|
|
2377
|
+
}
|
|
2378
|
+
// TODO use Viewlet.getState here and check if it exists
|
|
2379
|
+
const newIndex = state2.items.indexOf(dirent);
|
|
2380
|
+
// TODO if viewlet is disposed or root has changed, return
|
|
2381
|
+
if (newIndex === -1) {
|
|
2382
|
+
return state;
|
|
2383
|
+
}
|
|
2384
|
+
const newDirents = [...state2.items];
|
|
2385
|
+
newDirents.splice(newIndex + 1, 0, ...dirents);
|
|
2386
|
+
dirent.type = DirectoryExpanded;
|
|
2387
|
+
dirent.icon = getIcon();
|
|
2388
|
+
const {
|
|
2389
|
+
height,
|
|
2390
|
+
itemHeight,
|
|
2391
|
+
minLineY
|
|
2392
|
+
} = state2;
|
|
2393
|
+
// TODO when focused index has changed while expanding, don't update it
|
|
2394
|
+
const maxLineY = getExplorerMaxLineY(minLineY, height, itemHeight, newDirents.length);
|
|
2395
|
+
return {
|
|
2396
|
+
...state,
|
|
2397
|
+
items: newDirents,
|
|
2398
|
+
focusedIndex: newIndex,
|
|
2399
|
+
focused: keepFocus,
|
|
2400
|
+
maxLineY
|
|
2401
|
+
};
|
|
2402
|
+
};
|
|
2403
|
+
|
|
2261
2404
|
const getParentStartIndex = (dirents, index) => {
|
|
2262
2405
|
const dirent = dirents[index];
|
|
2263
2406
|
let startIndex = index - 1;
|
|
@@ -2270,10 +2413,6 @@ const getParentStartIndex = (dirents, index) => {
|
|
|
2270
2413
|
const Keyboard = -1;
|
|
2271
2414
|
const LeftClick = 0;
|
|
2272
2415
|
|
|
2273
|
-
const openFolder = async () => {
|
|
2274
|
-
// TODO
|
|
2275
|
-
};
|
|
2276
|
-
|
|
2277
2416
|
// TODO viewlet should only have create and refresh functions
|
|
2278
2417
|
// every thing else can be in a separate module <viewlet>.lazy.js
|
|
2279
2418
|
// and <viewlet>.ipc.js
|
|
@@ -2301,7 +2440,7 @@ const handleIconThemeChange = state => {
|
|
|
2301
2440
|
};
|
|
2302
2441
|
|
|
2303
2442
|
// TODO rename dirents to items, then can use virtual list component directly
|
|
2304
|
-
const setDeltaY = (state, deltaY) => {
|
|
2443
|
+
const setDeltaY$1 = (state, deltaY) => {
|
|
2305
2444
|
const {
|
|
2306
2445
|
itemHeight,
|
|
2307
2446
|
height,
|
|
@@ -2325,93 +2464,11 @@ const setDeltaY = (state, deltaY) => {
|
|
|
2325
2464
|
};
|
|
2326
2465
|
};
|
|
2327
2466
|
const handleWheel = (state, deltaMode, deltaY) => {
|
|
2328
|
-
return setDeltaY(state, state.deltaY + deltaY);
|
|
2329
|
-
};
|
|
2330
|
-
|
|
2331
|
-
// TODO support multiselection and removing multiple dirents
|
|
2332
|
-
const removeDirent = async state => {
|
|
2333
|
-
if (state.focusedIndex < 0) {
|
|
2334
|
-
return state;
|
|
2335
|
-
}
|
|
2336
|
-
const dirent = getFocusedDirent$1(state);
|
|
2337
|
-
const absolutePath = dirent.path;
|
|
2338
|
-
try {
|
|
2339
|
-
// TODO handle error
|
|
2340
|
-
await remove(absolutePath);
|
|
2341
|
-
} catch (error) {
|
|
2342
|
-
// TODO vscode shows error as alert (no stacktrace) and retry button
|
|
2343
|
-
// maybe should show alert as well, but where to put stacktrace?
|
|
2344
|
-
// on web should probably show notification (dialog)
|
|
2345
|
-
// ErrorHandling.handleError(error)
|
|
2346
|
-
// await ErrorHandling.showErrorDialog(error)
|
|
2347
|
-
return;
|
|
2348
|
-
}
|
|
2349
|
-
// TODO avoid state mutation
|
|
2350
|
-
const newVersion = ++state.version;
|
|
2351
|
-
// TODO race condition
|
|
2352
|
-
// const newState = await loadContent(state:any)
|
|
2353
|
-
if (state.version !== newVersion || state.disposed) {
|
|
2354
|
-
return state;
|
|
2355
|
-
}
|
|
2356
|
-
// TODO is it possible to make this more functional instead of mutating state?
|
|
2357
|
-
// maybe every function returns a new state?
|
|
2358
|
-
const index = state.items.indexOf(dirent);
|
|
2359
|
-
let deleteEnd = index + 1;
|
|
2360
|
-
for (; deleteEnd < state.items.length; deleteEnd++) {
|
|
2361
|
-
if (state.items[deleteEnd].depth <= dirent.depth) {
|
|
2362
|
-
break;
|
|
2363
|
-
}
|
|
2364
|
-
}
|
|
2365
|
-
const deleteCount = deleteEnd - index;
|
|
2366
|
-
const newDirents = [...state.items];
|
|
2367
|
-
newDirents.splice(index, deleteCount);
|
|
2368
|
-
let indexToFocus = -1;
|
|
2369
|
-
if (newDirents.length === 0) {
|
|
2370
|
-
indexToFocus = -1;
|
|
2371
|
-
} else if (index < state.focusedIndex) {
|
|
2372
|
-
indexToFocus = state.focusedIndex - 1;
|
|
2373
|
-
} else if (index === state.focusedIndex) {
|
|
2374
|
-
indexToFocus = Math.max(state.focusedIndex - 1, 0);
|
|
2375
|
-
} else {
|
|
2376
|
-
indexToFocus = Math.max(state.focusedIndex - 1, 0);
|
|
2377
|
-
}
|
|
2378
|
-
return {
|
|
2379
|
-
...state,
|
|
2380
|
-
items: newDirents,
|
|
2381
|
-
focusedIndex: indexToFocus
|
|
2382
|
-
};
|
|
2383
|
-
};
|
|
2384
|
-
const renameDirent = state => {
|
|
2385
|
-
const {
|
|
2386
|
-
focusedIndex,
|
|
2387
|
-
items
|
|
2388
|
-
} = state;
|
|
2389
|
-
const item = items[focusedIndex];
|
|
2390
|
-
// Focus.setFocus(FocusKey.ExplorerEditBox)
|
|
2391
|
-
return {
|
|
2392
|
-
...state,
|
|
2393
|
-
editingIndex: focusedIndex,
|
|
2394
|
-
editingType: Rename,
|
|
2395
|
-
editingValue: item.name
|
|
2396
|
-
};
|
|
2467
|
+
return setDeltaY$1(state, state.deltaY + deltaY);
|
|
2397
2468
|
};
|
|
2398
2469
|
|
|
2399
2470
|
// TODO use posInSet and setSize properties to compute more effectively
|
|
2400
2471
|
|
|
2401
|
-
const cancelEdit = state => {
|
|
2402
|
-
const {
|
|
2403
|
-
editingIndex
|
|
2404
|
-
} = state;
|
|
2405
|
-
return {
|
|
2406
|
-
...state,
|
|
2407
|
-
focusedIndex: editingIndex,
|
|
2408
|
-
focused: true,
|
|
2409
|
-
editingIndex: -1,
|
|
2410
|
-
editingValue: '',
|
|
2411
|
-
editingType: None$3
|
|
2412
|
-
};
|
|
2413
|
-
};
|
|
2414
|
-
|
|
2415
2472
|
// TODO much shared logic with newFolder
|
|
2416
2473
|
|
|
2417
2474
|
const handleClickFile = async (state, dirent, index, keepFocus = false) => {
|
|
@@ -2422,39 +2479,6 @@ const handleClickFile = async (state, dirent, index, keepFocus = false) => {
|
|
|
2422
2479
|
focused: keepFocus
|
|
2423
2480
|
};
|
|
2424
2481
|
};
|
|
2425
|
-
const handleClickDirectory = async (state, dirent, index, keepFocus) => {
|
|
2426
|
-
dirent.type = DirectoryExpanding;
|
|
2427
|
-
// TODO handle error
|
|
2428
|
-
const dirents = await getChildDirents(state.pathSeparator, dirent);
|
|
2429
|
-
const state2 = {};
|
|
2430
|
-
if (!state2) {
|
|
2431
|
-
return state;
|
|
2432
|
-
}
|
|
2433
|
-
// TODO use Viewlet.getState here and check if it exists
|
|
2434
|
-
const newIndex = state2.items.indexOf(dirent);
|
|
2435
|
-
// TODO if viewlet is disposed or root has changed, return
|
|
2436
|
-
if (newIndex === -1) {
|
|
2437
|
-
return state;
|
|
2438
|
-
}
|
|
2439
|
-
const newDirents = [...state2.items];
|
|
2440
|
-
newDirents.splice(newIndex + 1, 0, ...dirents);
|
|
2441
|
-
dirent.type = DirectoryExpanded;
|
|
2442
|
-
dirent.icon = getIcon();
|
|
2443
|
-
const {
|
|
2444
|
-
height,
|
|
2445
|
-
itemHeight,
|
|
2446
|
-
minLineY
|
|
2447
|
-
} = state2;
|
|
2448
|
-
// TODO when focused index has changed while expanding, don't update it
|
|
2449
|
-
const maxLineY = getExplorerMaxLineY(minLineY, height, itemHeight, newDirents.length);
|
|
2450
|
-
return {
|
|
2451
|
-
...state,
|
|
2452
|
-
items: newDirents,
|
|
2453
|
-
focusedIndex: newIndex,
|
|
2454
|
-
focused: keepFocus,
|
|
2455
|
-
maxLineY
|
|
2456
|
-
};
|
|
2457
|
-
};
|
|
2458
2482
|
const handleClickDirectoryExpanded = (state, dirent, index, keepFocus) => {
|
|
2459
2483
|
const {
|
|
2460
2484
|
minLineY,
|
|
@@ -2522,8 +2546,8 @@ const handleClickCurrentButKeepFocus = state => {
|
|
|
2522
2546
|
// export const handleBlur=()=>{}
|
|
2523
2547
|
|
|
2524
2548
|
const handleClickSymLink = async (state, dirent, index) => {
|
|
2525
|
-
await getRealPath();
|
|
2526
|
-
const type = await stat();
|
|
2549
|
+
const realPath = await getRealPath(dirent.path);
|
|
2550
|
+
const type = await stat(realPath);
|
|
2527
2551
|
switch (type) {
|
|
2528
2552
|
case File:
|
|
2529
2553
|
return handleClickFile(state, dirent, index);
|
|
@@ -2604,6 +2628,10 @@ const handleArrowLeft = state => {
|
|
|
2604
2628
|
|
|
2605
2629
|
// TODO maybe just insert items into explorer and refresh whole explorer
|
|
2606
2630
|
|
|
2631
|
+
const openFolder = async () => {
|
|
2632
|
+
// TODO
|
|
2633
|
+
};
|
|
2634
|
+
|
|
2607
2635
|
const handleClickOpenFolder = async state => {
|
|
2608
2636
|
await openFolder();
|
|
2609
2637
|
return state;
|
|
@@ -2650,6 +2678,21 @@ const handleContextMenu = (state, button, x, y) => {
|
|
|
2650
2678
|
}
|
|
2651
2679
|
};
|
|
2652
2680
|
|
|
2681
|
+
const handleCopy = async state => {
|
|
2682
|
+
// TODO handle multiple files
|
|
2683
|
+
// TODO if not file is selected, what happens?
|
|
2684
|
+
const dirent = getFocusedDirent$1(state);
|
|
2685
|
+
if (!dirent) {
|
|
2686
|
+
console.info('[ViewletExplorer/handleCopy] no dirent selected');
|
|
2687
|
+
return;
|
|
2688
|
+
}
|
|
2689
|
+
const absolutePath = dirent.path;
|
|
2690
|
+
// TODO handle copy error gracefully
|
|
2691
|
+
const files = [absolutePath];
|
|
2692
|
+
await writeNativeFiles('copy', files);
|
|
2693
|
+
return state;
|
|
2694
|
+
};
|
|
2695
|
+
|
|
2653
2696
|
const getFilePathElectron = async file => {
|
|
2654
2697
|
return invoke('GetFilePathElectron.getFilePathElectron', file);
|
|
2655
2698
|
};
|
|
@@ -2661,10 +2704,10 @@ const mergeDirents$2 = (oldDirents, newDirents) => {
|
|
|
2661
2704
|
// TODO copy files in parallel
|
|
2662
2705
|
const copyFilesElectron = async (root, pathSeparator, files) => {
|
|
2663
2706
|
for (const file of files) {
|
|
2664
|
-
await getFilePathElectron(file);
|
|
2707
|
+
const from = await getFilePathElectron(file);
|
|
2665
2708
|
// const from = file.path
|
|
2666
|
-
join(pathSeparator, root, file.name);
|
|
2667
|
-
await copy$1();
|
|
2709
|
+
const to = join(pathSeparator, root, file.name);
|
|
2710
|
+
await copy$1(from, to);
|
|
2668
2711
|
}
|
|
2669
2712
|
};
|
|
2670
2713
|
const getMergedDirents$2 = async (root, pathSeparator, dirents) => {
|
|
@@ -2757,7 +2800,10 @@ const handleDropIntoFolder = async (state, dirent, index, files) => {
|
|
|
2757
2800
|
items
|
|
2758
2801
|
} = state;
|
|
2759
2802
|
for (const file of files) {
|
|
2760
|
-
|
|
2803
|
+
// TODO path basename
|
|
2804
|
+
const baseName = file;
|
|
2805
|
+
const to = dirent.path + pathSeparator + baseName;
|
|
2806
|
+
await copy$1(file, to);
|
|
2761
2807
|
}
|
|
2762
2808
|
const childDirents = await getChildDirents(pathSeparator, dirent);
|
|
2763
2809
|
const mergedDirents = getMergedDirents(items, index, dirent, childDirents);
|
|
@@ -2915,8 +2961,8 @@ const handlePasteCopy = async (state, nativeFiles) => {
|
|
|
2915
2961
|
// TODO handle pasting files into hardlink
|
|
2916
2962
|
// TODO what if folder is big and it takes a long time
|
|
2917
2963
|
for (const source of nativeFiles.files) {
|
|
2918
|
-
join(state.pathSeperator, state.root, getBaseName(state.pathSeparator, source));
|
|
2919
|
-
await copy$1();
|
|
2964
|
+
const target = join(state.pathSeperator, state.root, getBaseName(state.pathSeparator, source));
|
|
2965
|
+
await copy$1(source, target);
|
|
2920
2966
|
}
|
|
2921
2967
|
// TODO only update folder at which level it changed
|
|
2922
2968
|
return updateRoot(state);
|
|
@@ -2924,8 +2970,8 @@ const handlePasteCopy = async (state, nativeFiles) => {
|
|
|
2924
2970
|
|
|
2925
2971
|
const handlePasteCut = async (state, nativeFiles) => {
|
|
2926
2972
|
for (const source of nativeFiles.files) {
|
|
2927
|
-
`${state.root}${state.pathSeparator}${getBaseName(state.pathSeparator, source)}`;
|
|
2928
|
-
await rename$1();
|
|
2973
|
+
const target = `${state.root}${state.pathSeparator}${getBaseName(state.pathSeparator, source)}`;
|
|
2974
|
+
await rename$1(source, target);
|
|
2929
2975
|
}
|
|
2930
2976
|
return state;
|
|
2931
2977
|
};
|
|
@@ -2977,6 +3023,34 @@ const handlePointerDown = (state, button, x, y) => {
|
|
|
2977
3023
|
return state;
|
|
2978
3024
|
};
|
|
2979
3025
|
|
|
3026
|
+
const handleUpload = async (state, dirents) => {
|
|
3027
|
+
const {
|
|
3028
|
+
root,
|
|
3029
|
+
pathSeparator
|
|
3030
|
+
} = state;
|
|
3031
|
+
for (const dirent of dirents) {
|
|
3032
|
+
// TODO switch
|
|
3033
|
+
// TODO symlink might not be possible to be copied
|
|
3034
|
+
// TODO create folder if type is 2
|
|
3035
|
+
if (dirent.type === /* File */1) {
|
|
3036
|
+
// TODO reading text might be inefficient for binary files
|
|
3037
|
+
// but not sure how else to send them via jsonrpc
|
|
3038
|
+
const content = await dirent.file.text();
|
|
3039
|
+
const absolutePath = [root, dirent.file.name].join(pathSeparator);
|
|
3040
|
+
await writeFile(absolutePath, content);
|
|
3041
|
+
}
|
|
3042
|
+
}
|
|
3043
|
+
};
|
|
3044
|
+
|
|
3045
|
+
const EmptyString = '';
|
|
3046
|
+
|
|
3047
|
+
const Fulfilled = 'fulfilled';
|
|
3048
|
+
const Rejected = 'rejected';
|
|
3049
|
+
|
|
3050
|
+
const getWorkspacePath = () => {
|
|
3051
|
+
return invoke('Workspace.getPath');
|
|
3052
|
+
};
|
|
3053
|
+
|
|
2980
3054
|
// TODO viewlet should only have create and refresh functions
|
|
2981
3055
|
// every thing else can be in a separate module <viewlet>.lazy.js
|
|
2982
3056
|
// and <viewlet>.ipc.js
|
|
@@ -2987,12 +3061,95 @@ const handlePointerDown = (state, button, x, y) => {
|
|
|
2987
3061
|
// TODO instead of root string, there should be a root dirent
|
|
2988
3062
|
|
|
2989
3063
|
const getPathSeparator = root => {
|
|
2990
|
-
return getPathSeparator$1();
|
|
3064
|
+
return getPathSeparator$1(root);
|
|
3065
|
+
};
|
|
3066
|
+
const getSavedChildDirents = (map, path, depth, excluded, pathSeparator) => {
|
|
3067
|
+
const children = map[path];
|
|
3068
|
+
if (!children) {
|
|
3069
|
+
return [];
|
|
3070
|
+
}
|
|
3071
|
+
const dirents = [];
|
|
3072
|
+
sortExplorerItems(children);
|
|
3073
|
+
const visible = [];
|
|
3074
|
+
const displayRoot = path.endsWith(pathSeparator) ? path : path + pathSeparator;
|
|
3075
|
+
for (const child of children) {
|
|
3076
|
+
if (excluded.includes(child.name)) {
|
|
3077
|
+
continue;
|
|
3078
|
+
}
|
|
3079
|
+
visible.push(child);
|
|
3080
|
+
}
|
|
3081
|
+
const visibleLength = visible.length;
|
|
3082
|
+
for (let i = 0; i < visibleLength; i++) {
|
|
3083
|
+
const child = visible[i];
|
|
3084
|
+
const {
|
|
3085
|
+
name,
|
|
3086
|
+
type
|
|
3087
|
+
} = child;
|
|
3088
|
+
const childPath = displayRoot + name;
|
|
3089
|
+
if ((child.type === Directory || child.type === SymLinkFolder) && childPath in map) {
|
|
3090
|
+
dirents.push({
|
|
3091
|
+
depth,
|
|
3092
|
+
posInSet: i + 1,
|
|
3093
|
+
setSize: visibleLength,
|
|
3094
|
+
icon: getFolderIcon(),
|
|
3095
|
+
name,
|
|
3096
|
+
path: childPath,
|
|
3097
|
+
type: DirectoryExpanded
|
|
3098
|
+
});
|
|
3099
|
+
dirents.push(...getSavedChildDirents(map, childPath, depth + 1, excluded, pathSeparator));
|
|
3100
|
+
} else {
|
|
3101
|
+
dirents.push({
|
|
3102
|
+
depth,
|
|
3103
|
+
posInSet: i + 1,
|
|
3104
|
+
setSize: visibleLength,
|
|
3105
|
+
icon: getIcon(),
|
|
3106
|
+
name,
|
|
3107
|
+
path: childPath,
|
|
3108
|
+
type
|
|
3109
|
+
});
|
|
3110
|
+
}
|
|
3111
|
+
}
|
|
3112
|
+
return dirents;
|
|
3113
|
+
};
|
|
3114
|
+
const createDirents = (root, expandedDirentPaths, expandedDirentChildren, excluded, pathSeparator) => {
|
|
3115
|
+
const dirents = [];
|
|
3116
|
+
const map = Object.create(null);
|
|
3117
|
+
for (let i = 0; i < expandedDirentPaths.length; i++) {
|
|
3118
|
+
const path = expandedDirentPaths[i];
|
|
3119
|
+
const children = expandedDirentChildren[i];
|
|
3120
|
+
if (children.status === Fulfilled) {
|
|
3121
|
+
map[path] = children.value;
|
|
3122
|
+
}
|
|
3123
|
+
}
|
|
3124
|
+
dirents.push(...getSavedChildDirents(map, root, 1, excluded, pathSeparator));
|
|
3125
|
+
return dirents;
|
|
3126
|
+
};
|
|
3127
|
+
const getSavedExpandedPaths = (savedState, root) => {
|
|
3128
|
+
if (savedState && savedState.root !== root) {
|
|
3129
|
+
return [];
|
|
3130
|
+
}
|
|
3131
|
+
if (savedState && savedState.expandedPaths && Array.isArray(savedState.expandedPaths)) {
|
|
3132
|
+
return savedState.expandedPaths;
|
|
3133
|
+
}
|
|
3134
|
+
return [];
|
|
2991
3135
|
};
|
|
2992
3136
|
const restoreExpandedState = async (savedState, root, pathSeparator, excluded) => {
|
|
2993
|
-
|
|
3137
|
+
// TODO read all opened folders in parallel
|
|
3138
|
+
// ignore ENOENT errors
|
|
3139
|
+
// ignore ENOTDIR errors
|
|
3140
|
+
// merge all dirents
|
|
3141
|
+
// restore scroll location
|
|
3142
|
+
const expandedPaths = getSavedExpandedPaths(savedState, root);
|
|
3143
|
+
if (root === EmptyString) {
|
|
2994
3144
|
return [];
|
|
2995
3145
|
}
|
|
3146
|
+
const expandedDirentPaths = [root, ...expandedPaths];
|
|
3147
|
+
const expandedDirentChildren = await Promise.allSettled(expandedDirentPaths.map(getChildDirentsRaw));
|
|
3148
|
+
if (expandedDirentChildren[0].status === Rejected) {
|
|
3149
|
+
throw expandedDirentChildren[0].reason;
|
|
3150
|
+
}
|
|
3151
|
+
const dirents = createDirents(root, expandedDirentPaths, expandedDirentChildren, excluded, pathSeparator);
|
|
3152
|
+
return dirents;
|
|
2996
3153
|
};
|
|
2997
3154
|
const getExcluded = () => {
|
|
2998
3155
|
const excludedObject = {};
|
|
@@ -3008,11 +3165,12 @@ const getSavedRoot$1 = (savedState, workspacePath) => {
|
|
|
3008
3165
|
return workspacePath;
|
|
3009
3166
|
};
|
|
3010
3167
|
const loadContent = async (state, savedState) => {
|
|
3011
|
-
const
|
|
3168
|
+
const workspacePath = await getWorkspacePath();
|
|
3169
|
+
const root = getSavedRoot$1(savedState, workspacePath);
|
|
3012
3170
|
// TODO path separator could be restored from saved state
|
|
3013
|
-
const pathSeparator = await getPathSeparator(); // TODO only load path separator once
|
|
3171
|
+
const pathSeparator = await getPathSeparator(root); // TODO only load path separator once
|
|
3014
3172
|
const excluded = getExcluded();
|
|
3015
|
-
const restoredDirents = await restoreExpandedState();
|
|
3173
|
+
const restoredDirents = await restoreExpandedState(savedState, root, pathSeparator, excluded);
|
|
3016
3174
|
const {
|
|
3017
3175
|
itemHeight,
|
|
3018
3176
|
height
|
|
@@ -3038,6 +3196,45 @@ const loadContent = async (state, savedState) => {
|
|
|
3038
3196
|
};
|
|
3039
3197
|
};
|
|
3040
3198
|
|
|
3199
|
+
const ExplorerEditBox = FocusExplorerEditBox;
|
|
3200
|
+
|
|
3201
|
+
const setFocus = key => {
|
|
3202
|
+
return invoke('Focus.setFocus', key);
|
|
3203
|
+
};
|
|
3204
|
+
|
|
3205
|
+
const newDirent = async (state, editingType) => {
|
|
3206
|
+
// TODO make focus functional instead of side effect
|
|
3207
|
+
await setFocus(ExplorerEditBox);
|
|
3208
|
+
// TODO do it like vscode, select position between folders and files
|
|
3209
|
+
const {
|
|
3210
|
+
focusedIndex,
|
|
3211
|
+
items
|
|
3212
|
+
} = state;
|
|
3213
|
+
if (focusedIndex >= 0) {
|
|
3214
|
+
const dirent = items[focusedIndex];
|
|
3215
|
+
if (dirent.type === Directory) {
|
|
3216
|
+
// TODO handle error
|
|
3217
|
+
// @ts-ignore
|
|
3218
|
+
await undefined(state, dirent, focusedIndex);
|
|
3219
|
+
}
|
|
3220
|
+
}
|
|
3221
|
+
return {
|
|
3222
|
+
...state,
|
|
3223
|
+
editingIndex: focusedIndex,
|
|
3224
|
+
editingType,
|
|
3225
|
+
editingValue: ''
|
|
3226
|
+
};
|
|
3227
|
+
};
|
|
3228
|
+
|
|
3229
|
+
// TODO much shared logic with newFolder
|
|
3230
|
+
const newFile = state => {
|
|
3231
|
+
return newDirent(state, CreateFile);
|
|
3232
|
+
};
|
|
3233
|
+
|
|
3234
|
+
const newFolder = state => {
|
|
3235
|
+
return newDirent(state, CreateFolder);
|
|
3236
|
+
};
|
|
3237
|
+
|
|
3041
3238
|
const getContaingingFolder = (root, dirents, focusedIndex, pathSeparator) => {
|
|
3042
3239
|
if (focusedIndex < 0) {
|
|
3043
3240
|
return root;
|
|
@@ -3060,6 +3257,123 @@ const openContainingFolder = async state => {
|
|
|
3060
3257
|
return state;
|
|
3061
3258
|
};
|
|
3062
3259
|
|
|
3260
|
+
// TODO support multiselection and removing multiple dirents
|
|
3261
|
+
const removeDirent = async state => {
|
|
3262
|
+
if (state.focusedIndex < 0) {
|
|
3263
|
+
return state;
|
|
3264
|
+
}
|
|
3265
|
+
const dirent = getFocusedDirent$1(state);
|
|
3266
|
+
const absolutePath = dirent.path;
|
|
3267
|
+
try {
|
|
3268
|
+
// TODO handle error
|
|
3269
|
+
await remove(absolutePath);
|
|
3270
|
+
} catch (error) {
|
|
3271
|
+
// TODO vscode shows error as alert (no stacktrace) and retry button
|
|
3272
|
+
// maybe should show alert as well, but where to put stacktrace?
|
|
3273
|
+
// on web should probably show notification (dialog)
|
|
3274
|
+
// ErrorHandling.handleError(error)
|
|
3275
|
+
// await ErrorHandling.showErrorDialog(error)
|
|
3276
|
+
return;
|
|
3277
|
+
}
|
|
3278
|
+
// TODO avoid state mutation
|
|
3279
|
+
const newVersion = ++state.version;
|
|
3280
|
+
// TODO race condition
|
|
3281
|
+
// const newState = await loadContent(state:any)
|
|
3282
|
+
if (state.version !== newVersion || state.disposed) {
|
|
3283
|
+
return state;
|
|
3284
|
+
}
|
|
3285
|
+
// TODO is it possible to make this more functional instead of mutating state?
|
|
3286
|
+
// maybe every function returns a new state?
|
|
3287
|
+
const index = state.items.indexOf(dirent);
|
|
3288
|
+
let deleteEnd = index + 1;
|
|
3289
|
+
for (; deleteEnd < state.items.length; deleteEnd++) {
|
|
3290
|
+
if (state.items[deleteEnd].depth <= dirent.depth) {
|
|
3291
|
+
break;
|
|
3292
|
+
}
|
|
3293
|
+
}
|
|
3294
|
+
const deleteCount = deleteEnd - index;
|
|
3295
|
+
const newDirents = [...state.items];
|
|
3296
|
+
newDirents.splice(index, deleteCount);
|
|
3297
|
+
let indexToFocus = -1;
|
|
3298
|
+
if (newDirents.length === 0) {
|
|
3299
|
+
indexToFocus = -1;
|
|
3300
|
+
} else if (index < state.focusedIndex) {
|
|
3301
|
+
indexToFocus = state.focusedIndex - 1;
|
|
3302
|
+
} else if (index === state.focusedIndex) {
|
|
3303
|
+
indexToFocus = Math.max(state.focusedIndex - 1, 0);
|
|
3304
|
+
} else {
|
|
3305
|
+
indexToFocus = Math.max(state.focusedIndex - 1, 0);
|
|
3306
|
+
}
|
|
3307
|
+
return {
|
|
3308
|
+
...state,
|
|
3309
|
+
items: newDirents,
|
|
3310
|
+
focusedIndex: indexToFocus
|
|
3311
|
+
};
|
|
3312
|
+
};
|
|
3313
|
+
|
|
3314
|
+
const renameDirent = state => {
|
|
3315
|
+
const {
|
|
3316
|
+
focusedIndex,
|
|
3317
|
+
items
|
|
3318
|
+
} = state;
|
|
3319
|
+
const item = items[focusedIndex];
|
|
3320
|
+
// Focus.setFocus(FocusKey.ExplorerEditBox)
|
|
3321
|
+
return {
|
|
3322
|
+
...state,
|
|
3323
|
+
editingIndex: focusedIndex,
|
|
3324
|
+
editingType: Rename$1,
|
|
3325
|
+
editingValue: item.name
|
|
3326
|
+
};
|
|
3327
|
+
};
|
|
3328
|
+
|
|
3329
|
+
const getIconVirtualDom = (icon, type = Div) => {
|
|
3330
|
+
return {
|
|
3331
|
+
type,
|
|
3332
|
+
className: `MaskIcon MaskIcon${icon}`,
|
|
3333
|
+
role: None$2,
|
|
3334
|
+
childCount: 0
|
|
3335
|
+
};
|
|
3336
|
+
};
|
|
3337
|
+
|
|
3338
|
+
const getActionButtonVirtualDom = action => {
|
|
3339
|
+
const {
|
|
3340
|
+
id,
|
|
3341
|
+
icon,
|
|
3342
|
+
command
|
|
3343
|
+
} = action;
|
|
3344
|
+
return [{
|
|
3345
|
+
type: Button,
|
|
3346
|
+
className: IconButton,
|
|
3347
|
+
title: id,
|
|
3348
|
+
'data-command': command,
|
|
3349
|
+
childCount: 1
|
|
3350
|
+
}, getIconVirtualDom(icon)];
|
|
3351
|
+
};
|
|
3352
|
+
|
|
3353
|
+
const getActionVirtualDom = action => {
|
|
3354
|
+
switch (action.type) {
|
|
3355
|
+
case Button$2:
|
|
3356
|
+
return getActionButtonVirtualDom(action);
|
|
3357
|
+
default:
|
|
3358
|
+
return [];
|
|
3359
|
+
}
|
|
3360
|
+
};
|
|
3361
|
+
|
|
3362
|
+
const getActionsVirtualDom = actions => {
|
|
3363
|
+
return [{
|
|
3364
|
+
type: Div,
|
|
3365
|
+
className: Actions,
|
|
3366
|
+
role: ToolBar,
|
|
3367
|
+
childCount: actions.length
|
|
3368
|
+
}, ...actions.flatMap(getActionVirtualDom)];
|
|
3369
|
+
};
|
|
3370
|
+
|
|
3371
|
+
const renderActions = state => {
|
|
3372
|
+
const actions = getActions(state.root);
|
|
3373
|
+
const dom = getActionsVirtualDom(actions);
|
|
3374
|
+
return dom;
|
|
3375
|
+
};
|
|
3376
|
+
|
|
3063
3377
|
const getSavedRoot = (savedState, workspacePath) => {
|
|
3064
3378
|
return workspacePath;
|
|
3065
3379
|
};
|
|
@@ -3309,12 +3623,14 @@ const revealItem = async (state, uri) => {
|
|
|
3309
3623
|
return revealItemVisible(state, index);
|
|
3310
3624
|
};
|
|
3311
3625
|
|
|
3312
|
-
const isExpandedDirectory = dirent => {
|
|
3313
|
-
return dirent.type === DirectoryExpanded;
|
|
3314
|
-
};
|
|
3315
3626
|
const getPath = dirent => {
|
|
3316
3627
|
return dirent.path;
|
|
3317
3628
|
};
|
|
3629
|
+
|
|
3630
|
+
const isExpandedDirectory = dirent => {
|
|
3631
|
+
return dirent.type === DirectoryExpanded;
|
|
3632
|
+
};
|
|
3633
|
+
|
|
3318
3634
|
const saveState = state => {
|
|
3319
3635
|
const {
|
|
3320
3636
|
items,
|
|
@@ -3333,9 +3649,45 @@ const saveState = state => {
|
|
|
3333
3649
|
};
|
|
3334
3650
|
};
|
|
3335
3651
|
|
|
3652
|
+
const setDeltaY = (state, deltaY) => {
|
|
3653
|
+
const {
|
|
3654
|
+
itemHeight,
|
|
3655
|
+
height,
|
|
3656
|
+
items
|
|
3657
|
+
} = state;
|
|
3658
|
+
if (deltaY < 0) {
|
|
3659
|
+
deltaY = 0;
|
|
3660
|
+
} else if (deltaY > items.length * itemHeight - height) {
|
|
3661
|
+
deltaY = Math.max(items.length * itemHeight - height, 0);
|
|
3662
|
+
}
|
|
3663
|
+
if (state.deltaY === deltaY) {
|
|
3664
|
+
return state;
|
|
3665
|
+
}
|
|
3666
|
+
const minLineY = Math.round(deltaY / itemHeight);
|
|
3667
|
+
const maxLineY = minLineY + Math.round(height / itemHeight);
|
|
3668
|
+
return {
|
|
3669
|
+
...state,
|
|
3670
|
+
deltaY,
|
|
3671
|
+
minLineY,
|
|
3672
|
+
maxLineY
|
|
3673
|
+
};
|
|
3674
|
+
};
|
|
3675
|
+
|
|
3676
|
+
const updateEditingValue = (state, value) => {
|
|
3677
|
+
const editingIcon = getFileIcon({
|
|
3678
|
+
name: value
|
|
3679
|
+
});
|
|
3680
|
+
return {
|
|
3681
|
+
...state,
|
|
3682
|
+
editingValue: value,
|
|
3683
|
+
editingIcon
|
|
3684
|
+
};
|
|
3685
|
+
};
|
|
3686
|
+
|
|
3336
3687
|
const commandMap = {
|
|
3337
3688
|
'Explorer.acceptEdit': acceptEdit,
|
|
3338
3689
|
'Explorer.cancelEdit': cancelEdit,
|
|
3690
|
+
'Explorer.collapseAll': collapseAll$1,
|
|
3339
3691
|
'Explorer.copyPath': copyPath$1,
|
|
3340
3692
|
'Explorer.copyRelativePath': copyRelativePath$1,
|
|
3341
3693
|
'Explorer.expandAll': expandAll,
|
|
@@ -3345,6 +3697,7 @@ const commandMap = {
|
|
|
3345
3697
|
'Explorer.focusLast': focusLast,
|
|
3346
3698
|
'Explorer.focusNext': focusNext,
|
|
3347
3699
|
'Explorer.focusPrevious': focusPrevious,
|
|
3700
|
+
'Explorer.getActions': getActions,
|
|
3348
3701
|
'Explorer.getKeyBindings': getKeyBindings,
|
|
3349
3702
|
'Explorer.getMenuEntries': getMenuEntries,
|
|
3350
3703
|
'Explorer.getVirtualDom': getExplorerVirtualDom,
|
|
@@ -3357,18 +3710,25 @@ const commandMap = {
|
|
|
3357
3710
|
'Explorer.handleClickCurrentButKeepFocus': handleClickCurrentButKeepFocus,
|
|
3358
3711
|
'Explorer.handleClickOpenFolder': handleClickOpenFolder,
|
|
3359
3712
|
'Explorer.handleContextMenu': handleContextMenu,
|
|
3713
|
+
'Explorer.handleCopy': handleCopy,
|
|
3360
3714
|
'Explorer.handleDrop': handleDrop,
|
|
3361
3715
|
'Explorer.handleIconThemeChange': handleIconThemeChange,
|
|
3362
3716
|
'Explorer.handlePaste': handlePaste,
|
|
3363
3717
|
'Explorer.handlePointerDown': handlePointerDown,
|
|
3718
|
+
'Explorer.handleUpload': handleUpload,
|
|
3364
3719
|
'Explorer.handleWheel': handleWheel,
|
|
3365
3720
|
'Explorer.loadContent': loadContent,
|
|
3721
|
+
'Explorer.newFile': newFile,
|
|
3722
|
+
'Explorer.newFolder': newFolder,
|
|
3366
3723
|
'Explorer.openContainingFolder': openContainingFolder,
|
|
3367
3724
|
'Explorer.removeDirent': removeDirent,
|
|
3368
3725
|
'Explorer.renameDirent': renameDirent,
|
|
3726
|
+
'Explorer.renderActions': renderActions,
|
|
3369
3727
|
'Explorer.restoreState': restoreState,
|
|
3370
3728
|
'Explorer.revealItem': revealItem,
|
|
3371
|
-
'Explorer.saveState': saveState
|
|
3729
|
+
'Explorer.saveState': saveState,
|
|
3730
|
+
'Explorer.setDeltaY': setDeltaY,
|
|
3731
|
+
'Explorer.updateEditingValue': updateEditingValue
|
|
3372
3732
|
};
|
|
3373
3733
|
|
|
3374
3734
|
const listen = async () => {
|