@lvce-editor/explorer-view 2.53.0 → 2.55.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.
@@ -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$f = (id, rpc) => {
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$f(rpcId, rpc);
916
+ set$g(rpcId, rpc);
917
917
  },
918
918
  async dispose() {
919
919
  const rpc = get$1(rpcId);
@@ -1005,9 +1005,6 @@ const dirname = (pathSeparator, path) => {
1005
1005
  const dirname2 = path => {
1006
1006
  return dirname('/', path);
1007
1007
  };
1008
- const join = (pathSeparator, ...parts) => {
1009
- return parts.join(pathSeparator);
1010
- };
1011
1008
  const getBaseName = (pathSeparator, path) => {
1012
1009
  return path.slice(path.lastIndexOf(pathSeparator) + 1);
1013
1010
  };
@@ -1844,6 +1841,7 @@ const writeText = async text => {
1844
1841
  await invoke$1('ClipBoard.writeText', /* text */text);
1845
1842
  };
1846
1843
  const readNativeFiles = async () => {
1844
+ // @ts-ignore
1847
1845
  return invoke$1('ClipBoard.readNativeFiles');
1848
1846
  };
1849
1847
  const writeNativeFiles = async (type, files) => {
@@ -3361,12 +3359,12 @@ const uploadFileSystemHandles = async (root, pathSeparator, fileSystemHandles) =
3361
3359
  return true;
3362
3360
  };
3363
3361
 
3364
- const mergeDirents$2 = (oldDirents, newDirents) => {
3362
+ const mergeDirents$1 = (oldDirents, newDirents) => {
3365
3363
  return newDirents;
3366
3364
  };
3367
3365
  const getMergedDirents$2 = async (root, pathSeparator, dirents) => {
3368
3366
  const childDirents = await getChildDirents(pathSeparator, root, 0);
3369
- const mergedDirents = mergeDirents$2(dirents, childDirents);
3367
+ const mergedDirents = mergeDirents$1(dirents, childDirents);
3370
3368
  return mergedDirents;
3371
3369
  };
3372
3370
  const handleDrop$2 = async (state, fileHandles, files) => {
@@ -3414,12 +3412,12 @@ const copyFilesElectron = async (root, pathSeparator, fileHandles, files, paths)
3414
3412
  await applyFileOperations(operations);
3415
3413
  };
3416
3414
 
3417
- const mergeDirents$1 = (oldDirents, newDirents) => {
3415
+ const mergeDirents = (oldDirents, newDirents) => {
3418
3416
  return newDirents;
3419
3417
  };
3420
3418
  const getMergedDirents$1 = async (root, pathSeparator, dirents) => {
3421
3419
  const childDirents = await getChildDirents(pathSeparator, root, 0);
3422
- const mergedDirents = mergeDirents$1(dirents, childDirents);
3420
+ const mergedDirents = mergeDirents(dirents, childDirents);
3423
3421
  return mergedDirents;
3424
3422
  };
3425
3423
  const handleDrop$1 = async (state, fileHandles, files, paths) => {
@@ -3682,41 +3680,102 @@ const handleKeyDown = (state, key) => {
3682
3680
  };
3683
3681
  };
3684
3682
 
3685
- const getTopLevelDirents = (root, pathSeparator, excluded) => {
3686
- if (!root) {
3687
- return [];
3683
+ const scrollInto = (index, minLineY, maxLineY) => {
3684
+ const diff = maxLineY - minLineY;
3685
+ const smallerHalf = Math.floor(diff / 2);
3686
+ const largerHalf = diff - smallerHalf;
3687
+ if (index < minLineY) {
3688
+ return {
3689
+ newMinLineY: index - smallerHalf,
3690
+ newMaxLineY: index + largerHalf
3691
+ };
3692
+ }
3693
+ if (index >= maxLineY) {
3694
+ return {
3695
+ newMinLineY: index - smallerHalf,
3696
+ newMaxLineY: index + largerHalf
3697
+ };
3688
3698
  }
3689
- return getChildDirents(pathSeparator, root, 0, excluded);
3699
+ return {
3700
+ newMinLineY: minLineY,
3701
+ newMaxLineY: maxLineY
3702
+ };
3690
3703
  };
3691
3704
 
3692
- const mergeDirents = (oldDirents, newDirents) => {
3693
- const merged = [];
3694
- for (const newDirent of newDirents) {
3695
- merged.push(newDirent);
3705
+ const adjustScrollAfterPaste = (state, focusedIndex) => {
3706
+ const {
3707
+ minLineY,
3708
+ maxLineY,
3709
+ itemHeight
3710
+ } = state;
3711
+ const {
3712
+ newMinLineY,
3713
+ newMaxLineY
3714
+ } = scrollInto(focusedIndex, minLineY, maxLineY);
3715
+ const newDeltaY = newMinLineY * itemHeight;
3716
+ return {
3717
+ ...state,
3718
+ focusedIndex,
3719
+ focused: true,
3720
+ minLineY: newMinLineY,
3721
+ maxLineY: newMaxLineY,
3722
+ deltaY: newDeltaY
3723
+ };
3724
+ };
3725
+
3726
+ const generateUniqueName = (baseName, existingPaths, root) => {
3727
+ // Handle files with extensions
3728
+ const lastDotIndex = baseName.lastIndexOf('.');
3729
+ const hasExtension = lastDotIndex !== -1 && lastDotIndex !== 0 && lastDotIndex !== baseName.length - 1;
3730
+ let nameWithoutExtension;
3731
+ let extension;
3732
+ if (hasExtension) {
3733
+ nameWithoutExtension = baseName.slice(0, lastDotIndex);
3734
+ extension = baseName.slice(lastDotIndex);
3735
+ } else {
3736
+ nameWithoutExtension = baseName;
3737
+ extension = '';
3738
+ }
3739
+
3740
+ // Check if original name exists
3741
+ const originalPath = join2(root, baseName);
3742
+ if (!existingPaths.includes(originalPath)) {
3743
+ return baseName;
3744
+ }
3745
+
3746
+ // Try "original copy"
3747
+ const copyName = `${nameWithoutExtension} copy${extension}`;
3748
+ const copyPath = join2(root, copyName);
3749
+ if (!existingPaths.includes(copyPath)) {
3750
+ return copyName;
3751
+ }
3752
+
3753
+ // Try "original copy 1", "original copy 2", etc.
3754
+ let counter = 1;
3755
+ while (true) {
3756
+ const numberedCopyName = `${nameWithoutExtension} copy ${counter}${extension}`;
3757
+ const numberedCopyPath = join2(root, numberedCopyName);
3758
+ if (!existingPaths.includes(numberedCopyPath)) {
3759
+ return numberedCopyName;
3760
+ }
3761
+ counter++;
3696
3762
  }
3697
- return merged;
3698
3763
  };
3699
3764
 
3700
- // TODO add lots of tests for this
3701
- const updateRoot = async state1 => {
3702
- // @ts-ignore
3703
- if (state1.disposed) {
3704
- return state1;
3765
+ const getFileOperationsCopy = (root, existingUris, files) => {
3766
+ const operations = [];
3767
+ for (const file of files) {
3768
+ const baseName = getBaseName('/', file);
3769
+ const uniqueName = generateUniqueName(baseName, existingUris, root);
3770
+ const newUri = join2(root, uniqueName);
3771
+ operations.push({
3772
+ type: Copy$2,
3773
+ from: file,
3774
+ // TODO ensure file is uri
3775
+ path: newUri
3776
+ });
3705
3777
  }
3706
- // const file = nativeFiles.files[0]
3707
- // @ts-ignore
3708
- const topLevelDirents = await getTopLevelDirents(state1.root, state1.pathSeparator, []);
3709
- // const state2 = Viewlet.getState('Explorer')
3710
- // // TODO what if root changes while reading directories?
3711
- // if (state2.disposed || state2.root !== state1.root) {
3712
- // return state2
3713
- // }
3714
- const newDirents = mergeDirents(state1.items, topLevelDirents);
3715
- const state3 = {
3716
- ...state1,
3717
- items: newDirents
3718
- };
3719
- return state3;
3778
+ return operations;
3720
3779
  };
3721
3780
 
3722
3781
  const handlePasteCopy = async (state, nativeFiles) => {
@@ -3725,13 +3784,38 @@ const handlePasteCopy = async (state, nativeFiles) => {
3725
3784
  // TODO handle pasting files into broken symlink
3726
3785
  // TODO handle pasting files into hardlink
3727
3786
  // TODO what if folder is big and it takes a long time
3728
- for (const source of nativeFiles.files) {
3729
- // @ts-ignore
3730
- const target = join(state.pathSeperator, state.root, getBaseName(state.pathSeparator, source));
3731
- await copy$1(source, target);
3732
- }
3787
+
3788
+ // TODO use file operations and bulk edit
3789
+ const {
3790
+ items,
3791
+ root
3792
+ } = state;
3793
+ const existingUris = items.map(item => item.path);
3794
+ const operations = getFileOperationsCopy(root, existingUris, nativeFiles.files);
3795
+ // TODO handle error?
3796
+ await applyFileOperations(operations);
3797
+
3798
+ // TODO use refreshExplorer with the paths that have been affected by file operations
3733
3799
  // TODO only update folder at which level it changed
3734
- return updateRoot(state);
3800
+ const latestState = await refresh(state);
3801
+
3802
+ // Focus on the first newly created file and adjust scroll position
3803
+ const newFilePaths = operations.map(operation => operation.path);
3804
+ if (newFilePaths.length > 0) {
3805
+ const firstNewFilePath = newFilePaths[0];
3806
+ const newFileIndex = getIndex(latestState.items, firstNewFilePath);
3807
+ if (newFileIndex !== -1) {
3808
+ return adjustScrollAfterPaste(latestState, newFileIndex);
3809
+ }
3810
+ }
3811
+ // If there are no items, ensure focusedIndex is 0
3812
+ if (latestState.items.length === 0) {
3813
+ return {
3814
+ ...latestState,
3815
+ focusedIndex: 0
3816
+ };
3817
+ }
3818
+ return latestState;
3735
3819
  };
3736
3820
 
3737
3821
  const handlePasteCut = async (state, nativeFiles) => {
@@ -3739,7 +3823,20 @@ const handlePasteCut = async (state, nativeFiles) => {
3739
3823
  const target = `${state.root}${state.pathSeparator}${getBaseName(state.pathSeparator, source)}`;
3740
3824
  await rename$1(source, target);
3741
3825
  }
3742
- return state;
3826
+
3827
+ // Refresh the state after cut operations
3828
+ const latestState = await refresh(state);
3829
+
3830
+ // Focus on the first pasted file and adjust scroll position
3831
+ if (nativeFiles.files.length > 0) {
3832
+ const firstPastedFile = nativeFiles.files[0];
3833
+ const targetPath = `${state.root}${state.pathSeparator}${getBaseName(state.pathSeparator, firstPastedFile)}`;
3834
+ const pastedFileIndex = getIndex(latestState.items, targetPath);
3835
+ if (pastedFileIndex !== -1) {
3836
+ return adjustScrollAfterPaste(latestState, pastedFileIndex);
3837
+ }
3838
+ }
3839
+ return latestState;
3743
3840
  };
3744
3841
 
3745
3842
  const handlePasteNone = async (state, nativeFiles) => {
@@ -3752,18 +3849,6 @@ const Copy = 'copy';
3752
3849
  const Cut = 'cut';
3753
3850
 
3754
3851
  const getPasteHandler = type => {
3755
- // TODO detect cut/paste event, not sure if that is possible
3756
- // TODO check that pasted folder is not a parent folder of opened folder
3757
- // TODO support pasting multiple paths
3758
- // TODO what happens when pasting multiple paths, but some of them error?
3759
- // how many error messages should be shown? Should the operation be undone?
3760
- // TODO what if it is a large folder and takes a long time to copy? Should show progress
3761
- // TODO what if there is a permission error? Probably should show a modal to ask for permission
3762
- // TODO if error is EEXISTS, just rename the copy (e.g. file-copy-1.txt, file-copy-2.txt)
3763
- // TODO actual target should be selected folder
3764
- // TODO but what if a file is currently selected? Then maybe the parent folder
3765
- // TODO but will it work if the folder is a symlink?
3766
- // TODO handle error gracefully when copy fails
3767
3852
  switch (type) {
3768
3853
  case None$3:
3769
3854
  return handlePasteNone;
@@ -3778,6 +3863,9 @@ const getPasteHandler = type => {
3778
3863
 
3779
3864
  const handlePaste = async state => {
3780
3865
  const nativeFiles = await readNativeFiles();
3866
+ if (!nativeFiles) {
3867
+ return state;
3868
+ }
3781
3869
  // TODO detect cut/paste event, not sure if that is possible
3782
3870
  // TODO check that pasted folder is not a parent folder of opened folder
3783
3871
  // TODO support pasting multiple paths
@@ -4267,7 +4355,11 @@ const removeDirent = async state => {
4267
4355
  // TODO use file operations, bulk edit and explorer refresh
4268
4356
  await removePaths(toRemove);
4269
4357
  const newState = await refresh(state);
4270
- return newState;
4358
+ return {
4359
+ ...newState,
4360
+ focused: true,
4361
+ focus: List
4362
+ };
4271
4363
  };
4272
4364
 
4273
4365
  const getEditingType = direntType => {
@@ -5087,28 +5179,6 @@ const mergeVisibleWithHiddenItems = (visibleItems, hiddenItems) => {
5087
5179
  return unique;
5088
5180
  };
5089
5181
 
5090
- const scrollInto = (index, minLineY, maxLineY) => {
5091
- const diff = maxLineY - minLineY;
5092
- const smallerHalf = Math.floor(diff / 2);
5093
- const largerHalf = diff - smallerHalf;
5094
- if (index < minLineY) {
5095
- return {
5096
- newMinLineY: index - smallerHalf,
5097
- newMaxLineY: index + largerHalf
5098
- };
5099
- }
5100
- if (index >= maxLineY) {
5101
- return {
5102
- newMinLineY: index - smallerHalf,
5103
- newMaxLineY: index + largerHalf
5104
- };
5105
- }
5106
- return {
5107
- newMinLineY: minLineY,
5108
- newMaxLineY: maxLineY
5109
- };
5110
- };
5111
-
5112
5182
  // TODO maybe just insert items into explorer and refresh whole explorer
5113
5183
  const revealItemHidden = async (state, uri) => {
5114
5184
  const {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lvce-editor/explorer-view",
3
- "version": "2.53.0",
3
+ "version": "2.55.0",
4
4
  "description": "Explorer Worker",
5
5
  "repository": {
6
6
  "type": "git",