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