@lvce-editor/explorer-view 2.29.0 → 2.31.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 +154 -94
- package/package.json +1 -1
|
@@ -985,8 +985,12 @@ const getMissingIconRequests = (dirents, fileIconCache) => {
|
|
|
985
985
|
return missingRequests;
|
|
986
986
|
};
|
|
987
987
|
|
|
988
|
-
const getPath =
|
|
989
|
-
return
|
|
988
|
+
const getPath = item => {
|
|
989
|
+
return item.path;
|
|
990
|
+
};
|
|
991
|
+
|
|
992
|
+
const getPaths = items => {
|
|
993
|
+
return items.map(getPath);
|
|
990
994
|
};
|
|
991
995
|
|
|
992
996
|
const DELTA_EDITING = 100;
|
|
@@ -1058,7 +1062,7 @@ const getFileIcons = async (dirents, fileIconCache) => {
|
|
|
1058
1062
|
const missingRequests = getMissingIconRequests(dirents, fileIconCache);
|
|
1059
1063
|
const newIcons = await requestFileIcons(missingRequests);
|
|
1060
1064
|
const newFileIconCache = updateIconCache(fileIconCache, missingRequests, newIcons);
|
|
1061
|
-
const paths = dirents
|
|
1065
|
+
const paths = getPaths(dirents);
|
|
1062
1066
|
const icons = getIconsCached(paths, newFileIconCache);
|
|
1063
1067
|
return {
|
|
1064
1068
|
icons,
|
|
@@ -1653,7 +1657,11 @@ const create2 = (uid, uri, x, y, width, height, args, parentUid, platform = 0) =
|
|
|
1653
1657
|
end: 0
|
|
1654
1658
|
},
|
|
1655
1659
|
focusWord: '',
|
|
1656
|
-
focusWordTimeout: 800
|
|
1660
|
+
focusWordTimeout: 800,
|
|
1661
|
+
finalDeltaY: 0,
|
|
1662
|
+
handleOffset: 0,
|
|
1663
|
+
scrollBarActive: false,
|
|
1664
|
+
scrollBarHeight: 0
|
|
1657
1665
|
};
|
|
1658
1666
|
set(uid, state, state);
|
|
1659
1667
|
};
|
|
@@ -1696,7 +1704,11 @@ const create = (id, uri, x, y, width, height, args, parentUid, platform = 0) =>
|
|
|
1696
1704
|
end: 0
|
|
1697
1705
|
},
|
|
1698
1706
|
focusWord: '',
|
|
1699
|
-
focusWordTimeout: 800
|
|
1707
|
+
focusWordTimeout: 800,
|
|
1708
|
+
finalDeltaY: 0,
|
|
1709
|
+
handleOffset: 0,
|
|
1710
|
+
scrollBarActive: false,
|
|
1711
|
+
scrollBarHeight: 0
|
|
1700
1712
|
};
|
|
1701
1713
|
set(state.uid, state, state);
|
|
1702
1714
|
return state;
|
|
@@ -2968,23 +2980,37 @@ const handleDragOver = (state, x, y) => {
|
|
|
2968
2980
|
};
|
|
2969
2981
|
};
|
|
2970
2982
|
|
|
2971
|
-
const
|
|
2972
|
-
|
|
2973
|
-
return [];
|
|
2974
|
-
}
|
|
2975
|
-
return getChildDirents(pathSeparator, {
|
|
2976
|
-
depth: 0,
|
|
2977
|
-
path: root,
|
|
2978
|
-
type: Directory
|
|
2979
|
-
}, excluded);
|
|
2983
|
+
const isExpanded = item => {
|
|
2984
|
+
return item.type === DirectoryExpanded || item.type === DirectoryExpanding;
|
|
2980
2985
|
};
|
|
2981
2986
|
|
|
2982
|
-
const
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
2987
|
+
const getExpandedDirents = items => {
|
|
2988
|
+
return items.filter(isExpanded);
|
|
2989
|
+
};
|
|
2990
|
+
|
|
2991
|
+
const refreshChildDirent = async (folder, dirent, pathSeparator, expandedFolders) => {
|
|
2992
|
+
const path = folder.path.endsWith(pathSeparator) ? `${folder.path}${dirent.name}` : `${folder.path}${pathSeparator}${dirent.name}`;
|
|
2993
|
+
const isExpandedFolder = expandedFolders.includes(path);
|
|
2994
|
+
const type = dirent.type === 'directory' ? isExpandedFolder ? DirectoryExpanded : Directory : File;
|
|
2995
|
+
const item = {
|
|
2996
|
+
name: dirent.name,
|
|
2997
|
+
type,
|
|
2998
|
+
path,
|
|
2999
|
+
depth: folder.depth + 1,
|
|
3000
|
+
selected: false
|
|
3001
|
+
};
|
|
3002
|
+
if (isExpandedFolder) {
|
|
3003
|
+
const nestedItems = await refreshChildDirents(item, pathSeparator, expandedFolders);
|
|
3004
|
+
return [item, ...nestedItems];
|
|
2986
3005
|
}
|
|
2987
|
-
return
|
|
3006
|
+
return [item];
|
|
3007
|
+
};
|
|
3008
|
+
const refreshChildDirents = async (folder, pathSeparator, expandedFolders) => {
|
|
3009
|
+
const childDirents = await readDirWithFileTypes(folder.path);
|
|
3010
|
+
const childItems = await Promise.all(childDirents.map(async dirent => {
|
|
3011
|
+
return refreshChildDirent(folder, dirent, pathSeparator, expandedFolders);
|
|
3012
|
+
}));
|
|
3013
|
+
return childItems.flat();
|
|
2988
3014
|
};
|
|
2989
3015
|
|
|
2990
3016
|
// TODO add lots of tests for this
|
|
@@ -2995,24 +3021,73 @@ const refresh = async state => {
|
|
|
2995
3021
|
minLineY,
|
|
2996
3022
|
height,
|
|
2997
3023
|
itemHeight,
|
|
2998
|
-
fileIconCache
|
|
3024
|
+
fileIconCache,
|
|
3025
|
+
items,
|
|
3026
|
+
focusedIndex
|
|
2999
3027
|
} = state;
|
|
3000
|
-
|
|
3001
|
-
|
|
3028
|
+
|
|
3029
|
+
// Get all expanded folders
|
|
3030
|
+
const expandedDirents = getExpandedDirents(items);
|
|
3031
|
+
const expandedFolders = getPaths(expandedDirents);
|
|
3032
|
+
|
|
3033
|
+
// Get top level dirents
|
|
3034
|
+
const topLevelDirents = await readDirWithFileTypes(root);
|
|
3035
|
+
const newDirents = topLevelDirents.map(dirent => ({
|
|
3036
|
+
name: dirent.name,
|
|
3037
|
+
type: dirent.type === 'directory' ? Directory : File,
|
|
3038
|
+
path: root.endsWith(pathSeparator) ? `${root}${dirent.name}` : `${root}${pathSeparator}${dirent.name}`,
|
|
3039
|
+
depth: 0,
|
|
3040
|
+
selected: false
|
|
3041
|
+
}));
|
|
3042
|
+
|
|
3043
|
+
// Process expanded folders in parallel
|
|
3044
|
+
const expandedFolderResults = await Promise.all(expandedFolders.map(async folderPath => {
|
|
3045
|
+
const folderIndex = newDirents.findIndex(item => item.path === folderPath);
|
|
3046
|
+
if (folderIndex !== -1) {
|
|
3047
|
+
const folder = newDirents[folderIndex];
|
|
3048
|
+
if (folder.type === Directory) {
|
|
3049
|
+
const childItems = await refreshChildDirents(folder, pathSeparator, expandedFolders);
|
|
3050
|
+
// @ts-ignore
|
|
3051
|
+
folder.type = DirectoryExpanded;
|
|
3052
|
+
return {
|
|
3053
|
+
folderIndex,
|
|
3054
|
+
childItems
|
|
3055
|
+
};
|
|
3056
|
+
}
|
|
3057
|
+
}
|
|
3058
|
+
return null;
|
|
3059
|
+
}));
|
|
3060
|
+
|
|
3061
|
+
// Insert child items in the correct order
|
|
3062
|
+
let offset = 0;
|
|
3063
|
+
for (const result of expandedFolderResults) {
|
|
3064
|
+
if (result) {
|
|
3065
|
+
const {
|
|
3066
|
+
folderIndex,
|
|
3067
|
+
childItems
|
|
3068
|
+
} = result;
|
|
3069
|
+
newDirents.splice(folderIndex + 1 + offset, 0, ...childItems);
|
|
3070
|
+
offset += childItems.length;
|
|
3071
|
+
}
|
|
3072
|
+
}
|
|
3002
3073
|
const maxLineY = getExplorerMaxLineY(minLineY, height, itemHeight, newDirents.length);
|
|
3003
3074
|
const visible = newDirents.slice(minLineY, maxLineY);
|
|
3004
3075
|
const {
|
|
3005
3076
|
icons,
|
|
3006
3077
|
newFileIconCache
|
|
3007
3078
|
} = await getFileIcons(visible, fileIconCache);
|
|
3008
|
-
|
|
3079
|
+
let newFocusedIndex = focusedIndex;
|
|
3080
|
+
if (focusedIndex >= newDirents.length) {
|
|
3081
|
+
newFocusedIndex = newDirents.length - 1;
|
|
3082
|
+
}
|
|
3083
|
+
return {
|
|
3009
3084
|
...state,
|
|
3010
3085
|
items: newDirents,
|
|
3011
3086
|
fileIconCache: newFileIconCache,
|
|
3012
3087
|
icons,
|
|
3013
|
-
maxLineY
|
|
3088
|
+
maxLineY,
|
|
3089
|
+
focusedIndex: newFocusedIndex
|
|
3014
3090
|
};
|
|
3015
|
-
return state3;
|
|
3016
3091
|
};
|
|
3017
3092
|
|
|
3018
3093
|
const applyOperation = operation => {
|
|
@@ -3109,7 +3184,7 @@ const uploadFileSystemHandles = async (root, pathSeparator, fileSystemHandles) =
|
|
|
3109
3184
|
return true;
|
|
3110
3185
|
};
|
|
3111
3186
|
|
|
3112
|
-
const mergeDirents$
|
|
3187
|
+
const mergeDirents$2 = (oldDirents, newDirents) => {
|
|
3113
3188
|
return newDirents;
|
|
3114
3189
|
};
|
|
3115
3190
|
const getMergedDirents$2 = async (root, pathSeparator, dirents) => {
|
|
@@ -3117,7 +3192,7 @@ const getMergedDirents$2 = async (root, pathSeparator, dirents) => {
|
|
|
3117
3192
|
path: root,
|
|
3118
3193
|
depth: 0
|
|
3119
3194
|
});
|
|
3120
|
-
const mergedDirents = mergeDirents$
|
|
3195
|
+
const mergedDirents = mergeDirents$2(dirents, childDirents);
|
|
3121
3196
|
return mergedDirents;
|
|
3122
3197
|
};
|
|
3123
3198
|
const handleDrop$2 = async (state, fileHandles, files) => {
|
|
@@ -3166,7 +3241,7 @@ const copyFilesElectron = async (root, pathSeparator, fileHandles, files, paths)
|
|
|
3166
3241
|
await applyFileOperations(operations);
|
|
3167
3242
|
};
|
|
3168
3243
|
|
|
3169
|
-
const mergeDirents = (oldDirents, newDirents) => {
|
|
3244
|
+
const mergeDirents$1 = (oldDirents, newDirents) => {
|
|
3170
3245
|
return newDirents;
|
|
3171
3246
|
};
|
|
3172
3247
|
const getMergedDirents$1 = async (root, pathSeparator, dirents) => {
|
|
@@ -3174,7 +3249,7 @@ const getMergedDirents$1 = async (root, pathSeparator, dirents) => {
|
|
|
3174
3249
|
path: root,
|
|
3175
3250
|
depth: 0
|
|
3176
3251
|
});
|
|
3177
|
-
const mergedDirents = mergeDirents(dirents, childDirents);
|
|
3252
|
+
const mergedDirents = mergeDirents$1(dirents, childDirents);
|
|
3178
3253
|
return mergedDirents;
|
|
3179
3254
|
};
|
|
3180
3255
|
const handleDrop$1 = async (state, fileHandles, files, paths) => {
|
|
@@ -3427,6 +3502,25 @@ const handleKeyDown = (state, key) => {
|
|
|
3427
3502
|
};
|
|
3428
3503
|
};
|
|
3429
3504
|
|
|
3505
|
+
const getTopLevelDirents = (root, pathSeparator, excluded) => {
|
|
3506
|
+
if (!root) {
|
|
3507
|
+
return [];
|
|
3508
|
+
}
|
|
3509
|
+
return getChildDirents(pathSeparator, {
|
|
3510
|
+
depth: 0,
|
|
3511
|
+
path: root,
|
|
3512
|
+
type: Directory
|
|
3513
|
+
}, excluded);
|
|
3514
|
+
};
|
|
3515
|
+
|
|
3516
|
+
const mergeDirents = (oldDirents, newDirents) => {
|
|
3517
|
+
const merged = [];
|
|
3518
|
+
for (const newDirent of newDirents) {
|
|
3519
|
+
merged.push(newDirent);
|
|
3520
|
+
}
|
|
3521
|
+
return merged;
|
|
3522
|
+
};
|
|
3523
|
+
|
|
3430
3524
|
// TODO add lots of tests for this
|
|
3431
3525
|
const updateRoot = async state1 => {
|
|
3432
3526
|
// @ts-ignore
|
|
@@ -3441,7 +3535,7 @@ const updateRoot = async state1 => {
|
|
|
3441
3535
|
// if (state2.disposed || state2.root !== state1.root) {
|
|
3442
3536
|
// return state2
|
|
3443
3537
|
// }
|
|
3444
|
-
const newDirents = mergeDirents
|
|
3538
|
+
const newDirents = mergeDirents(state1.items, topLevelDirents);
|
|
3445
3539
|
const state3 = {
|
|
3446
3540
|
...state1,
|
|
3447
3541
|
items: newDirents
|
|
@@ -3749,10 +3843,11 @@ const loadContent = async (state, savedState) => {
|
|
|
3749
3843
|
deltaY = savedState.deltaY;
|
|
3750
3844
|
}
|
|
3751
3845
|
const maxLineY = getExplorerMaxLineY(minLineY, height, itemHeight, restoredDirents.length);
|
|
3846
|
+
const visible = restoredDirents.slice(minLineY, maxLineY);
|
|
3752
3847
|
const {
|
|
3753
3848
|
icons,
|
|
3754
3849
|
newFileIconCache
|
|
3755
|
-
} = await getFileIcons(
|
|
3850
|
+
} = await getFileIcons(visible, fileIconCache);
|
|
3756
3851
|
return {
|
|
3757
3852
|
...state,
|
|
3758
3853
|
root,
|
|
@@ -3929,70 +4024,35 @@ const openContainingFolder = async state => {
|
|
|
3929
4024
|
return state;
|
|
3930
4025
|
};
|
|
3931
4026
|
|
|
3932
|
-
|
|
3933
|
-
const
|
|
3934
|
-
|
|
3935
|
-
|
|
3936
|
-
|
|
3937
|
-
|
|
3938
|
-
|
|
3939
|
-
|
|
3940
|
-
|
|
3941
|
-
|
|
3942
|
-
|
|
3943
|
-
|
|
3944
|
-
await remove(absolutePath);
|
|
3945
|
-
} catch {
|
|
3946
|
-
// TODO vscode shows error as alert (no stacktrace) and retry button
|
|
3947
|
-
// maybe should show alert as well, but where to put stacktrace?
|
|
3948
|
-
// on web should probably show notification (dialog)
|
|
3949
|
-
// ErrorHandling.handleError(error)
|
|
3950
|
-
// await ErrorHandling.showErrorDialog(error)
|
|
3951
|
-
return state;
|
|
3952
|
-
}
|
|
3953
|
-
// TODO avoid state mutation
|
|
3954
|
-
// @ts-ignore
|
|
3955
|
-
const newVersion = ++state.version;
|
|
3956
|
-
// TODO race condition
|
|
3957
|
-
// const newState = await loadContent(state:any)
|
|
3958
|
-
// @ts-ignore
|
|
3959
|
-
if (state.version !== newVersion || state.disposed) {
|
|
3960
|
-
return state;
|
|
3961
|
-
}
|
|
3962
|
-
// TODO is it possible to make this more functional instead of mutating state?
|
|
3963
|
-
// maybe every function returns a new state?
|
|
3964
|
-
const index = state.items.indexOf(dirent);
|
|
3965
|
-
let deleteEnd = index + 1;
|
|
3966
|
-
for (; deleteEnd < state.items.length; deleteEnd++) {
|
|
3967
|
-
if (state.items[deleteEnd].depth <= dirent.depth) {
|
|
3968
|
-
break;
|
|
4027
|
+
const getSelectedItems = (items, focusedIndex) => {
|
|
4028
|
+
const dirent = items[focusedIndex];
|
|
4029
|
+
const selectedItems = items.filter(item => item.selected || item === dirent);
|
|
4030
|
+
return selectedItems;
|
|
4031
|
+
};
|
|
4032
|
+
|
|
4033
|
+
const removePaths = async paths => {
|
|
4034
|
+
for (const item of paths) {
|
|
4035
|
+
try {
|
|
4036
|
+
await remove(item);
|
|
4037
|
+
} catch {
|
|
4038
|
+
// ignore
|
|
3969
4039
|
}
|
|
3970
4040
|
}
|
|
3971
|
-
|
|
3972
|
-
|
|
3973
|
-
|
|
3974
|
-
let indexToFocus = -1;
|
|
3975
|
-
if (newDirents.length === 0) {
|
|
3976
|
-
indexToFocus = -1;
|
|
3977
|
-
} else if (index < state.focusedIndex) {
|
|
3978
|
-
indexToFocus = state.focusedIndex - 1;
|
|
3979
|
-
} else if (index === state.focusedIndex) {
|
|
3980
|
-
indexToFocus = Math.max(state.focusedIndex - 1, 0);
|
|
3981
|
-
} else {
|
|
3982
|
-
indexToFocus = Math.max(state.focusedIndex - 1, 0);
|
|
3983
|
-
}
|
|
3984
|
-
const visible = newDirents.slice(state.minLineY, state.maxLineY);
|
|
4041
|
+
};
|
|
4042
|
+
|
|
4043
|
+
const removeDirent = async state => {
|
|
3985
4044
|
const {
|
|
3986
|
-
|
|
3987
|
-
|
|
3988
|
-
} =
|
|
3989
|
-
|
|
3990
|
-
|
|
3991
|
-
|
|
3992
|
-
|
|
3993
|
-
|
|
3994
|
-
|
|
3995
|
-
|
|
4045
|
+
items,
|
|
4046
|
+
focusedIndex
|
|
4047
|
+
} = state;
|
|
4048
|
+
const selectedItems = getSelectedItems(items, focusedIndex);
|
|
4049
|
+
if (selectedItems.length === 0) {
|
|
4050
|
+
return state;
|
|
4051
|
+
}
|
|
4052
|
+
const toRemove = getPaths(selectedItems);
|
|
4053
|
+
await removePaths(toRemove);
|
|
4054
|
+
const newState = await refresh(state);
|
|
4055
|
+
return newState;
|
|
3996
4056
|
};
|
|
3997
4057
|
|
|
3998
4058
|
const getNewDirentsForRename = (items, focusedIndex) => {
|
|
@@ -4083,14 +4143,14 @@ const Chevron = 'Chevron';
|
|
|
4083
4143
|
const Empty = '';
|
|
4084
4144
|
const Explorer = 'Explorer';
|
|
4085
4145
|
const ExplorerDropTarget = 'DropTarget';
|
|
4146
|
+
const ExplorerInputBox = 'ExplorerInputBox';
|
|
4086
4147
|
const FileIcon = 'FileIcon';
|
|
4087
4148
|
const FocusOutline = 'FocusOutline';
|
|
4088
|
-
const ListItems = 'ListItems';
|
|
4089
4149
|
const IconButton = 'IconButton';
|
|
4090
4150
|
const InputBox = 'InputBox';
|
|
4091
|
-
const ExplorerInputBox = 'ExplorerInputBox';
|
|
4092
4151
|
const InputValidationError = 'InputValidationError';
|
|
4093
4152
|
const Label = 'Label';
|
|
4153
|
+
const ListItems = 'ListItems';
|
|
4094
4154
|
const MaskIconChevronDown = 'MaskIconChevronDown';
|
|
4095
4155
|
const MaskIconChevronRight = 'MaskIconChevronRight';
|
|
4096
4156
|
const TreeItem = 'TreeItem';
|