@lvce-editor/explorer-view 2.29.0 → 2.30.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.
@@ -985,8 +985,8 @@ const getMissingIconRequests = (dirents, fileIconCache) => {
985
985
  return missingRequests;
986
986
  };
987
987
 
988
- const getPath = dirent => {
989
- return dirent.path;
988
+ const getPath = item => {
989
+ return item.path;
990
990
  };
991
991
 
992
992
  const DELTA_EDITING = 100;
@@ -2968,23 +2968,41 @@ const handleDragOver = (state, x, y) => {
2968
2968
  };
2969
2969
  };
2970
2970
 
2971
- const getTopLevelDirents = (root, pathSeparator, excluded) => {
2972
- if (!root) {
2973
- return [];
2974
- }
2975
- return getChildDirents(pathSeparator, {
2976
- depth: 0,
2977
- path: root,
2978
- type: Directory
2979
- }, excluded);
2971
+ const isExpanded = item => {
2972
+ return item.type === DirectoryExpanded || item.type === DirectoryExpanding;
2980
2973
  };
2981
2974
 
2982
- const mergeDirents$2 = (oldDirents, newDirents) => {
2983
- const merged = [];
2984
- for (const newDirent of newDirents) {
2985
- merged.push(newDirent);
2975
+ const getExpandedDirents = items => {
2976
+ return items.filter(isExpanded);
2977
+ };
2978
+
2979
+ const getPaths = items => {
2980
+ return items.map(getPath);
2981
+ };
2982
+
2983
+ const refreshChildDirent = async (folder, dirent, pathSeparator, expandedFolders) => {
2984
+ const path = folder.path.endsWith(pathSeparator) ? `${folder.path}${dirent.name}` : `${folder.path}${pathSeparator}${dirent.name}`;
2985
+ const isExpandedFolder = expandedFolders.includes(path);
2986
+ const type = dirent.type === 'directory' ? isExpandedFolder ? DirectoryExpanded : Directory : File;
2987
+ const item = {
2988
+ name: dirent.name,
2989
+ type,
2990
+ path,
2991
+ depth: folder.depth + 1,
2992
+ selected: false
2993
+ };
2994
+ if (isExpandedFolder) {
2995
+ const nestedItems = await refreshChildDirents(item, pathSeparator, expandedFolders);
2996
+ return [item, ...nestedItems];
2986
2997
  }
2987
- return merged;
2998
+ return [item];
2999
+ };
3000
+ const refreshChildDirents = async (folder, pathSeparator, expandedFolders) => {
3001
+ const childDirents = await readDirWithFileTypes(folder.path);
3002
+ const childItems = await Promise.all(childDirents.map(async dirent => {
3003
+ return refreshChildDirent(folder, dirent, pathSeparator, expandedFolders);
3004
+ }));
3005
+ return childItems.flat();
2988
3006
  };
2989
3007
 
2990
3008
  // TODO add lots of tests for this
@@ -2995,24 +3013,73 @@ const refresh = async state => {
2995
3013
  minLineY,
2996
3014
  height,
2997
3015
  itemHeight,
2998
- fileIconCache
3016
+ fileIconCache,
3017
+ items,
3018
+ focusedIndex
2999
3019
  } = state;
3000
- const topLevelDirents = await getTopLevelDirents(root, pathSeparator, []);
3001
- const newDirents = mergeDirents$2(state.items, topLevelDirents);
3020
+
3021
+ // Get all expanded folders
3022
+ const expandedDirents = getExpandedDirents(items);
3023
+ const expandedFolders = getPaths(expandedDirents);
3024
+
3025
+ // Get top level dirents
3026
+ const topLevelDirents = await readDirWithFileTypes(root);
3027
+ const newDirents = topLevelDirents.map(dirent => ({
3028
+ name: dirent.name,
3029
+ type: dirent.type === 'directory' ? Directory : File,
3030
+ path: root.endsWith(pathSeparator) ? `${root}${dirent.name}` : `${root}${pathSeparator}${dirent.name}`,
3031
+ depth: 0,
3032
+ selected: false
3033
+ }));
3034
+
3035
+ // Process expanded folders in parallel
3036
+ const expandedFolderResults = await Promise.all(expandedFolders.map(async folderPath => {
3037
+ const folderIndex = newDirents.findIndex(item => item.path === folderPath);
3038
+ if (folderIndex !== -1) {
3039
+ const folder = newDirents[folderIndex];
3040
+ if (folder.type === Directory) {
3041
+ const childItems = await refreshChildDirents(folder, pathSeparator, expandedFolders);
3042
+ // @ts-ignore
3043
+ folder.type = DirectoryExpanded;
3044
+ return {
3045
+ folderIndex,
3046
+ childItems
3047
+ };
3048
+ }
3049
+ }
3050
+ return null;
3051
+ }));
3052
+
3053
+ // Insert child items in the correct order
3054
+ let offset = 0;
3055
+ for (const result of expandedFolderResults) {
3056
+ if (result) {
3057
+ const {
3058
+ folderIndex,
3059
+ childItems
3060
+ } = result;
3061
+ newDirents.splice(folderIndex + 1 + offset, 0, ...childItems);
3062
+ offset += childItems.length;
3063
+ }
3064
+ }
3002
3065
  const maxLineY = getExplorerMaxLineY(minLineY, height, itemHeight, newDirents.length);
3003
3066
  const visible = newDirents.slice(minLineY, maxLineY);
3004
3067
  const {
3005
3068
  icons,
3006
3069
  newFileIconCache
3007
3070
  } = await getFileIcons(visible, fileIconCache);
3008
- const state3 = {
3071
+ let newFocusedIndex = focusedIndex;
3072
+ if (focusedIndex >= newDirents.length) {
3073
+ newFocusedIndex = newDirents.length - 1;
3074
+ }
3075
+ return {
3009
3076
  ...state,
3010
3077
  items: newDirents,
3011
3078
  fileIconCache: newFileIconCache,
3012
3079
  icons,
3013
- maxLineY
3080
+ maxLineY,
3081
+ focusedIndex: newFocusedIndex
3014
3082
  };
3015
- return state3;
3016
3083
  };
3017
3084
 
3018
3085
  const applyOperation = operation => {
@@ -3109,7 +3176,7 @@ const uploadFileSystemHandles = async (root, pathSeparator, fileSystemHandles) =
3109
3176
  return true;
3110
3177
  };
3111
3178
 
3112
- const mergeDirents$1 = (oldDirents, newDirents) => {
3179
+ const mergeDirents$2 = (oldDirents, newDirents) => {
3113
3180
  return newDirents;
3114
3181
  };
3115
3182
  const getMergedDirents$2 = async (root, pathSeparator, dirents) => {
@@ -3117,7 +3184,7 @@ const getMergedDirents$2 = async (root, pathSeparator, dirents) => {
3117
3184
  path: root,
3118
3185
  depth: 0
3119
3186
  });
3120
- const mergedDirents = mergeDirents$1(dirents, childDirents);
3187
+ const mergedDirents = mergeDirents$2(dirents, childDirents);
3121
3188
  return mergedDirents;
3122
3189
  };
3123
3190
  const handleDrop$2 = async (state, fileHandles, files) => {
@@ -3166,7 +3233,7 @@ const copyFilesElectron = async (root, pathSeparator, fileHandles, files, paths)
3166
3233
  await applyFileOperations(operations);
3167
3234
  };
3168
3235
 
3169
- const mergeDirents = (oldDirents, newDirents) => {
3236
+ const mergeDirents$1 = (oldDirents, newDirents) => {
3170
3237
  return newDirents;
3171
3238
  };
3172
3239
  const getMergedDirents$1 = async (root, pathSeparator, dirents) => {
@@ -3174,7 +3241,7 @@ const getMergedDirents$1 = async (root, pathSeparator, dirents) => {
3174
3241
  path: root,
3175
3242
  depth: 0
3176
3243
  });
3177
- const mergedDirents = mergeDirents(dirents, childDirents);
3244
+ const mergedDirents = mergeDirents$1(dirents, childDirents);
3178
3245
  return mergedDirents;
3179
3246
  };
3180
3247
  const handleDrop$1 = async (state, fileHandles, files, paths) => {
@@ -3427,6 +3494,25 @@ const handleKeyDown = (state, key) => {
3427
3494
  };
3428
3495
  };
3429
3496
 
3497
+ const getTopLevelDirents = (root, pathSeparator, excluded) => {
3498
+ if (!root) {
3499
+ return [];
3500
+ }
3501
+ return getChildDirents(pathSeparator, {
3502
+ depth: 0,
3503
+ path: root,
3504
+ type: Directory
3505
+ }, excluded);
3506
+ };
3507
+
3508
+ const mergeDirents = (oldDirents, newDirents) => {
3509
+ const merged = [];
3510
+ for (const newDirent of newDirents) {
3511
+ merged.push(newDirent);
3512
+ }
3513
+ return merged;
3514
+ };
3515
+
3430
3516
  // TODO add lots of tests for this
3431
3517
  const updateRoot = async state1 => {
3432
3518
  // @ts-ignore
@@ -3441,7 +3527,7 @@ const updateRoot = async state1 => {
3441
3527
  // if (state2.disposed || state2.root !== state1.root) {
3442
3528
  // return state2
3443
3529
  // }
3444
- const newDirents = mergeDirents$2(state1.items, topLevelDirents);
3530
+ const newDirents = mergeDirents(state1.items, topLevelDirents);
3445
3531
  const state3 = {
3446
3532
  ...state1,
3447
3533
  items: newDirents
@@ -3929,70 +4015,35 @@ const openContainingFolder = async state => {
3929
4015
  return state;
3930
4016
  };
3931
4017
 
3932
- // TODO support multiselection and removing multiple dirents
3933
- const removeDirent = async state => {
3934
- if (state.focusedIndex < 0) {
3935
- return state;
3936
- }
3937
- const dirent = getFocusedDirent$1(state);
3938
- if (!dirent) {
3939
- return state;
3940
- }
3941
- const absolutePath = dirent.path;
3942
- try {
3943
- // TODO handle error
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;
4018
+ const getSelectedItems = (items, focusedIndex) => {
4019
+ const dirent = items[focusedIndex];
4020
+ const selectedItems = items.filter(item => item.selected || item === dirent);
4021
+ return selectedItems;
4022
+ };
4023
+
4024
+ const removePaths = async paths => {
4025
+ for (const item of paths) {
4026
+ try {
4027
+ await remove(item);
4028
+ } catch {
4029
+ // ignore
3969
4030
  }
3970
4031
  }
3971
- const deleteCount = deleteEnd - index;
3972
- const newDirents = [...state.items];
3973
- newDirents.splice(index, deleteCount);
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);
4032
+ };
4033
+
4034
+ const removeDirent = async state => {
3985
4035
  const {
3986
- icons,
3987
- newFileIconCache
3988
- } = await getFileIcons(visible, state.fileIconCache);
3989
- return {
3990
- ...state,
3991
- items: newDirents,
3992
- icons,
3993
- fileIconCache: newFileIconCache,
3994
- focusedIndex: indexToFocus
3995
- };
4036
+ items,
4037
+ focusedIndex
4038
+ } = state;
4039
+ const selectedItems = getSelectedItems(items, focusedIndex);
4040
+ if (selectedItems.length === 0) {
4041
+ return state;
4042
+ }
4043
+ const toRemove = getPaths(selectedItems);
4044
+ await removePaths(toRemove);
4045
+ const newState = await refresh(state);
4046
+ return newState;
3996
4047
  };
3997
4048
 
3998
4049
  const getNewDirentsForRename = (items, focusedIndex) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lvce-editor/explorer-view",
3
- "version": "2.29.0",
3
+ "version": "2.30.0",
4
4
  "description": "Explorer Worker",
5
5
  "repository": {
6
6
  "type": "git",