@lvce-editor/explorer-view 6.13.0 → 6.15.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.
@@ -1667,11 +1667,32 @@ const getChildDirentsRaw = async uri => {
1667
1667
  };
1668
1668
 
1669
1669
  const RE_CHARACTERS = /^[a-zA-Z.-]+$/;
1670
+ const RE_LEADING_DIGITS = /^\d+/;
1671
+ const RE_LEADING_ZEROES = /^0+/;
1672
+ const compareLeadingDigits = (a, b) => {
1673
+ const normalizedA = a.replace(RE_LEADING_ZEROES, '') || '0';
1674
+ const normalizedB = b.replace(RE_LEADING_ZEROES, '') || '0';
1675
+ if (normalizedA.length !== normalizedB.length) {
1676
+ return normalizedA.length - normalizedB.length;
1677
+ }
1678
+ if (normalizedA !== normalizedB) {
1679
+ return normalizedA < normalizedB ? -1 : 1;
1680
+ }
1681
+ return a.length - b.length;
1682
+ };
1683
+ const compareLeadingNumbers = (a, b) => {
1684
+ const leadingDigitsA = a.match(RE_LEADING_DIGITS)?.[0];
1685
+ const leadingDigitsB = b.match(RE_LEADING_DIGITS)?.[0];
1686
+ if (leadingDigitsA && leadingDigitsB) {
1687
+ return compareLeadingDigits(leadingDigitsA, leadingDigitsB);
1688
+ }
1689
+ return 0;
1690
+ };
1670
1691
  const compareStringNumeric = (a, b) => {
1671
1692
  if (RE_CHARACTERS.test(a) && RE_CHARACTERS.test(b)) {
1672
1693
  return a < b ? -1 : 1;
1673
1694
  }
1674
- return a.localeCompare(b, 'en', {
1695
+ return compareLeadingNumbers(a, b) || a.localeCompare(b, 'en', {
1675
1696
  numeric: true
1676
1697
  });
1677
1698
  };
@@ -1739,14 +1760,11 @@ const getChildDirents = async (pathSeparator, parentDirentPath, parentDirentDept
1739
1760
  return displayDirents;
1740
1761
  };
1741
1762
 
1742
- const isTopLevel = dirent => {
1743
- return dirent.depth === 1;
1744
- };
1745
-
1746
1763
  const orderDirents = dirents => {
1747
1764
  if (dirents.length === 0) {
1748
1765
  return dirents;
1749
1766
  }
1767
+ const minDepth = Math.min(...dirents.map(dirent => dirent.depth));
1750
1768
  const withDeepChildren = (parent, processed) => {
1751
1769
  if (processed.has(parent.path)) {
1752
1770
  return [];
@@ -1760,7 +1778,7 @@ const orderDirents = dirents => {
1760
1778
  }
1761
1779
  return [parent, ...children];
1762
1780
  };
1763
- const topLevelDirents = dirents.filter(isTopLevel);
1781
+ const topLevelDirents = dirents.filter(dirent => dirent.depth === minDepth);
1764
1782
  const processed = new Set();
1765
1783
  const ordered = topLevelDirents.flatMap(dirent => withDeepChildren(dirent, processed));
1766
1784
  return ordered;
@@ -2060,14 +2078,23 @@ const computeExplorerRenamedDirentUpdate = (root, parentPath, oldUri, children,
2060
2078
  const relativeOldPath = oldUri.slice(rootLength);
2061
2079
  const relativeNewUri = newUri.slice(rootLength);
2062
2080
  const update = Object.create(null);
2063
- update[relativeDirname] = children;
2064
2081
  const oldItems = tree[relativeOldPath] || [];
2082
+ update[relativeDirname] = children.map(child => {
2083
+ if (oldItems.length > 0 && child.path === newUri && child.type === Directory) {
2084
+ return {
2085
+ ...child,
2086
+ type: DirectoryExpanded
2087
+ };
2088
+ }
2089
+ return child;
2090
+ });
2065
2091
  update[relativeNewUri] = oldItems;
2066
2092
  for (const [key, value] of Object.entries(tree)) {
2067
- if (key.startsWith(`${relativeOldPath}/`)) {
2068
- const newKey = relativeNewUri + key.slice(relativeOldPath.length);
2069
- update[newKey] = value;
2093
+ if (!key.startsWith(`${relativeOldPath}/`)) {
2094
+ continue;
2070
2095
  }
2096
+ const newKey = relativeNewUri + key.slice(relativeOldPath.length);
2097
+ update[newKey] = value;
2071
2098
  }
2072
2099
  return update;
2073
2100
  };
@@ -2244,6 +2271,10 @@ const cancelTypeAhead = state => {
2244
2271
  };
2245
2272
  };
2246
2273
 
2274
+ const isTopLevel = dirent => {
2275
+ return dirent.depth === 1;
2276
+ };
2277
+
2247
2278
  const toCollapsedDirent = dirent => {
2248
2279
  if (dirent.type === DirectoryExpanded) {
2249
2280
  return {
@@ -2911,6 +2942,9 @@ const {
2911
2942
  set,
2912
2943
  wrapGetter
2913
2944
  } = create$a();
2945
+ const hasSameVisibleExplorerItemInputs = (oldState, newState) => {
2946
+ return oldState.items === newState.items && oldState.minLineY === newState.minLineY && oldState.height === newState.height && oldState.itemHeight === newState.itemHeight && oldState.focusedIndex === newState.focusedIndex && oldState.editingIndex === newState.editingIndex && oldState.editingIcon === newState.editingIcon && oldState.cutItems === newState.cutItems && oldState.editingErrorMessage === newState.editingErrorMessage && oldState.dropTargets === newState.dropTargets && oldState.fileIconCache === newState.fileIconCache && oldState.decorations === newState.decorations && oldState.useChevrons === newState.useChevrons && oldState.sourceControlIgnoredUris === newState.sourceControlIgnoredUris;
2947
+ };
2914
2948
  const wrapListItemCommand = fn => {
2915
2949
  const wrappedCommand = async (id, ...args) => {
2916
2950
  const {
@@ -2938,10 +2972,10 @@ const wrapListItemCommand = fn => {
2938
2972
  } = updatedState;
2939
2973
  const intermediate = get(id);
2940
2974
  set(id, intermediate.oldState, updatedState);
2941
- const maxLineY = getExplorerMaxLineY(minLineY, height, itemHeight, items.length);
2942
- if (items === intermediate.newState.items && minLineY === intermediate.newState.minLineY && height === intermediate.newState.height && itemHeight === intermediate.newState.itemHeight && editingIcon === intermediate.newState.editingIcon && cutItems === intermediate.newState.cutItems && editingErrorMessage === intermediate.newState.editingErrorMessage && dropTargets === intermediate.newState.dropTargets && fileIconCache === intermediate.newState.fileIconCache && decorations === intermediate.newState.decorations) {
2975
+ if (hasSameVisibleExplorerItemInputs(intermediate.newState, updatedState)) {
2943
2976
  return;
2944
2977
  }
2978
+ const maxLineY = getExplorerMaxLineY(minLineY, height, itemHeight, items.length);
2945
2979
  const visible = items.slice(minLineY, maxLineY);
2946
2980
  const {
2947
2981
  icons,
@@ -3113,25 +3147,26 @@ const expandAll = async state => {
3113
3147
  } = dirent;
3114
3148
  const newDirents = [...items];
3115
3149
  // TODO fetch child dirents in parallel
3116
- for (const dirent of newDirents) {
3117
- if (dirent.depth === depth && dirent.type === Directory) {
3118
- // TODO expand
3119
- // TODO avoid mutating state here
3120
- // @ts-ignore
3121
- dirent.type = DirectoryExpanding;
3122
- // TODO handle error
3123
- // TODO race condition
3124
- const childDirents = await getChildDirents(pathSeparator, dirent.path, dirent.depth);
3125
- const newIndex = newDirents.indexOf(dirent);
3126
- if (newIndex === -1) {
3127
- continue;
3128
- }
3129
- newDirents.splice(newIndex + 1, 0, ...childDirents);
3130
- // TODO avoid mutating state here
3131
- // @ts-ignore
3132
- dirent.type = DirectoryExpanded;
3133
- // await expand(state, dirent.index)
3150
+ for (const dirent of items) {
3151
+ if (dirent.depth !== depth || dirent.type !== Directory) {
3152
+ continue;
3153
+ }
3154
+ // TODO expand
3155
+ // TODO avoid mutating state here
3156
+ // @ts-ignore
3157
+ dirent.type = DirectoryExpanding;
3158
+ // TODO handle error
3159
+ // TODO race condition
3160
+ const childDirents = await getChildDirents(pathSeparator, dirent.path, dirent.depth);
3161
+ const newIndex = newDirents.indexOf(dirent);
3162
+ if (newIndex === -1) {
3163
+ continue;
3134
3164
  }
3165
+ newDirents.splice(newIndex + 1, 0, ...childDirents);
3166
+ // TODO avoid mutating state here
3167
+ // @ts-ignore
3168
+ dirent.type = DirectoryExpanded;
3169
+ // await expand(state, dirent.index)
3135
3170
  }
3136
3171
  return {
3137
3172
  ...state,
@@ -3290,11 +3325,7 @@ const lastIndex = array => {
3290
3325
  return array.length - 1;
3291
3326
  };
3292
3327
  const fromAsync = async asyncIterable => {
3293
- const children = [];
3294
- for await (const value of asyncIterable) {
3295
- children.push(value);
3296
- }
3297
- return children;
3328
+ return Array.fromAsync(asyncIterable);
3298
3329
  };
3299
3330
 
3300
3331
  const focusLast = state => {
@@ -4294,12 +4325,19 @@ const handleContextMenuAtIndex = async (state, index, x, y) => {
4294
4325
  number(x);
4295
4326
  number(y);
4296
4327
  const {
4328
+ items,
4297
4329
  uid
4298
4330
  } = state;
4331
+ const contextMenuItem = items[index];
4332
+ const newItems = contextMenuItem && !contextMenuItem.selected ? items.map(item => ({
4333
+ ...item,
4334
+ selected: false
4335
+ })) : items;
4299
4336
  const newState = {
4300
4337
  ...state,
4301
4338
  focused: false,
4302
- focusedIndex: index
4339
+ focusedIndex: index,
4340
+ items: newItems
4303
4341
  };
4304
4342
  set(uid, state, newState);
4305
4343
  await show2(uid, Explorer, x, y, {
@@ -5249,8 +5287,8 @@ const handleKeyDown = (state, key) => {
5249
5287
  if (typeAheadTimeout.value) {
5250
5288
  clearTimeout(typeAheadTimeout.value);
5251
5289
  }
5252
- typeAheadTimeout.value = setTimeout(async () => {
5253
- await invoke$2('Explorer.cancelTypeAhead');
5290
+ typeAheadTimeout.value = setTimeout(() => {
5291
+ void invoke$2('Explorer.cancelTypeAhead');
5254
5292
  }, focusWordTimeout);
5255
5293
  if (matchingIndex === -1) {
5256
5294
  return {
@@ -5572,13 +5610,14 @@ const handleUpload = async (state, dirents) => {
5572
5610
  // TODO switch
5573
5611
  // TODO symlink might not be possible to be copied
5574
5612
  // TODO create folder if type is 2
5575
- if (dirent.type === /* File */1) {
5576
- // TODO reading text might be inefficient for binary files
5577
- // but not sure how else to send them via jsonrpc
5578
- const content = await dirent.file.text();
5579
- const absolutePath = [root, dirent.file.name].join(pathSeparator);
5580
- await writeFile(absolutePath, content);
5613
+ if (dirent.type !== /* File */1) {
5614
+ continue;
5581
5615
  }
5616
+ // TODO reading text might be inefficient for binary files
5617
+ // but not sure how else to send them via jsonrpc
5618
+ const content = await dirent.file.text();
5619
+ const absolutePath = [root, dirent.file.name].join(pathSeparator);
5620
+ await writeFile(absolutePath, content);
5582
5621
  }
5583
5622
  };
5584
5623
 
@@ -5661,7 +5700,7 @@ const confirmDelete = async paths => {
5661
5700
  // TODO use i18n string
5662
5701
  const message = paths.length === 1 ? `Are you sure you want to delete "${paths[0]}"?` : `Are you sure you want to delete ${paths.length} items?`;
5663
5702
  const result = await confirm(message);
5664
- return result === true;
5703
+ return result;
5665
5704
  };
5666
5705
 
5667
5706
  const showErrorAlert = async errorMessage => {
@@ -6604,7 +6643,17 @@ const revealItemHidden = async (state, uri) => {
6604
6643
  const pathPartsChildrenFlat = pathPartsChildren.flat();
6605
6644
  const orderedPathParts = orderDirents(pathPartsChildrenFlat);
6606
6645
  const mergedDirents = mergeVisibleWithHiddenItems(items, orderedPathParts);
6607
- const index = getIndex(mergedDirents, uri);
6646
+ const expandedPaths = new Set(pathPartsToReveal.map(pathPart => pathPart.path));
6647
+ const newDirents = mergedDirents.map(item => {
6648
+ if (expandedPaths.has(item.path) && item.type === Directory) {
6649
+ return {
6650
+ ...item,
6651
+ type: DirectoryExpanded
6652
+ };
6653
+ }
6654
+ return item;
6655
+ });
6656
+ const index = getIndex(newDirents, uri);
6608
6657
  if (index === -1) {
6609
6658
  throw new Error(`File not found in explorer ${uri}`);
6610
6659
  }
@@ -6616,7 +6665,7 @@ const revealItemHidden = async (state, uri) => {
6616
6665
  ...state,
6617
6666
  focused: true,
6618
6667
  focusedIndex: index,
6619
- items: mergedDirents,
6668
+ items: newDirents,
6620
6669
  maxLineY: newMaxLineY,
6621
6670
  minLineY: newMinLineY
6622
6671
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lvce-editor/explorer-view",
3
- "version": "6.13.0",
3
+ "version": "6.15.0",
4
4
  "description": "Explorer Worker",
5
5
  "repository": {
6
6
  "type": "git",