@lvce-editor/explorer-view 2.55.0 → 2.57.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.
@@ -885,7 +885,7 @@ const WebWorkerRpcClient = {
885
885
 
886
886
  const CreateFolder$1 = 1;
887
887
  const CreateFile$1 = 2;
888
- const Copy$2 = 3;
888
+ const Copy$1 = 3;
889
889
  const Rename$2 = 4;
890
890
 
891
891
  const rpcs = Object.create(null);
@@ -973,7 +973,7 @@ const applyOperation = operation => {
973
973
  if (operation.type === CreateFolder$1) {
974
974
  return mkdir(operation.path);
975
975
  }
976
- if (operation.type === Copy$2) {
976
+ if (operation.type === Copy$1) {
977
977
  return copy$1(operation.from || '', operation.path);
978
978
  }
979
979
  if (operation.type === Rename$2) {
@@ -995,6 +995,23 @@ const applyFileOperations = async operations => {
995
995
  }
996
996
  };
997
997
 
998
+ const DELTA_EDITING = 100;
999
+
1000
+ const BlockDevice = 1;
1001
+ const CharacterDevice = 2;
1002
+ const Directory = 3;
1003
+ const DirectoryExpanded = 4;
1004
+ const DirectoryExpanding = 5;
1005
+ const File = 7;
1006
+ const Socket = 8;
1007
+ const Symlink = 9;
1008
+ const SymLinkFile = 10;
1009
+ const SymLinkFolder = 11;
1010
+ const Unknown = 12;
1011
+ const EditingFile = File + DELTA_EDITING;
1012
+ const EditingFolder = Directory + DELTA_EDITING;
1013
+ const EditingDirectoryExpanded = DirectoryExpanded + DELTA_EDITING;
1014
+
998
1015
  const dirname = (pathSeparator, path) => {
999
1016
  const index = path.lastIndexOf(pathSeparator);
1000
1017
  if (index === -1) {
@@ -1015,16 +1032,32 @@ const join2 = (path, childPath) => {
1015
1032
  return `${path}/${childPath}`;
1016
1033
  };
1017
1034
 
1035
+ const getActualType = (type, expanded) => {
1036
+ const actualType = type === Directory && expanded ? DirectoryExpanded : type;
1037
+ return actualType;
1038
+ };
1018
1039
  const createTree = (items, root) => {
1019
1040
  const tree = Object.create(null);
1020
1041
  const rootLength = root.length;
1021
- for (const item of items) {
1042
+ const paths = items.map(item => {
1022
1043
  const relativePath = item.path.slice(rootLength);
1023
1044
  const dirname = dirname2(relativePath);
1045
+ return dirname;
1046
+ });
1047
+ for (const item of items) {
1048
+ const {
1049
+ type,
1050
+ name,
1051
+ path
1052
+ } = item;
1053
+ const relativePath = path.slice(rootLength);
1054
+ const dirname = dirname2(relativePath);
1055
+ const isExpanded = paths.includes(relativePath);
1056
+ const actualType = getActualType(type, isExpanded);
1024
1057
  tree[dirname] ||= [];
1025
1058
  tree[dirname].push({
1026
- name: item.name,
1027
- type: item.type
1059
+ name,
1060
+ type: actualType
1028
1061
  });
1029
1062
  }
1030
1063
  return tree;
@@ -1076,23 +1109,6 @@ const getPaths = items => {
1076
1109
  return items.map(getPath);
1077
1110
  };
1078
1111
 
1079
- const DELTA_EDITING = 100;
1080
-
1081
- const BlockDevice = 1;
1082
- const CharacterDevice = 2;
1083
- const Directory = 3;
1084
- const DirectoryExpanded = 4;
1085
- const DirectoryExpanding = 5;
1086
- const File = 7;
1087
- const Socket = 8;
1088
- const Symlink = 9;
1089
- const SymLinkFile = 10;
1090
- const SymLinkFolder = 11;
1091
- const Unknown = 12;
1092
- const EditingFile = File + DELTA_EDITING;
1093
- const EditingFolder = Directory + DELTA_EDITING;
1094
- const EditingDirectoryExpanded = DirectoryExpanded + DELTA_EDITING;
1095
-
1096
1112
  const getSimpleIconRequestType = direntType => {
1097
1113
  if (direntType === Directory || direntType === DirectoryExpanded || direntType === EditingDirectoryExpanded || direntType === EditingFolder) {
1098
1114
  return 2;
@@ -1197,13 +1213,14 @@ const getPathParts = (root, uri, pathSeparator) => {
1197
1213
  const parts = [];
1198
1214
  let index = root.length - 1;
1199
1215
  let depth = 0;
1200
- while ((index = uri.indexOf('/', index + 1)) !== -1) {
1216
+ while ((index = uri.indexOf(pathSeparator, index + 1)) !== -1) {
1201
1217
  const partUri = uri.slice(0, index);
1202
1218
  parts.push({
1203
1219
  path: partUri,
1204
1220
  depth: depth++,
1205
1221
  root,
1206
- pathSeparator
1222
+ pathSeparator,
1223
+ expanded: true
1207
1224
  });
1208
1225
  }
1209
1226
  return parts;
@@ -1310,14 +1327,14 @@ const sortExplorerItems = rawDirents => {
1310
1327
  };
1311
1328
 
1312
1329
  // TODO figure out whether this uses too much memory (name,path -> redundant, depth could be computed on demand)
1313
- const toDisplayDirent = (parentPath, parentDepth, rawDirent, index, length) => {
1314
- const path = join2(parentPath, rawDirent.name);
1330
+ const toDisplayDirent = (parentPath, parentDepth, rawDirentType, rawDirentName, index, length) => {
1331
+ const path = join2(parentPath, rawDirentName);
1315
1332
  return {
1316
- name: rawDirent.name,
1333
+ name: rawDirentName,
1317
1334
  posInSet: index + 1,
1318
1335
  setSize: length,
1319
1336
  depth: parentDepth + 1,
1320
- type: rawDirent.type,
1337
+ type: rawDirentType,
1321
1338
  path,
1322
1339
  // TODO storing absolute path might be too costly, could also store relative path here
1323
1340
  icon: '',
@@ -1325,7 +1342,7 @@ const toDisplayDirent = (parentPath, parentDepth, rawDirent, index, length) => {
1325
1342
  };
1326
1343
  };
1327
1344
 
1328
- const toDisplayDirents = (pathSeparator, rawDirents, parentDirentPath, parentDirentDepth, excluded) => {
1345
+ const toDisplayDirents = (pathSeparator, rawDirents, parentDirentPath, parentDirentDepth, excluded, expanded = false) => {
1329
1346
  rawDirents = sortExplorerItems(rawDirents);
1330
1347
  const result = [];
1331
1348
  const visibleItems = rawDirents.filter(item => {
@@ -1337,7 +1354,7 @@ const toDisplayDirents = (pathSeparator, rawDirents, parentDirentPath, parentDir
1337
1354
  const count = visibleItems.length;
1338
1355
  for (let i = 0; i < visibleItems.length; i++) {
1339
1356
  const rawDirent = visibleItems[i];
1340
- result.push(toDisplayDirent(parentDirentPath, parentDirentDepth, rawDirent, i, count));
1357
+ result.push(toDisplayDirent(parentDirentPath, parentDirentDepth, rawDirent.type, rawDirent.name, i, count));
1341
1358
  }
1342
1359
  return result;
1343
1360
  };
@@ -1443,11 +1460,12 @@ const i18nString = (key, placeholders = emptyObject) => {
1443
1460
  };
1444
1461
 
1445
1462
  const CollapseAllFoldersInExplorer = 'Collapse All Folders in Explorer';
1446
- const Copy$1 = 'Copy';
1463
+ const Copy = 'Copy';
1447
1464
  const CopyPath = 'Copy Path';
1448
1465
  const CopyRelativePath = 'Copy Relative Path';
1449
- const Cut$1 = 'Cut';
1466
+ const Cut = 'Cut';
1450
1467
  const Delete$1 = 'Delete';
1468
+ const FileNameCannotStartWithSlash = 'A file or folder name cannot start with a slash.';
1451
1469
  const FileOrFolderNameMustBeProvider = 'A file or folder name must be provided.';
1452
1470
  const FilesExplorer = 'Files Explorer';
1453
1471
  const NewFile$1 = 'New File...';
@@ -1474,10 +1492,10 @@ const openInIntegratedTerminal = () => {
1474
1492
  return i18nString(OpenInIntegratedTerminal);
1475
1493
  };
1476
1494
  const cut = () => {
1477
- return i18nString(Cut$1);
1495
+ return i18nString(Cut);
1478
1496
  };
1479
1497
  const copy = () => {
1480
- return i18nString(Copy$1);
1498
+ return i18nString(Copy);
1481
1499
  };
1482
1500
  const paste = () => {
1483
1501
  return i18nString(Paste);
@@ -1512,6 +1530,9 @@ const openFolder$1 = () => {
1512
1530
  const fileOrFolderNameMustBeProvided = () => {
1513
1531
  return i18nString(FileOrFolderNameMustBeProvider);
1514
1532
  };
1533
+ const fileCannotStartWithSlash = () => {
1534
+ return i18nString(FileNameCannotStartWithSlash);
1535
+ };
1515
1536
  const typeAFileName = () => {
1516
1537
  return i18nString(TypeAFileName);
1517
1538
  };
@@ -1521,6 +1542,9 @@ const validateFileName2 = name => {
1521
1542
  const editingErrorMessage = fileOrFolderNameMustBeProvided();
1522
1543
  return editingErrorMessage;
1523
1544
  }
1545
+ if (name.startsWith('/')) {
1546
+ return fileCannotStartWithSlash();
1547
+ }
1524
1548
  return '';
1525
1549
  };
1526
1550
 
@@ -1970,7 +1994,8 @@ const create2 = (uid, uri, x, y, width, height, args, parentUid, platform = 0) =
1970
1994
  handleOffset: 0,
1971
1995
  scrollBarActive: false,
1972
1996
  scrollBarHeight: 0,
1973
- confirmPaste: false
1997
+ confirmPaste: false,
1998
+ pasteShouldMove: false
1974
1999
  };
1975
2000
  set(uid, state, state);
1976
2001
  };
@@ -2017,7 +2042,8 @@ const create = (id, uri, x, y, width, height, args, parentUid, platform = 0) =>
2017
2042
  handleOffset: 0,
2018
2043
  scrollBarActive: false,
2019
2044
  scrollBarHeight: 0,
2020
- confirmPaste: false
2045
+ confirmPaste: false,
2046
+ pasteShouldMove: false
2021
2047
  };
2022
2048
  set(state.uid, state, state);
2023
2049
  return state;
@@ -2355,7 +2381,7 @@ const focusPrevious = state => {
2355
2381
  }
2356
2382
  };
2357
2383
 
2358
- const commandIds = ['acceptEdit', 'cancelEdit', 'cancelTypeAhead', 'collapseAll', 'copyPath', 'copyRelativePath', 'dispose', 'expandAll', 'expandRecursively', 'focus', 'focusFirst', 'focusIndex', 'focusLast', 'focusNext', 'focusNone', 'focusPrevious', 'getFocusedDirent', 'getMenuEntries2', 'getMouseActions', 'handleArrowLeft', 'handleArrowLeft', 'handleArrowRight', 'handleArrowRight', 'handleBlur', 'handleClick', 'handleClickAt', 'handleClickCurrent', 'handleClickCurrentButKeepFocus', 'handleClickOpenFolder', 'handleContextMenu', 'handleContextMenuKeyboard', 'handleCopy', 'handleDragLeave', 'handleDragOver', 'handleDrop', 'handleFocus', 'handleIconThemeChange', 'handleInputBlur', 'handleInputClick', 'handleInputKeyDown', 'handleKeyDown', 'handleLanguagesChanged', 'handleMouseEnter', 'handleMouseLeave', 'handlePaste', 'handlePointerDown', 'handleUpload', 'handleWheel', 'handleWorkspaceChange', 'hotReload', 'newFile', 'newFolder', 'openContainingFolder', 'refresh', 'removeDirent', 'rename', 'renameDirent', 'renderEventListeners', 'revealItem', 'revealItem', 'scrollDown', 'scrollUp', 'selectAll', 'selectDown', 'selectUp', 'setDeltaY', 'setSelectedIndices', 'updateEditingValue', 'updateIcons'];
2384
+ const commandIds = ['acceptEdit', 'cancelEdit', 'cancelTypeAhead', 'collapseAll', 'copyPath', 'copyRelativePath', 'dispose', 'expandAll', 'expandRecursively', 'focus', 'focusFirst', 'focusIndex', 'focusLast', 'handleCut', 'focusNext', 'focusNone', 'focusPrevious', 'getFocusedDirent', 'getMenuEntries2', 'getMouseActions', 'handleArrowLeft', 'handleArrowLeft', 'handleArrowRight', 'handleArrowRight', 'handleBlur', 'handleClick', 'handleClickAt', 'handleClickCurrent', 'handleClickCurrentButKeepFocus', 'handleClickOpenFolder', 'handleContextMenu', 'handleContextMenuKeyboard', 'handleCopy', 'handleDragLeave', 'handleDragOver', 'handleDrop', 'handleFocus', 'handleIconThemeChange', 'handleInputBlur', 'handleInputClick', 'handleInputKeyDown', 'handleKeyDown', 'handleLanguagesChanged', 'handleMouseEnter', 'handleMouseLeave', 'handlePaste', 'handlePointerDown', 'handleUpload', 'handleWheel', 'handleWorkspaceChange', 'hotReload', 'newFile', 'newFolder', 'openContainingFolder', 'refresh', 'removeDirent', 'rename', 'renameDirent', 'renderEventListeners', 'revealItem', 'revealItem', 'scrollDown', 'scrollUp', 'selectAll', 'selectDown', 'selectUp', 'setDeltaY', 'setSelectedIndices', 'updateEditingValue', 'updateIcons'];
2359
2385
 
2360
2386
  const getCommandIds = () => {
2361
2387
  return commandIds;
@@ -2511,7 +2537,7 @@ const menuEntryCut = {
2511
2537
  id: 'cut',
2512
2538
  label: cut(),
2513
2539
  flags: RestoreFocus,
2514
- command: /* TODO */'-1'
2540
+ command: 'Explorer.handleCut'
2515
2541
  };
2516
2542
  const menuEntryCopy = {
2517
2543
  id: 'copy',
@@ -3102,7 +3128,28 @@ const handleCopy = async state => {
3102
3128
  // TODO handle copy error gracefully
3103
3129
  const files = [absolutePath];
3104
3130
  await writeNativeFiles('copy', files);
3105
- return state;
3131
+ return {
3132
+ ...state,
3133
+ pasteShouldMove: false
3134
+ };
3135
+ };
3136
+
3137
+ const handleCut = async state => {
3138
+ // TODO handle multiple files
3139
+ // TODO if not file is selected, what happens?
3140
+ const dirent = getFocusedDirent$1(state);
3141
+ if (!dirent) {
3142
+ console.error('[ViewletExplorer/handleCut] no dirent selected');
3143
+ return state;
3144
+ }
3145
+ const absolutePath = dirent.path;
3146
+ // TODO handle cut error gracefully
3147
+ const files = [absolutePath];
3148
+ await writeNativeFiles('cut', files);
3149
+ return {
3150
+ ...state,
3151
+ pasteShouldMove: true
3152
+ };
3106
3153
  };
3107
3154
 
3108
3155
  const handleDragLeave = state => {
@@ -3398,7 +3445,7 @@ const getFileOperationsElectron = async (root, paths, fileHandles) => {
3398
3445
  } = fileHandle;
3399
3446
  const path = paths[i];
3400
3447
  operations.push({
3401
- type: Copy$2,
3448
+ type: Copy$1,
3402
3449
  path: join2(root, name),
3403
3450
  from: path
3404
3451
  });
@@ -3769,7 +3816,7 @@ const getFileOperationsCopy = (root, existingUris, files) => {
3769
3816
  const uniqueName = generateUniqueName(baseName, existingUris, root);
3770
3817
  const newUri = join2(root, uniqueName);
3771
3818
  operations.push({
3772
- type: Copy$2,
3819
+ type: Copy$1,
3773
3820
  from: file,
3774
3821
  // TODO ensure file is uri
3775
3822
  path: newUri
@@ -3805,24 +3852,57 @@ const handlePasteCopy = async (state, nativeFiles) => {
3805
3852
  const firstNewFilePath = newFilePaths[0];
3806
3853
  const newFileIndex = getIndex(latestState.items, firstNewFilePath);
3807
3854
  if (newFileIndex !== -1) {
3808
- return adjustScrollAfterPaste(latestState, newFileIndex);
3855
+ const adjustedState = adjustScrollAfterPaste(latestState, newFileIndex);
3856
+ return {
3857
+ ...adjustedState,
3858
+ pasteShouldMove: false
3859
+ };
3809
3860
  }
3810
3861
  }
3811
3862
  // If there are no items, ensure focusedIndex is 0
3812
3863
  if (latestState.items.length === 0) {
3813
3864
  return {
3814
3865
  ...latestState,
3815
- focusedIndex: 0
3866
+ focusedIndex: 0,
3867
+ pasteShouldMove: false
3816
3868
  };
3817
3869
  }
3818
- return latestState;
3870
+ return {
3871
+ ...latestState,
3872
+ pasteShouldMove: false
3873
+ };
3819
3874
  };
3820
3875
 
3821
- const handlePasteCut = async (state, nativeFiles) => {
3822
- for (const source of nativeFiles.files) {
3823
- const target = `${state.root}${state.pathSeparator}${getBaseName(state.pathSeparator, source)}`;
3824
- await rename$1(source, target);
3876
+ const getOperations = (toUri, files) => {
3877
+ const operations = [];
3878
+ for (const file of files) {
3879
+ const baseName = getBaseName('/', file);
3880
+ const newUri = join2(toUri, baseName);
3881
+ operations.push({
3882
+ type: Rename$2,
3883
+ from: file,
3884
+ path: newUri
3885
+ });
3886
+ }
3887
+ return operations;
3888
+ };
3889
+ const getTargetUri = (root, items, index) => {
3890
+ if (index === -1) {
3891
+ return root;
3825
3892
  }
3893
+ return items[index].path;
3894
+ };
3895
+ const handlePasteCut = async (state, nativeFiles) => {
3896
+ const {
3897
+ root,
3898
+ pathSeparator,
3899
+ items,
3900
+ focusedIndex
3901
+ } = state;
3902
+ // TODO root is not necessrily target uri
3903
+ const targetUri = getTargetUri(root, items, focusedIndex);
3904
+ const operations = getOperations(targetUri, nativeFiles.files);
3905
+ await applyFileOperations(operations);
3826
3906
 
3827
3907
  // Refresh the state after cut operations
3828
3908
  const latestState = await refresh(state);
@@ -3830,36 +3910,23 @@ const handlePasteCut = async (state, nativeFiles) => {
3830
3910
  // Focus on the first pasted file and adjust scroll position
3831
3911
  if (nativeFiles.files.length > 0) {
3832
3912
  const firstPastedFile = nativeFiles.files[0];
3833
- const targetPath = `${state.root}${state.pathSeparator}${getBaseName(state.pathSeparator, firstPastedFile)}`;
3913
+ const targetPath = `${root}${pathSeparator}${getBaseName(pathSeparator, firstPastedFile)}`;
3834
3914
  const pastedFileIndex = getIndex(latestState.items, targetPath);
3835
3915
  if (pastedFileIndex !== -1) {
3836
- return adjustScrollAfterPaste(latestState, pastedFileIndex);
3916
+ const adjustedState = adjustScrollAfterPaste(latestState, pastedFileIndex);
3917
+ return {
3918
+ ...adjustedState,
3919
+ pasteShouldMove: false
3920
+ };
3837
3921
  }
3838
3922
  }
3839
- return latestState;
3840
- };
3841
-
3842
- const handlePasteNone = async (state, nativeFiles) => {
3843
- console.error('[ViewletExplorer/handlePaste] no paths detected');
3844
- return state;
3923
+ return {
3924
+ ...latestState,
3925
+ pasteShouldMove: false
3926
+ };
3845
3927
  };
3846
3928
 
3847
3929
  const None$3 = 'none';
3848
- const Copy = 'copy';
3849
- const Cut = 'cut';
3850
-
3851
- const getPasteHandler = type => {
3852
- switch (type) {
3853
- case None$3:
3854
- return handlePasteNone;
3855
- case Copy:
3856
- return handlePasteCopy;
3857
- case Cut:
3858
- return handlePasteCut;
3859
- default:
3860
- throw new Error(`unexpected native paste type: ${type}`);
3861
- }
3862
- };
3863
3930
 
3864
3931
  const handlePaste = async state => {
3865
3932
  const nativeFiles = await readNativeFiles();
@@ -3878,8 +3945,18 @@ const handlePaste = async state => {
3878
3945
  // TODO but what if a file is currently selected? Then maybe the parent folder
3879
3946
  // TODO but will it work if the folder is a symlink?
3880
3947
  // TODO handle error gracefully when copy fails
3881
- const fn = getPasteHandler(nativeFiles.type);
3882
- return fn(state, nativeFiles);
3948
+
3949
+ // If no files to paste, return original state unchanged
3950
+ if (nativeFiles.type === None$3) {
3951
+ return state;
3952
+ }
3953
+
3954
+ // Use the pasteShouldMove flag to determine whether to cut or copy
3955
+ if (state.pasteShouldMove) {
3956
+ return handlePasteCut(state, nativeFiles);
3957
+ } else {
3958
+ return handlePasteCopy(state, nativeFiles);
3959
+ }
3883
3960
  };
3884
3961
 
3885
3962
  const handlePointerDown = (state, button, x, y) => {
@@ -5427,6 +5504,7 @@ const commandMap = {
5427
5504
  'Explorer.handleContextMenu': wrapCommand(handleContextMenu),
5428
5505
  'Explorer.handleContextMenuKeyboard': wrapCommand(handleContextMenuKeyboard),
5429
5506
  'Explorer.handleCopy': wrapCommand(handleCopy),
5507
+ 'Explorer.handleCut': wrapCommand(handleCut),
5430
5508
  'Explorer.handleDragLeave': wrapCommand(handleDragLeave),
5431
5509
  'Explorer.handleDragOver': wrapCommand(handleDragOver),
5432
5510
  'Explorer.handleDrop': wrapCommand(handleDrop),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lvce-editor/explorer-view",
3
- "version": "2.55.0",
3
+ "version": "2.57.0",
4
4
  "description": "Explorer Worker",
5
5
  "repository": {
6
6
  "type": "git",