@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.
- package/dist/explorerViewWorkerMain.js +125 -48
- package/package.json +1 -1
|
@@ -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$
|
|
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$
|
|
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
|
|
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
|
|
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
|
|
3680
|
-
|
|
3681
|
-
|
|
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
|
-
|
|
3687
|
-
const
|
|
3688
|
-
|
|
3689
|
-
|
|
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
|
-
|
|
3695
|
-
const
|
|
3696
|
-
|
|
3697
|
-
|
|
3698
|
-
|
|
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
|
-
|
|
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
|
-
|
|
3723
|
-
|
|
3724
|
-
|
|
3725
|
-
|
|
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
|
-
|
|
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;
|