@lvce-editor/explorer-view 2.52.0 → 2.54.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.
@@ -936,6 +936,7 @@ const {
936
936
  set: set$1
937
937
  } = RendererWorker;
938
938
 
939
+ // TODO use direct connection
939
940
  const invoke = async (method, ...params) => {
940
941
  return invoke$1(method, ...params);
941
942
  };
@@ -1004,9 +1005,6 @@ const dirname = (pathSeparator, path) => {
1004
1005
  const dirname2 = path => {
1005
1006
  return dirname('/', path);
1006
1007
  };
1007
- const join = (pathSeparator, ...parts) => {
1008
- return parts.join(pathSeparator);
1009
- };
1010
1008
  const getBaseName = (pathSeparator, path) => {
1011
1009
  return path.slice(path.lastIndexOf(pathSeparator) + 1);
1012
1010
  };
@@ -1843,6 +1841,7 @@ const writeText = async text => {
1843
1841
  await invoke$1('ClipBoard.writeText', /* text */text);
1844
1842
  };
1845
1843
  const readNativeFiles = async () => {
1844
+ // @ts-ignore
1846
1845
  return invoke$1('ClipBoard.readNativeFiles');
1847
1846
  };
1848
1847
  const writeNativeFiles = async (type, files) => {
@@ -1957,6 +1956,7 @@ const create2 = (uid, uri, x, y, width, height, args, parentUid, platform = 0) =
1957
1956
  editingIcon: '',
1958
1957
  fileIconCache: Object.create(null),
1959
1958
  useChevrons: false,
1959
+ confirmDelete: false,
1960
1960
  icons: [],
1961
1961
  platform,
1962
1962
  focus: 0,
@@ -1969,7 +1969,8 @@ const create2 = (uid, uri, x, y, width, height, args, parentUid, platform = 0) =
1969
1969
  finalDeltaY: 0,
1970
1970
  handleOffset: 0,
1971
1971
  scrollBarActive: false,
1972
- scrollBarHeight: 0
1972
+ scrollBarHeight: 0,
1973
+ confirmPaste: false
1973
1974
  };
1974
1975
  set(uid, state, state);
1975
1976
  };
@@ -2002,6 +2003,7 @@ const create = (id, uri, x, y, width, height, args, parentUid, platform = 0) =>
2002
2003
  editingIcon: '',
2003
2004
  fileIconCache: Object.create(null),
2004
2005
  useChevrons: false,
2006
+ confirmDelete: false,
2005
2007
  icons: [],
2006
2008
  platform,
2007
2009
  focus: 0,
@@ -2014,7 +2016,8 @@ const create = (id, uri, x, y, width, height, args, parentUid, platform = 0) =>
2014
2016
  finalDeltaY: 0,
2015
2017
  handleOffset: 0,
2016
2018
  scrollBarActive: false,
2017
- scrollBarHeight: 0
2019
+ scrollBarHeight: 0,
2020
+ confirmPaste: false
2018
2021
  };
2019
2022
  set(state.uid, state, state);
2020
2023
  return state;
@@ -3311,6 +3314,7 @@ const createUploadTree = async (root, fileHandles) => {
3311
3314
  const childTree = await createUploadTree(name, children);
3312
3315
  uploadTree[name] = childTree;
3313
3316
  } else if (isFileHandle(fileHandle)) {
3317
+ // TODO maybe save blob and use filesystem.writeblob
3314
3318
  const text = await getFileHandleText(fileHandle);
3315
3319
  uploadTree[name] = text;
3316
3320
  }
@@ -3355,12 +3359,12 @@ const uploadFileSystemHandles = async (root, pathSeparator, fileSystemHandles) =
3355
3359
  return true;
3356
3360
  };
3357
3361
 
