@lvce-editor/explorer-view 2.54.0 → 2.56.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/explorerViewWorkerMain.js +121 -72
- package/package.json +1 -1
|
@@ -889,7 +889,7 @@ const Copy$2 = 3;
|
|
|
889
889
|
const Rename$2 = 4;
|
|
890
890
|
|
|
891
891
|
const rpcs = Object.create(null);
|
|
892
|
-
const set$
|
|
892
|
+
const set$g = (id, rpc) => {
|
|
893
893
|
rpcs[id] = rpc;
|
|
894
894
|
};
|
|
895
895
|
const get$1 = id => {
|
|
@@ -913,7 +913,7 @@ const create$2 = rpcId => {
|
|
|
913
913
|
return rpc.invokeAndTransfer(method, ...params);
|
|
914
914
|
},
|
|
915
915
|
set(rpc) {
|
|
916
|
-
set$
|
|
916
|
+
set$g(rpcId, rpc);
|
|
917
917
|
},
|
|
918
918
|
async dispose() {
|
|
919
919
|
const rpc = get$1(rpcId);
|
|
@@ -995,6 +995,23 @@ const applyFileOperations = async operations => {
|
|
|
995
995
|
}
|
|
996
996
|
};
|
|
997
997
|
|
|
998
|
+
const DELTA_EDITING = 100;
|
|
999
|
+
|
|
1000
|
+
const BlockDevice = 1;
|
|
1001
|
+
const CharacterDevice = 2;
|
|
1002
|
+
const Directory = 3;
|
|
1003
|
+
const DirectoryExpanded = 4;
|
|
1004
|
+
const DirectoryExpanding = 5;
|
|
1005
|
+
const File = 7;
|
|
1006
|
+
const Socket = 8;
|
|
1007
|
+
const Symlink = 9;
|
|
1008
|
+
const SymLinkFile = 10;
|
|
1009
|
+
const SymLinkFolder = 11;
|
|
1010
|
+
const Unknown = 12;
|
|
1011
|
+
const EditingFile = File + DELTA_EDITING;
|
|
1012
|
+
const EditingFolder = Directory + DELTA_EDITING;
|
|
1013
|
+
const EditingDirectoryExpanded = DirectoryExpanded + DELTA_EDITING;
|
|
1014
|
+
|
|
998
1015
|
const dirname = (pathSeparator, path) => {
|
|
999
1016
|
const index = path.lastIndexOf(pathSeparator);
|
|
1000
1017
|
if (index === -1) {
|
|
@@ -1015,16 +1032,32 @@ const join2 = (path, childPath) => {
|
|
|
1015
1032
|
return `${path}/${childPath}`;
|
|
1016
1033
|
};
|
|
1017
1034
|
|
|
1035
|
+
const getActualType = (type, expanded) => {
|
|
1036
|
+
const actualType = type === Directory && expanded ? DirectoryExpanded : type;
|
|
1037
|
+
return actualType;
|
|
1038
|
+
};
|
|
1018
1039
|
const createTree = (items, root) => {
|
|
1019
1040
|
const tree = Object.create(null);
|
|
1020
1041
|
const rootLength = root.length;
|
|
1021
|
-
|
|
1042
|
+
const paths = items.map(item => {
|
|
1022
1043
|
const relativePath = item.path.slice(rootLength);
|
|
1023
1044
|
const dirname = dirname2(relativePath);
|
|
1045
|
+
return dirname;
|
|
1046
|
+
});
|
|
1047
|
+
for (const item of items) {
|
|
1048
|
+
const {
|
|
1049
|
+
type,
|
|
1050
|
+
name,
|
|
1051
|
+
path
|
|
1052
|
+
} = item;
|
|
1053
|
+
const relativePath = path.slice(rootLength);
|
|
1054
|
+
const dirname = dirname2(relativePath);
|
|
1055
|
+
const isExpanded = paths.includes(relativePath);
|
|
1056
|
+
const actualType = getActualType(type, isExpanded);
|
|
1024
1057
|
tree[dirname] ||= [];
|
|
1025
1058
|
tree[dirname].push({
|
|
1026
|
-
name
|
|
1027
|
-
type:
|
|
1059
|
+
name,
|
|
1060
|
+
type: actualType
|
|
1028
1061
|
});
|
|
1029
1062
|
}
|
|
1030
1063
|
return tree;
|
|
@@ -1076,23 +1109,6 @@ const getPaths = items => {
|
|
|
1076
1109
|
return items.map(getPath);
|
|
1077
1110
|
};
|
|
1078
1111
|
|
|
1079
|
-
const DELTA_EDITING = 100;
|
|
1080
|
-
|
|
1081
|
-
const BlockDevice = 1;
|
|
1082
|
-
const CharacterDevice = 2;
|
|
1083
|
-
const Directory = 3;
|
|
1084
|
-
const DirectoryExpanded = 4;
|
|
1085
|
-
const DirectoryExpanding = 5;
|
|
1086
|
-
const File = 7;
|
|
1087
|
-
const Socket = 8;
|
|
1088
|
-
const Symlink = 9;
|
|
1089
|
-
const SymLinkFile = 10;
|
|
1090
|
-
const SymLinkFolder = 11;
|
|
1091
|
-
const Unknown = 12;
|
|
1092
|
-
const EditingFile = File + DELTA_EDITING;
|
|
1093
|
-
const EditingFolder = Directory + DELTA_EDITING;
|
|
1094
|
-
const EditingDirectoryExpanded = DirectoryExpanded + DELTA_EDITING;
|
|
1095
|
-
|
|
1096
1112
|
const getSimpleIconRequestType = direntType => {
|
|
1097
1113
|
if (direntType === Directory || direntType === DirectoryExpanded || direntType === EditingDirectoryExpanded || direntType === EditingFolder) {
|
|
1098
1114
|
return 2;
|
|
@@ -1197,13 +1213,14 @@ const getPathParts = (root, uri, pathSeparator) => {
|
|
|
1197
1213
|
const parts = [];
|
|
1198
1214
|
let index = root.length - 1;
|
|
1199
1215
|
let depth = 0;
|
|
1200
|
-
while ((index = uri.indexOf(
|
|
1216
|
+
while ((index = uri.indexOf(pathSeparator, index + 1)) !== -1) {
|
|
1201
1217
|
const partUri = uri.slice(0, index);
|
|
1202
1218
|
parts.push({
|
|
1203
1219
|
path: partUri,
|
|
1204
1220
|
depth: depth++,
|
|
1205
1221
|
root,
|
|
1206
|
-
pathSeparator
|
|
1222
|
+
pathSeparator,
|
|
1223
|
+
expanded: true
|
|
1207
1224
|
});
|
|
1208
1225
|
}
|
|
1209
1226
|
return parts;
|
|
@@ -1310,14 +1327,14 @@ const sortExplorerItems = rawDirents => {
|
|
|
1310
1327
|
};
|
|
1311
1328
|
|
|
1312
1329
|
// TODO figure out whether this uses too much memory (name,path -> redundant, depth could be computed on demand)
|
|
1313
|
-
const toDisplayDirent = (parentPath, parentDepth,
|
|
1314
|
-
const path = join2(parentPath,
|
|
1330
|
+
const toDisplayDirent = (parentPath, parentDepth, rawDirentType, rawDirentName, index, length) => {
|
|
1331
|
+
const path = join2(parentPath, rawDirentName);
|
|
1315
1332
|
return {
|
|
1316
|
-
name:
|
|
1333
|
+
name: rawDirentName,
|
|
1317
1334
|
posInSet: index + 1,
|
|
1318
1335
|
setSize: length,
|
|
1319
1336
|
depth: parentDepth + 1,
|
|
1320
|
-
type:
|
|
1337
|
+
type: rawDirentType,
|
|
1321
1338
|
path,
|
|
1322
1339
|
// TODO storing absolute path might be too costly, could also store relative path here
|
|
1323
1340
|
icon: '',
|
|
@@ -1325,7 +1342,7 @@ const toDisplayDirent = (parentPath, parentDepth, rawDirent, index, length) => {
|
|
|
1325
1342
|
};
|
|
1326
1343
|
};
|
|
1327
1344
|
|
|
1328
|
-
const toDisplayDirents = (pathSeparator, rawDirents, parentDirentPath, parentDirentDepth, excluded) => {
|
|
1345
|
+
const toDisplayDirents = (pathSeparator, rawDirents, parentDirentPath, parentDirentDepth, excluded, expanded = false) => {
|
|
1329
1346
|
rawDirents = sortExplorerItems(rawDirents);
|
|
1330
1347
|
const result = [];
|
|
1331
1348
|
const visibleItems = rawDirents.filter(item => {
|
|
@@ -1337,7 +1354,7 @@ const toDisplayDirents = (pathSeparator, rawDirents, parentDirentPath, parentDir
|
|
|
1337
1354
|
const count = visibleItems.length;
|
|
1338
1355
|
for (let i = 0; i < visibleItems.length; i++) {
|
|
1339
1356
|
const rawDirent = visibleItems[i];
|
|
1340
|
-
result.push(toDisplayDirent(parentDirentPath, parentDirentDepth, rawDirent, i, count));
|
|
1357
|
+
result.push(toDisplayDirent(parentDirentPath, parentDirentDepth, rawDirent.type, rawDirent.name, i, count));
|
|
1341
1358
|
}
|
|
1342
1359
|
return result;
|
|
1343
1360
|
};
|
|
@@ -1448,6 +1465,7 @@ const CopyPath = 'Copy Path';
|
|
|
1448
1465
|
const CopyRelativePath = 'Copy Relative Path';
|
|
1449
1466
|
const Cut$1 = 'Cut';
|
|
1450
1467
|
const Delete$1 = 'Delete';
|
|
1468
|
+
const FileNameCannotStartWithSlash = 'A file or folder name cannot start with a slash.';
|
|
1451
1469
|
const FileOrFolderNameMustBeProvider = 'A file or folder name must be provided.';
|
|
1452
1470
|
const FilesExplorer = 'Files Explorer';
|
|
1453
1471
|
const NewFile$1 = 'New File...';
|
|
@@ -1512,6 +1530,9 @@ const openFolder$1 = () => {
|
|
|
1512
1530
|
const fileOrFolderNameMustBeProvided = () => {
|
|
1513
1531
|
return i18nString(FileOrFolderNameMustBeProvider);
|
|
1514
1532
|
};
|
|
1533
|
+
const fileCannotStartWithSlash = () => {
|
|
1534
|
+
return i18nString(FileNameCannotStartWithSlash);
|
|
1535
|
+
};
|
|
1515
1536
|
const typeAFileName = () => {
|
|
1516
1537
|
return i18nString(TypeAFileName);
|
|
1517
1538
|
};
|
|
@@ -1521,6 +1542,9 @@ const validateFileName2 = name => {
|
|
|
1521
1542
|
const editingErrorMessage = fileOrFolderNameMustBeProvided();
|
|
1522
1543
|
return editingErrorMessage;
|
|
1523
1544
|
}
|
|
1545
|
+
if (name.startsWith('/')) {
|
|
1546
|
+
return fileCannotStartWithSlash();
|
|
1547
|
+
}
|
|
1524
1548
|
return '';
|
|
1525
1549
|
};
|
|
1526
1550
|
|
|
@@ -3680,6 +3704,49 @@ const handleKeyDown = (state, key) => {
|
|
|
3680
3704
|
};
|
|
3681
3705
|
};
|
|
3682
3706
|
|
|
3707
|
+
const scrollInto = (index, minLineY, maxLineY) => {
|
|
3708
|
+
const diff = maxLineY - minLineY;
|
|
3709
|
+
const smallerHalf = Math.floor(diff / 2);
|
|
3710
|
+
const largerHalf = diff - smallerHalf;
|
|
3711
|
+
if (index < minLineY) {
|
|
3712
|
+
return {
|
|
3713
|
+
newMinLineY: index - smallerHalf,
|
|
3714
|
+
newMaxLineY: index + largerHalf
|
|
3715
|
+
};
|
|
3716
|
+
}
|
|
3717
|
+
if (index >= maxLineY) {
|
|
3718
|
+
return {
|
|
3719
|
+
newMinLineY: index - smallerHalf,
|
|
3720
|
+
newMaxLineY: index + largerHalf
|
|
3721
|
+
};
|
|
3722
|
+
}
|
|
3723
|
+
return {
|
|
3724
|
+
newMinLineY: minLineY,
|
|
3725
|
+
newMaxLineY: maxLineY
|
|
3726
|
+
};
|
|
3727
|
+
};
|
|
3728
|
+
|
|
3729
|
+
const adjustScrollAfterPaste = (state, focusedIndex) => {
|
|
3730
|
+
const {
|
|
3731
|
+
minLineY,
|
|
3732
|
+
maxLineY,
|
|
3733
|
+
itemHeight
|
|
3734
|
+
} = state;
|
|
3735
|
+
const {
|
|
3736
|
+
newMinLineY,
|
|
3737
|
+
newMaxLineY
|
|
3738
|
+
} = scrollInto(focusedIndex, minLineY, maxLineY);
|
|
3739
|
+
const newDeltaY = newMinLineY * itemHeight;
|
|
3740
|
+
return {
|
|
3741
|
+
...state,
|
|
3742
|
+
focusedIndex,
|
|
3743
|
+
focused: true,
|
|
3744
|
+
minLineY: newMinLineY,
|
|
3745
|
+
maxLineY: newMaxLineY,
|
|
3746
|
+
deltaY: newDeltaY
|
|
3747
|
+
};
|
|
3748
|
+
};
|
|
3749
|
+
|
|
3683
3750
|
const generateUniqueName = (baseName, existingPaths, root) => {
|
|
3684
3751
|
// Handle files with extensions
|
|
3685
3752
|
const lastDotIndex = baseName.lastIndexOf('.');
|
|
@@ -3756,17 +3823,13 @@ const handlePasteCopy = async (state, nativeFiles) => {
|
|
|
3756
3823
|
// TODO only update folder at which level it changed
|
|
3757
3824
|
const latestState = await refresh(state);
|
|
3758
3825
|
|
|
3759
|
-
// Focus on the first newly created file
|
|
3826
|
+
// Focus on the first newly created file and adjust scroll position
|
|
3760
3827
|
const newFilePaths = operations.map(operation => operation.path);
|
|
3761
3828
|
if (newFilePaths.length > 0) {
|
|
3762
3829
|
const firstNewFilePath = newFilePaths[0];
|
|
3763
3830
|
const newFileIndex = getIndex(latestState.items, firstNewFilePath);
|
|
3764
3831
|
if (newFileIndex !== -1) {
|
|
3765
|
-
return
|
|
3766
|
-
...latestState,
|
|
3767
|
-
focusedIndex: newFileIndex,
|
|
3768
|
-
focused: true
|
|
3769
|
-
};
|
|
3832
|
+
return adjustScrollAfterPaste(latestState, newFileIndex);
|
|
3770
3833
|
}
|
|
3771
3834
|
}
|
|
3772
3835
|
// If there are no items, ensure focusedIndex is 0
|
|
@@ -3784,7 +3847,20 @@ const handlePasteCut = async (state, nativeFiles) => {
|
|
|
3784
3847
|
const target = `${state.root}${state.pathSeparator}${getBaseName(state.pathSeparator, source)}`;
|
|
3785
3848
|
await rename$1(source, target);
|
|
3786
3849
|
}
|
|
3787
|
-
|
|
3850
|
+
|
|
3851
|
+
// Refresh the state after cut operations
|
|
3852
|
+
const latestState = await refresh(state);
|
|
3853
|
+
|
|
3854
|
+
// Focus on the first pasted file and adjust scroll position
|
|
3855
|
+
if (nativeFiles.files.length > 0) {
|
|
3856
|
+
const firstPastedFile = nativeFiles.files[0];
|
|
3857
|
+
const targetPath = `${state.root}${state.pathSeparator}${getBaseName(state.pathSeparator, firstPastedFile)}`;
|
|
3858
|
+
const pastedFileIndex = getIndex(latestState.items, targetPath);
|
|
3859
|
+
if (pastedFileIndex !== -1) {
|
|
3860
|
+
return adjustScrollAfterPaste(latestState, pastedFileIndex);
|
|
3861
|
+
}
|
|
3862
|
+
}
|
|
3863
|
+
return latestState;
|
|
3788
3864
|
};
|
|
3789
3865
|
|
|
3790
3866
|
const handlePasteNone = async (state, nativeFiles) => {
|
|
@@ -3797,18 +3873,6 @@ const Copy = 'copy';
|
|
|
3797
3873
|
const Cut = 'cut';
|
|
3798
3874
|
|
|
3799
3875
|
const getPasteHandler = type => {
|
|
3800
|
-
// TODO detect cut/paste event, not sure if that is possible
|
|
3801
|
-
// TODO check that pasted folder is not a parent folder of opened folder
|
|
3802
|
-
// TODO support pasting multiple paths
|
|
3803
|
-
// TODO what happens when pasting multiple paths, but some of them error?
|
|
3804
|
-
// how many error messages should be shown? Should the operation be undone?
|
|
3805
|
-
// TODO what if it is a large folder and takes a long time to copy? Should show progress
|
|
3806
|
-
// TODO what if there is a permission error? Probably should show a modal to ask for permission
|
|
3807
|
-
// TODO if error is EEXISTS, just rename the copy (e.g. file-copy-1.txt, file-copy-2.txt)
|
|
3808
|
-
// TODO actual target should be selected folder
|
|
3809
|
-
// TODO but what if a file is currently selected? Then maybe the parent folder
|
|
3810
|
-
// TODO but will it work if the folder is a symlink?
|
|
3811
|
-
// TODO handle error gracefully when copy fails
|
|
3812
3876
|
switch (type) {
|
|
3813
3877
|
case None$3:
|
|
3814
3878
|
return handlePasteNone;
|
|
@@ -3823,6 +3887,9 @@ const getPasteHandler = type => {
|
|
|
3823
3887
|
|
|
3824
3888
|
const handlePaste = async state => {
|
|
3825
3889
|
const nativeFiles = await readNativeFiles();
|
|
3890
|
+
if (!nativeFiles) {
|
|
3891
|
+
return state;
|
|
3892
|
+
}
|
|
3826
3893
|
// TODO detect cut/paste event, not sure if that is possible
|
|
3827
3894
|
// TODO check that pasted folder is not a parent folder of opened folder
|
|
3828
3895
|
// TODO support pasting multiple paths
|
|
@@ -4312,7 +4379,11 @@ const removeDirent = async state => {
|
|
|
4312
4379
|
// TODO use file operations, bulk edit and explorer refresh
|
|
4313
4380
|
await removePaths(toRemove);
|
|
4314
4381
|
const newState = await refresh(state);
|
|
4315
|
-
return
|
|
4382
|
+
return {
|
|
4383
|
+
...newState,
|
|
4384
|
+
focused: true,
|
|
4385
|
+
focus: List
|
|
4386
|
+
};
|
|
4316
4387
|
};
|
|
4317
4388
|
|
|
4318
4389
|
const getEditingType = direntType => {
|
|
@@ -5132,28 +5203,6 @@ const mergeVisibleWithHiddenItems = (visibleItems, hiddenItems) => {
|
|
|
5132
5203
|
return unique;
|
|
5133
5204
|
};
|
|
5134
5205
|
|
|
5135
|
-
const scrollInto = (index, minLineY, maxLineY) => {
|
|
5136
|
-
const diff = maxLineY - minLineY;
|
|
5137
|
-
const smallerHalf = Math.floor(diff / 2);
|
|
5138
|
-
const largerHalf = diff - smallerHalf;
|
|
5139
|
-
if (index < minLineY) {
|
|
5140
|
-
return {
|
|
5141
|
-
newMinLineY: index - smallerHalf,
|
|
5142
|
-
newMaxLineY: index + largerHalf
|
|
5143
|
-
};
|
|
5144
|
-
}
|
|
5145
|
-
if (index >= maxLineY) {
|
|
5146
|
-
return {
|
|
5147
|
-
newMinLineY: index - smallerHalf,
|
|
5148
|
-
newMaxLineY: index + largerHalf
|
|
5149
|
-
};
|
|
5150
|
-
}
|
|
5151
|
-
return {
|
|
5152
|
-
newMinLineY: minLineY,
|
|
5153
|
-
newMaxLineY: maxLineY
|
|
5154
|
-
};
|
|
5155
|
-
};
|
|
5156
|
-
|
|
5157
5206
|
// TODO maybe just insert items into explorer and refresh whole explorer
|
|
5158
5207
|
const revealItemHidden = async (state, uri) => {
|
|
5159
5208
|
const {
|