3358
- const mergeDirents$2 = (oldDirents, newDirents) => {
3362
+ const mergeDirents$1 = (oldDirents, newDirents) => {
3359
3363
  return newDirents;
3360
3364
  };
3361
3365
  const getMergedDirents$2 = async (root, pathSeparator, dirents) => {
3362
3366
  const childDirents = await getChildDirents(pathSeparator, root, 0);
3363
- const mergedDirents = mergeDirents$2(dirents, childDirents);
3367
+ const mergedDirents = mergeDirents$1(dirents, childDirents);
3364
3368
  return mergedDirents;
3365
3369
  };
3366
3370
  const handleDrop$2 = async (state, fileHandles, files) => {
@@ -3408,12 +3412,12 @@ const copyFilesElectron = async (root, pathSeparator, fileHandles, files, paths)
3408
3412
  await applyFileOperations(operations);
3409
3413
  };
3410
3414
 
3411
- const mergeDirents$1 = (oldDirents, newDirents) => {
3415
+ const mergeDirents = (oldDirents, newDirents) => {
3412
3416
  return newDirents;
3413
3417
  };
3414
3418
  const getMergedDirents$1 = async (root, pathSeparator, dirents) => {
3415
3419
  const childDirents = await getChildDirents(pathSeparator, root, 0);
3416
- const mergedDirents = mergeDirents$1(dirents, childDirents);
3420
+ const mergedDirents = mergeDirents(dirents, childDirents);
3417
3421
  return mergedDirents;
3418
3422
  };
3419
3423
  const handleDrop$1 = async (state, fileHandles, files, paths) => {
@@ -3676,41 +3680,59 @@ const handleKeyDown = (state, key) => {
3676
3680
  };
3677
3681
  };
3678
3682
 
3679
- const getTopLevelDirents = (root, pathSeparator, excluded) => {
3680
- if (!root) {
3681
- return [];
3683
+ const generateUniqueName = (baseName, existingPaths, root) => {
3684
+ // Handle files with extensions
3685
+ const lastDotIndex = baseName.lastIndexOf('.');
3686
+ const hasExtension = lastDotIndex !== -1 && lastDotIndex !== 0 && lastDotIndex !== baseName.length - 1;
3687
+ let nameWithoutExtension;
3688
+ let extension;
3689
+ if (hasExtension) {
3690
+ nameWithoutExtension = baseName.slice(0, lastDotIndex);
3691
+ extension = baseName.slice(lastDotIndex);
3692
+ } else {
3693
+ nameWithoutExtension = baseName;
3694
+ extension = '';
3682
3695
  }
3683
- return getChildDirents(pathSeparator, root, 0, excluded);
3684
- };
3685
3696
 
3686
- const mergeDirents = (oldDirents, newDirents) => {
3687
- const merged = [];
3688
- for (const newDirent of newDirents) {
3689
- merged.push(newDirent);
3697
+ // Check if original name exists
3698
+ const originalPath = join2(root, baseName);
3699
+ if (!existingPaths.includes(originalPath)) {
3700
+ return baseName;
3701
+ }
3702
+
3703
+ // Try "original copy"
3704
+ const copyName = `${nameWithoutExtension} copy${extension}`;
3705
+ const copyPath = join2(root, copyName);
3706
+ if (!existingPaths.includes(copyPath)) {
3707
+ return copyName;
3708
+ }
3709
+
3710
+ // Try "original copy 1", "original copy 2", etc.
3711
+ let counter = 1;
3712
+ while (true) {
3713
+ const numberedCopyName = `${nameWithoutExtension} copy ${counter}${extension}`;
3714
+ const numberedCopyPath = join2(root, numberedCopyName);
3715
+ if (!existingPaths.includes(numberedCopyPath)) {
3716
+ return numberedCopyName;
3717
+ }
3718
+ counter++;
3690
3719
  }
3691
- return merged;
3692
3720
  };
3693
3721
 
3694
- // TODO add lots of tests for this
3695
- const updateRoot = async state1 => {
3696
- // @ts-ignore
3697
- if (state1.disposed) {
3698
- return state1;
3722
+ const getFileOperationsCopy = (root, existingUris, files) => {
3723
+ const operations = [];
3724
+ for (const file of files) {
3725
+ const baseName = getBaseName('/', file);
3726
+ const uniqueName = generateUniqueName(baseName, existingUris, root);
3727
+ const newUri = join2(root, uniqueName);
3728
+ operations.push({
3729
+ type: Copy$2,
3730
+ from: file,
3731
+ // TODO ensure file is uri
3732
+ path: newUri
3733
+ });
3699
3734
  }
3700
- // const file = nativeFiles.files[0]
3701
- // @ts-ignore
3702
- const topLevelDirents = await getTopLevelDirents(state1.root, state1.pathSeparator, []);
3703
- // const state2 = Viewlet.getState('Explorer')
3704
- // // TODO what if root changes while reading directories?
3705
- // if (state2.disposed || state2.root !== state1.root) {
3706
- // return state2
3707
- // }
3708
- const newDirents = mergeDirents(state1.items, topLevelDirents);
3709
- const state3 = {
3710
- ...state1,
3711
- items: newDirents
3712
- };
3713
- return state3;
3735
+ return operations;
3714
3736
  };
3715
3737
 
3716
3738
  const handlePasteCopy = async (state, nativeFiles) => {
@@ -3719,13 +3741,42 @@ const handlePasteCopy = async (state, nativeFiles) => {
3719
3741
  // TODO handle pasting files into broken symlink
3720
3742
  // TODO handle pasting files into hardlink
3721
3743
  // TODO what if folder is big and it takes a long time
3722
- for (const source of nativeFiles.files) {
3723
- // @ts-ignore
3724
- const target = join(state.pathSeperator, state.root, getBaseName(state.pathSeparator, source));
3725
- await copy$1(source, target);
3726
- }
3744
+
3745
+ // TODO use file operations and bulk edit
3746
+ const {
3747
+ items,
3748
+ root
3749
+ } = state;
3750
+ const existingUris = items.map(item => item.path);
3751
+ const operations = getFileOperationsCopy(root, existingUris, nativeFiles.files);
3752
+ // TODO handle error?
3753
+ await applyFileOperations(operations);
3754
+
3755
+ // TODO use refreshExplorer with the paths that have been affected by file operations
3727
3756
  // TODO only update folder at which level it changed
3728
- return updateRoot(state);
3757
+ const latestState = await refresh(state);
3758
+
3759
+ // Focus on the first newly created file
3760
+ const newFilePaths = operations.map(operation => operation.path);
3761
+ if (newFilePaths.length > 0) {
3762
+ const firstNewFilePath = newFilePaths[0];
3763
+ const newFileIndex = getIndex(latestState.items, firstNewFilePath);
3764
+ if (newFileIndex !== -1) {
3765
+ return {
3766
+ ...latestState,
3767
+ focusedIndex: newFileIndex,
3768
+ focused: true
3769
+ };
3770
+ }
3771
+ }
3772
+ // If there are no items, ensure focusedIndex is 0
3773
+ if (latestState.items.length === 0) {
3774
+ return {
3775
+ ...latestState,
3776
+ focusedIndex: 0
3777
+ };
3778
+ }
3779
+ return latestState;
3729
3780
  };
3730
3781
 
3731
3782
  const handlePasteCut = async (state, nativeFiles) => {
@@ -3860,10 +3911,17 @@ const getWorkspacePath = () => {
3860
3911
  };
3861
3912
 
3862
3913
  const getSettings = async () => {
3914
+ // TODO get all settings at once
3863
3915
  const useChevronsRaw = await invoke$1('Preferences.get', 'explorer.useChevrons');
3864
3916
  const useChevrons = useChevronsRaw === false ? false : true;
3917
+ const confirmDeleteRaw = await invoke$1('Preferences.get', 'explorer.confirmdelete');
3918
+ const confirmDelete = confirmDeleteRaw === false ? false : false;
3919
+ const confirmPasteRaw = await invoke$1('Preferences.get', 'explorer.confirmpaste');
3920
+ const confirmPaste = confirmPasteRaw === false ? false : false;
3865
3921
  return {
3866
- useChevrons
3922
+ useChevrons,
3923
+ confirmDelete,
3924
+ confirmPaste
3867
3925
  };
3868
3926
  };
3869
3927
 
@@ -3992,7 +4050,8 @@ const loadContent = async (state, savedState) => {
3992
4050
  fileIconCache
3993
4051
  } = state;
3994
4052
  const {
3995
- useChevrons
4053
+ useChevrons,
4054
+ confirmDelete
3996
4055
  } = await getSettings();
3997
4056
  const workspacePath = await getWorkspacePath();
3998
4057
  const root = getSavedRoot(savedState, workspacePath);
@@ -4029,7 +4088,8 @@ const loadContent = async (state, savedState) => {
4029
4088
  maxLineY,
4030
4089
  pathSeparator,
4031
4090
  excluded,
4032
- useChevrons
4091
+ useChevrons,
4092
+ confirmDelete
4033
4093
  };
4034
4094
  };
4035
4095
 
@@ -4207,6 +4267,14 @@ const openContainingFolder = async state => {
4207
4267
  return state;
4208
4268
  };
4209
4269
 
4270
+ const confirmDelete = async paths => {
4271
+ // TODO use i18n string
4272
+ const message = paths.length === 1 ? `Are you sure you want to delete "${paths[0]}"?` : `Are you sure you want to delete ${paths.length} items?`;
4273
+ // @ts-ignore
4274
+ const result = await invoke$1('Confirmprompt.prompt', message);
4275
+ return result === true;
4276
+ };
4277
+
4210
4278
  const getSelectedItems = (items, focusedIndex) => {
4211
4279
  const dirent = items[focusedIndex];
4212
4280
  const selectedItems = items.filter(item => item.selected || item === dirent);
@@ -4226,13 +4294,22 @@ const removePaths = async paths => {
4226
4294
  const removeDirent = async state => {
4227
4295
  const {
4228
4296
  items,
4229
- focusedIndex
4297
+ focusedIndex,
4298
+ confirmDelete: confirmDelete$1
4230
4299
  } = state;
4231
4300
  const selectedItems = getSelectedItems(items, focusedIndex);
4232
4301
  if (selectedItems.length === 0) {
4233
4302
  return state;
4234
4303
  }
4235
4304
  const toRemove = getPaths(selectedItems);
4305
+ if (confirmDelete$1) {
4306
+ const confirmed = await confirmDelete(toRemove);
4307
+ if (!confirmed) {
4308
+ return state;
4309
+ }
4310
+ }
4311
+
4312
+ // TODO use file operations, bulk edit and explorer refresh
4236
4313
  await removePaths(toRemove);
4237
4314
  const newState = await refresh(state);
4238
4315
  return newState;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lvce-editor/explorer-view",
3
- "version": "2.52.0",
3
+ "version": "2.54.0",
4
4
  "description": "Explorer Worker",
5
5
  "repository": {
6
6
  "type": "git",