@lvce-editor/explorer-view 6.11.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.
- package/dist/explorerViewWorkerMain.js +200 -179
- package/package.json +1 -1
|
@@ -189,7 +189,7 @@ class AssertionError extends Error {
|
|
|
189
189
|
const Object$1 = 1;
|
|
190
190
|
const Number$1 = 2;
|
|
191
191
|
const Array$1 = 3;
|
|
192
|
-
const String = 4;
|
|
192
|
+
const String$1 = 4;
|
|
193
193
|
const Boolean$1 = 5;
|
|
194
194
|
const Function = 6;
|
|
195
195
|
const Null = 7;
|
|
@@ -201,7 +201,7 @@ const getType = value => {
|
|
|
201
201
|
case 'function':
|
|
202
202
|
return Function;
|
|
203
203
|
case 'string':
|
|
204
|
-
return String;
|
|
204
|
+
return String$1;
|
|
205
205
|
case 'object':
|
|
206
206
|
if (value === null) {
|
|
207
207
|
return Null;
|
|
@@ -236,7 +236,7 @@ const array = value => {
|
|
|
236
236
|
};
|
|
237
237
|
const string = value => {
|
|
238
238
|
const type = getType(value);
|
|
239
|
-
if (type !== String) {
|
|
239
|
+
if (type !== String$1) {
|
|
240
240
|
throw new AssertionError('expected value to be of type string');
|
|
241
241
|
}
|
|
242
242
|
};
|
|
@@ -1436,8 +1436,8 @@ const applyFileOperations = async operations => {
|
|
|
1436
1436
|
}
|
|
1437
1437
|
return '';
|
|
1438
1438
|
} catch (error) {
|
|
1439
|
-
console.error(new VError(error,
|
|
1440
|
-
return
|
|
1439
|
+
console.error(new VError(error, 'Failed to apply file operations'));
|
|
1440
|
+
return String(error);
|
|
1441
1441
|
}
|
|
1442
1442
|
};
|
|
1443
1443
|
|
|
@@ -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(
|
|
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;
|
|
@@ -1981,7 +1998,7 @@ const validateFileName2 = (name, siblingFileNames = []) => {
|
|
|
1981
1998
|
}
|
|
1982
1999
|
|
|
1983
2000
|
// Disallow reserved directory names
|
|
1984
|
-
if (
|
|
2001
|
+
if (['.', '..', '...'].includes(name)) {
|
|
1985
2002
|
return theNameIsNotValid();
|
|
1986
2003
|
}
|
|
1987
2004
|
|
|
@@ -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
|
-
|
|
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 {
|
|
@@ -2384,7 +2414,7 @@ const getPaths = items => {
|
|
|
2384
2414
|
};
|
|
2385
2415
|
|
|
2386
2416
|
const getSimpleIconRequestType = direntType => {
|
|
2387
|
-
if (
|
|
2417
|
+
if ([Directory, DirectoryExpanded, EditingDirectoryExpanded, EditingFolder].includes(direntType)) {
|
|
2388
2418
|
return 2;
|
|
2389
2419
|
}
|
|
2390
2420
|
return 1;
|
|
@@ -2625,12 +2655,12 @@ const getChildrenWithCount = (nodes, startIndex, childCount) => {
|
|
|
2625
2655
|
};
|
|
2626
2656
|
|
|
2627
2657
|
const compareNodes = (oldNode, newNode) => {
|
|
2628
|
-
const patches = [];
|
|
2629
2658
|
// Check if node type changed - return null to signal incompatible nodes
|
|
2630
2659
|
// (caller should handle this with a Replace operation)
|
|
2631
2660
|
if (oldNode.type !== newNode.type) {
|
|
2632
2661
|
return null;
|
|
2633
2662
|
}
|
|
2663
|
+
const patches = [];
|
|
2634
2664
|
// Handle reference nodes - special handling for uid changes
|
|
2635
2665
|
if (oldNode.type === Reference) {
|
|
2636
2666
|
if (oldNode.uid !== newNode.uid) {
|
|
@@ -2666,7 +2696,7 @@ const compareNodes = (oldNode, newNode) => {
|
|
|
2666
2696
|
}
|
|
2667
2697
|
// Check for removed attributes
|
|
2668
2698
|
for (const key of oldKeys) {
|
|
2669
|
-
if (!(key
|
|
2699
|
+
if (!Object.hasOwn(newNode, key)) {
|
|
2670
2700
|
patches.push({
|
|
2671
2701
|
type: RemoveAttribute,
|
|
2672
2702
|
key
|
|
@@ -2684,11 +2714,78 @@ const treeToArray = node => {
|
|
|
2684
2714
|
return result;
|
|
2685
2715
|
};
|
|
2686
2716
|
|
|
2717
|
+
const navigateToChild = (patches, currentChildIndex, index) => {
|
|
2718
|
+
if (currentChildIndex === -1) {
|
|
2719
|
+
patches.push({
|
|
2720
|
+
type: NavigateChild,
|
|
2721
|
+
index
|
|
2722
|
+
});
|
|
2723
|
+
return index;
|
|
2724
|
+
}
|
|
2725
|
+
if (currentChildIndex !== index) {
|
|
2726
|
+
patches.push({
|
|
2727
|
+
type: NavigateSibling,
|
|
2728
|
+
index
|
|
2729
|
+
});
|
|
2730
|
+
}
|
|
2731
|
+
return index;
|
|
2732
|
+
};
|
|
2733
|
+
const navigateToParent = (patches, currentChildIndex) => {
|
|
2734
|
+
if (currentChildIndex >= 0) {
|
|
2735
|
+
patches.push({
|
|
2736
|
+
type: NavigateParent
|
|
2737
|
+
});
|
|
2738
|
+
}
|
|
2739
|
+
return -1;
|
|
2740
|
+
};
|
|
2741
|
+
const addTree = (newNode, patches) => {
|
|
2742
|
+
patches.push({
|
|
2743
|
+
type: Add,
|
|
2744
|
+
nodes: treeToArray(newNode)
|
|
2745
|
+
});
|
|
2746
|
+
};
|
|
2747
|
+
const replaceTree = (newNode, patches) => {
|
|
2748
|
+
patches.push({
|
|
2749
|
+
type: Replace,
|
|
2750
|
+
nodes: treeToArray(newNode)
|
|
2751
|
+
});
|
|
2752
|
+
};
|
|
2753
|
+
const diffExistingChild = (oldNode, newNode, patches, currentChildIndex, index) => {
|
|
2754
|
+
const nodePatches = compareNodes(oldNode.node, newNode.node);
|
|
2755
|
+
if (nodePatches === null) {
|
|
2756
|
+
const nextChildIndex = navigateToChild(patches, currentChildIndex, index);
|
|
2757
|
+
replaceTree(newNode, patches);
|
|
2758
|
+
return nextChildIndex;
|
|
2759
|
+
}
|
|
2760
|
+
const hasChildrenToCompare = oldNode.children.length > 0 || newNode.children.length > 0;
|
|
2761
|
+
if (nodePatches.length === 0 && !hasChildrenToCompare) {
|
|
2762
|
+
return currentChildIndex;
|
|
2763
|
+
}
|
|
2764
|
+
const nextChildIndex = navigateToChild(patches, currentChildIndex, index);
|
|
2765
|
+
if (nodePatches.length > 0) {
|
|
2766
|
+
patches.push(...nodePatches);
|
|
2767
|
+
}
|
|
2768
|
+
if (hasChildrenToCompare) {
|
|
2769
|
+
diffChildren(oldNode.children, newNode.children, patches);
|
|
2770
|
+
}
|
|
2771
|
+
return nextChildIndex;
|
|
2772
|
+
};
|
|
2773
|
+
const diffRootNode = (oldNode, newNode, patches) => {
|
|
2774
|
+
const nodePatches = compareNodes(oldNode.node, newNode.node);
|
|
2775
|
+
if (nodePatches === null) {
|
|
2776
|
+
replaceTree(newNode, patches);
|
|
2777
|
+
return;
|
|
2778
|
+
}
|
|
2779
|
+
if (nodePatches.length > 0) {
|
|
2780
|
+
patches.push(...nodePatches);
|
|
2781
|
+
}
|
|
2782
|
+
if (oldNode.children.length > 0 || newNode.children.length > 0) {
|
|
2783
|
+
diffChildren(oldNode.children, newNode.children, patches);
|
|
2784
|
+
}
|
|
2785
|
+
};
|
|
2687
2786
|
const diffChildren = (oldChildren, newChildren, patches) => {
|
|
2688
2787
|
const maxLength = Math.max(oldChildren.length, newChildren.length);
|
|
2689
|
-
// Track where we are: -1 means at parent, >= 0 means at child index
|
|
2690
2788
|
let currentChildIndex = -1;
|
|
2691
|
-
// Collect indices of children to remove (we'll add these patches at the end in reverse order)
|
|
2692
2789
|
const indicesToRemove = [];
|
|
2693
2790
|
for (let i = 0; i < maxLength; i++) {
|
|
2694
2791
|
const oldNode = oldChildren[i];
|
|
@@ -2697,88 +2794,17 @@ const diffChildren = (oldChildren, newChildren, patches) => {
|
|
|
2697
2794
|
continue;
|
|
2698
2795
|
}
|
|
2699
2796
|
if (!oldNode) {
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
});
|
|
2706
|
-
currentChildIndex = -1;
|
|
2707
|
-
}
|
|
2708
|
-
// Flatten the entire subtree so renderInternal can handle it
|
|
2709
|
-
const flatNodes = treeToArray(newNode);
|
|
2710
|
-
patches.push({
|
|
2711
|
-
type: Add,
|
|
2712
|
-
nodes: flatNodes
|
|
2713
|
-
});
|
|
2714
|
-
} else if (newNode) {
|
|
2715
|
-
// Compare nodes to see if we need any patches
|
|
2716
|
-
const nodePatches = compareNodes(oldNode.node, newNode.node);
|
|
2717
|
-
// If nodePatches is null, the node types are incompatible - need to replace
|
|
2718
|
-
if (nodePatches === null) {
|
|
2719
|
-
// Navigate to this child
|
|
2720
|
-
if (currentChildIndex === -1) {
|
|
2721
|
-
patches.push({
|
|
2722
|
-
type: NavigateChild,
|
|
2723
|
-
index: i
|
|
2724
|
-
});
|
|
2725
|
-
currentChildIndex = i;
|
|
2726
|
-
} else if (currentChildIndex !== i) {
|
|
2727
|
-
patches.push({
|
|
2728
|
-
type: NavigateSibling,
|
|
2729
|
-
index: i
|
|
2730
|
-
});
|
|
2731
|
-
currentChildIndex = i;
|
|
2732
|
-
}
|
|
2733
|
-
// Replace the entire subtree
|
|
2734
|
-
const flatNodes = treeToArray(newNode);
|
|
2735
|
-
patches.push({
|
|
2736
|
-
type: Replace,
|
|
2737
|
-
nodes: flatNodes
|
|
2738
|
-
});
|
|
2739
|
-
// After replace, we're at the new element (same position)
|
|
2740
|
-
continue;
|
|
2741
|
-
}
|
|
2742
|
-
// Check if we need to recurse into children
|
|
2743
|
-
const hasChildrenToCompare = oldNode.children.length > 0 || newNode.children.length > 0;
|
|
2744
|
-
// Only navigate to this element if we need to do something
|
|
2745
|
-
if (nodePatches.length > 0 || hasChildrenToCompare) {
|
|
2746
|
-
// Navigate to this child if not already there
|
|
2747
|
-
if (currentChildIndex === -1) {
|
|
2748
|
-
patches.push({
|
|
2749
|
-
type: NavigateChild,
|
|
2750
|
-
index: i
|
|
2751
|
-
});
|
|
2752
|
-
currentChildIndex = i;
|
|
2753
|
-
} else if (currentChildIndex !== i) {
|
|
2754
|
-
patches.push({
|
|
2755
|
-
type: NavigateSibling,
|
|
2756
|
-
index: i
|
|
2757
|
-
});
|
|
2758
|
-
currentChildIndex = i;
|
|
2759
|
-
}
|
|
2760
|
-
// Apply node patches (these apply to the current element, not children)
|
|
2761
|
-
if (nodePatches.length > 0) {
|
|
2762
|
-
patches.push(...nodePatches);
|
|
2763
|
-
}
|
|
2764
|
-
// Compare children recursively
|
|
2765
|
-
if (hasChildrenToCompare) {
|
|
2766
|
-
diffChildren(oldNode.children, newNode.children, patches);
|
|
2767
|
-
}
|
|
2768
|
-
}
|
|
2769
|
-
} else {
|
|
2770
|
-
// Remove old node - collect the index for later removal
|
|
2797
|
+
currentChildIndex = navigateToParent(patches, currentChildIndex);
|
|
2798
|
+
addTree(newNode, patches);
|
|
2799
|
+
continue;
|
|
2800
|
+
}
|
|
2801
|
+
if (!newNode) {
|
|
2771
2802
|
indicesToRemove.push(i);
|
|
2803
|
+
continue;
|
|
2772
2804
|
}
|
|
2805
|
+
currentChildIndex = diffExistingChild(oldNode, newNode, patches, currentChildIndex, i);
|
|
2773
2806
|
}
|
|
2774
|
-
|
|
2775
|
-
if (currentChildIndex >= 0) {
|
|
2776
|
-
patches.push({
|
|
2777
|
-
type: NavigateParent
|
|
2778
|
-
});
|
|
2779
|
-
}
|
|
2780
|
-
// Add remove patches in reverse order (highest index first)
|
|
2781
|
-
// This ensures indices remain valid as we remove
|
|
2807
|
+
navigateToParent(patches, currentChildIndex);
|
|
2782
2808
|
for (let j = indicesToRemove.length - 1; j >= 0; j--) {
|
|
2783
2809
|
patches.push({
|
|
2784
2810
|
type: RemoveChild,
|
|
@@ -2787,33 +2813,11 @@ const diffChildren = (oldChildren, newChildren, patches) => {
|
|
|
2787
2813
|
}
|
|
2788
2814
|
};
|
|
2789
2815
|
const diffTrees = (oldTree, newTree, patches, path) => {
|
|
2790
|
-
// At the root level (path.length === 0), we're already AT the element
|
|
2791
|
-
// So we compare the root node directly, then compare its children
|
|
2792
2816
|
if (path.length === 0 && oldTree.length === 1 && newTree.length === 1) {
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
// Compare root nodes
|
|
2796
|
-
const nodePatches = compareNodes(oldNode.node, newNode.node);
|
|
2797
|
-
// If nodePatches is null, the root node types are incompatible - need to replace
|
|
2798
|
-
if (nodePatches === null) {
|
|
2799
|
-
const flatNodes = treeToArray(newNode);
|
|
2800
|
-
patches.push({
|
|
2801
|
-
type: Replace,
|
|
2802
|
-
nodes: flatNodes
|
|
2803
|
-
});
|
|
2804
|
-
return;
|
|
2805
|
-
}
|
|
2806
|
-
if (nodePatches.length > 0) {
|
|
2807
|
-
patches.push(...nodePatches);
|
|
2808
|
-
}
|
|
2809
|
-
// Compare children
|
|
2810
|
-
if (oldNode.children.length > 0 || newNode.children.length > 0) {
|
|
2811
|
-
diffChildren(oldNode.children, newNode.children, patches);
|
|
2812
|
-
}
|
|
2813
|
-
} else {
|
|
2814
|
-
// Non-root level or multiple root elements - use the regular comparison
|
|
2815
|
-
diffChildren(oldTree, newTree, patches);
|
|
2817
|
+
diffRootNode(oldTree[0], newTree[0], patches);
|
|
2818
|
+
return;
|
|
2816
2819
|
}
|
|
2820
|
+
diffChildren(oldTree, newTree, patches);
|
|
2817
2821
|
};
|
|
2818
2822
|
|
|
2819
2823
|
const removeTrailingNavigationPatches = patches => {
|
|
@@ -2892,6 +2896,12 @@ const getVisibleExplorerItems = (items, minLineY, maxLineY, focusedIndex, editin
|
|
|
2892
2896
|
for (let i = minLineY; i < Math.min(maxLineY, items.length); i++) {
|
|
2893
2897
|
const item = items[i];
|
|
2894
2898
|
let chevron = getChevronType(item.type, useChevrons);
|
|
2899
|
+
const isEditing = i === editingIndex;
|
|
2900
|
+
let icon = icons[iconIndex++];
|
|
2901
|
+
if (isEditing) {
|
|
2902
|
+
icon = editingIcon;
|
|
2903
|
+
chevron = getEditingChevron(item.type);
|
|
2904
|
+
}
|
|
2895
2905
|
const isFocused = i === focusedIndex;
|
|
2896
2906
|
const id = isFocused ? 'TreeItemActive' : undefined;
|
|
2897
2907
|
const isSelected = item.selected;
|
|
@@ -2903,12 +2913,6 @@ const getVisibleExplorerItems = (items, minLineY, maxLineY, focusedIndex, editin
|
|
|
2903
2913
|
const className = getTreeItemClassName(isSelected, isFocused, isDropping, useChevrons, indent, decoration);
|
|
2904
2914
|
const expanded = getExpandedType(item.type);
|
|
2905
2915
|
const ariaExpanded = ariaExpandedValues[expanded];
|
|
2906
|
-
const isEditing = i === editingIndex;
|
|
2907
|
-
let icon = icons[iconIndex++];
|
|
2908
|
-
if (isEditing) {
|
|
2909
|
-
icon = editingIcon;
|
|
2910
|
-
chevron = getEditingChevron(item.type);
|
|
2911
|
-
}
|
|
2912
2916
|
visible.push({
|
|
2913
2917
|
...item,
|
|
2914
2918
|
ariaExpanded,
|
|
@@ -2937,6 +2941,9 @@ const {
|
|
|
2937
2941
|
set,
|
|
2938
2942
|
wrapGetter
|
|
2939
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
|
+
};
|
|
2940
2947
|
const wrapListItemCommand = fn => {
|
|
2941
2948
|
const wrappedCommand = async (id, ...args) => {
|
|
2942
2949
|
const {
|
|
@@ -2964,10 +2971,10 @@ const wrapListItemCommand = fn => {
|
|
|
2964
2971
|
} = updatedState;
|
|
2965
2972
|
const intermediate = get(id);
|
|
2966
2973
|
set(id, intermediate.oldState, updatedState);
|
|
2967
|
-
|
|
2968
|
-
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)) {
|
|
2969
2975
|
return;
|
|
2970
2976
|
}
|
|
2977
|
+
const maxLineY = getExplorerMaxLineY(minLineY, height, itemHeight, items.length);
|
|
2971
2978
|
const visible = items.slice(minLineY, maxLineY);
|
|
2972
2979
|
const {
|
|
2973
2980
|
icons,
|
|
@@ -3139,25 +3146,26 @@ const expandAll = async state => {
|
|
|
3139
3146
|
} = dirent;
|
|
3140
3147
|
const newDirents = [...items];
|
|
3141
3148
|
// TODO fetch child dirents in parallel
|
|
3142
|
-
for (const dirent of
|
|
3143
|
-
if (dirent.depth
|
|
3144
|
-
|
|
3145
|
-
// TODO avoid mutating state here
|
|
3146
|
-
// @ts-ignore
|
|
3147
|
-
dirent.type = DirectoryExpanding;
|
|
3148
|
-
// TODO handle error
|
|
3149
|
-
// TODO race condition
|
|
3150
|
-
const childDirents = await getChildDirents(pathSeparator, dirent.path, dirent.depth);
|
|
3151
|
-
const newIndex = newDirents.indexOf(dirent);
|
|
3152
|
-
if (newIndex === -1) {
|
|
3153
|
-
continue;
|
|
3154
|
-
}
|
|
3155
|
-
newDirents.splice(newIndex + 1, 0, ...childDirents);
|
|
3156
|
-
// TODO avoid mutating state here
|
|
3157
|
-
// @ts-ignore
|
|
3158
|
-
dirent.type = DirectoryExpanded;
|
|
3159
|
-
// await expand(state, dirent.index)
|
|
3149
|
+
for (const dirent of items) {
|
|
3150
|
+
if (dirent.depth !== depth || dirent.type !== Directory) {
|
|
3151
|
+
continue;
|
|
3160
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;
|
|
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)
|
|
3161
3169
|
}
|
|
3162
3170
|
return {
|
|
3163
3171
|
...state,
|
|
@@ -3316,11 +3324,7 @@ const lastIndex = array => {
|
|
|
3316
3324
|
return array.length - 1;
|
|
3317
3325
|
};
|
|
3318
3326
|
const fromAsync = async asyncIterable => {
|
|
3319
|
-
|
|
3320
|
-
for await (const value of asyncIterable) {
|
|
3321
|
-
children.push(value);
|
|
3322
|
-
}
|
|
3323
|
-
return children;
|
|
3327
|
+
return Array.fromAsync(asyncIterable);
|
|
3324
3328
|
};
|
|
3325
3329
|
|
|
3326
3330
|
const focusLast = state => {
|
|
@@ -3845,7 +3849,7 @@ const OpenFolder = 'OpenFolder';
|
|
|
3845
3849
|
const Refresh$1 = 'Refresh';
|
|
3846
3850
|
|
|
3847
3851
|
const isFolder = direntType => {
|
|
3848
|
-
return
|
|
3852
|
+
return [Directory, DirectoryExpanded, SymLinkFolder].includes(direntType);
|
|
3849
3853
|
};
|
|
3850
3854
|
const getFittingIndex = (dirents, startIndex) => {
|
|
3851
3855
|
for (let i = startIndex; i >= 0; i--) {
|
|
@@ -4320,12 +4324,19 @@ const handleContextMenuAtIndex = async (state, index, x, y) => {
|
|
|
4320
4324
|
number(x);
|
|
4321
4325
|
number(y);
|
|
4322
4326
|
const {
|
|
4327
|
+
items,
|
|
4323
4328
|
uid
|
|
4324
4329
|
} = state;
|
|
4330
|
+
const contextMenuItem = items[index];
|
|
4331
|
+
const newItems = contextMenuItem && !contextMenuItem.selected ? items.map(item => ({
|
|
4332
|
+
...item,
|
|
4333
|
+
selected: false
|
|
4334
|
+
})) : items;
|
|
4325
4335
|
const newState = {
|
|
4326
4336
|
...state,
|
|
4327
4337
|
focused: false,
|
|
4328
|
-
focusedIndex: index
|
|
4338
|
+
focusedIndex: index,
|
|
4339
|
+
items: newItems
|
|
4329
4340
|
};
|
|
4330
4341
|
set(uid, state, newState);
|
|
4331
4342
|
await show2(uid, Explorer, x, y, {
|
|
@@ -4386,6 +4397,7 @@ const handleCopy = async state => {
|
|
|
4386
4397
|
await writeNativeFiles('copy', files);
|
|
4387
4398
|
return {
|
|
4388
4399
|
...state,
|
|
4400
|
+
cutItems: [],
|
|
4389
4401
|
pasteShouldMove: false
|
|
4390
4402
|
};
|
|
4391
4403
|
};
|
|
@@ -4874,11 +4886,7 @@ const getDroppedName = item => {
|
|
|
4874
4886
|
return item.name;
|
|
4875
4887
|
};
|
|
4876
4888
|
const getFileSystemHandlesNormalized = fileSystemHandles => {
|
|
4877
|
-
|
|
4878
|
-
for (const item of fileSystemHandles) {
|
|
4879
|
-
normalized.push(getFileSystemHandle(item));
|
|
4880
|
-
}
|
|
4881
|
-
return normalized;
|
|
4889
|
+
return Array.from(fileSystemHandles, getFileSystemHandle);
|
|
4882
4890
|
};
|
|
4883
4891
|
const uploadFileSystemHandles = async (root, pathSeparator, fileSystemHandles) => {
|
|
4884
4892
|
if (fileSystemHandles.length === 0) {
|
|
@@ -5258,7 +5266,7 @@ const isAscii = key => {
|
|
|
5258
5266
|
return RE_ASCII.test(key);
|
|
5259
5267
|
};
|
|
5260
5268
|
|
|
5261
|
-
|
|
5269
|
+
const typeAheadTimeout = {};
|
|
5262
5270
|
const handleKeyDown = (state, key) => {
|
|
5263
5271
|
const {
|
|
5264
5272
|
focusedIndex,
|
|
@@ -5275,10 +5283,10 @@ const handleKeyDown = (state, key) => {
|
|
|
5275
5283
|
const newFocusWord = focusWord + key.toLowerCase();
|
|
5276
5284
|
const itemNames = items.map(item => item.name);
|
|
5277
5285
|
const matchingIndex = filterByFocusWord(itemNames, focusedIndex, newFocusWord);
|
|
5278
|
-
if (
|
|
5279
|
-
clearTimeout(
|
|
5286
|
+
if (typeAheadTimeout.value) {
|
|
5287
|
+
clearTimeout(typeAheadTimeout.value);
|
|
5280
5288
|
}
|
|
5281
|
-
|
|
5289
|
+
typeAheadTimeout.value = setTimeout(async () => {
|
|
5282
5290
|
await invoke$2('Explorer.cancelTypeAhead');
|
|
5283
5291
|
}, focusWordTimeout);
|
|
5284
5292
|
if (matchingIndex === -1) {
|
|
@@ -5601,13 +5609,14 @@ const handleUpload = async (state, dirents) => {
|
|
|
5601
5609
|
// TODO switch
|
|
5602
5610
|
// TODO symlink might not be possible to be copied
|
|
5603
5611
|
// TODO create folder if type is 2
|
|
5604
|
-
if (dirent.type
|
|
5605
|
-
|
|
5606
|
-
// but not sure how else to send them via jsonrpc
|
|
5607
|
-
const content = await dirent.file.text();
|
|
5608
|
-
const absolutePath = [root, dirent.file.name].join(pathSeparator);
|
|
5609
|
-
await writeFile(absolutePath, content);
|
|
5612
|
+
if (dirent.type !== /* File */1) {
|
|
5613
|
+
continue;
|
|
5610
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);
|
|
5611
5620
|
}
|
|
5612
5621
|
};
|
|
5613
5622
|
|
|
@@ -5667,7 +5676,7 @@ const getContainingFolder = (root, dirents, focusedIndex, pathSeparator) => {
|
|
|
5667
5676
|
const dirent = dirents[focusedIndex];
|
|
5668
5677
|
const direntPath = dirent.path;
|
|
5669
5678
|
const direntParentPath = direntPath.slice(0, -(dirent.name.length + 1));
|
|
5670
|
-
const path =
|
|
5679
|
+
const path = direntParentPath;
|
|
5671
5680
|
return path;
|
|
5672
5681
|
};
|
|
5673
5682
|
|
|
@@ -5690,7 +5699,7 @@ const confirmDelete = async paths => {
|
|
|
5690
5699
|
// TODO use i18n string
|
|
5691
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?`;
|
|
5692
5701
|
const result = await confirm(message);
|
|
5693
|
-
return result
|
|
5702
|
+
return result;
|
|
5694
5703
|
};
|
|
5695
5704
|
|
|
5696
5705
|
const showErrorAlert = async errorMessage => {
|
|
@@ -5893,7 +5902,7 @@ const getDragLabel = urls => {
|
|
|
5893
5902
|
if (urls.length === 1) {
|
|
5894
5903
|
return getBaseName('/', urls[0]);
|
|
5895
5904
|
}
|
|
5896
|
-
return
|
|
5905
|
+
return String(urls.length);
|
|
5897
5906
|
};
|
|
5898
5907
|
|
|
5899
5908
|
const toUri = path => {
|
|
@@ -6633,7 +6642,17 @@ const revealItemHidden = async (state, uri) => {
|
|
|
6633
6642
|
const pathPartsChildrenFlat = pathPartsChildren.flat();
|
|
6634
6643
|
const orderedPathParts = orderDirents(pathPartsChildrenFlat);
|
|
6635
6644
|
const mergedDirents = mergeVisibleWithHiddenItems(items, orderedPathParts);
|
|
6636
|
-
const
|
|
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);
|
|
6637
6656
|
if (index === -1) {
|
|
6638
6657
|
throw new Error(`File not found in explorer ${uri}`);
|
|
6639
6658
|
}
|
|
@@ -6645,7 +6664,7 @@ const revealItemHidden = async (state, uri) => {
|
|
|
6645
6664
|
...state,
|
|
6646
6665
|
focused: true,
|
|
6647
6666
|
focusedIndex: index,
|
|
6648
|
-
items:
|
|
6667
|
+
items: newDirents,
|
|
6649
6668
|
maxLineY: newMaxLineY,
|
|
6650
6669
|
minLineY: newMinLineY
|
|
6651
6670
|
};
|
|
@@ -6709,6 +6728,8 @@ const saveState = state => {
|
|
|
6709
6728
|
};
|
|
6710
6729
|
};
|
|
6711
6730
|
|
|
6731
|
+
// TODO select all should only select all items in the current folder
|
|
6732
|
+
// and when calling it next item, expand selection to its parent folder
|
|
6712
6733
|
const selectAll = state => {
|
|
6713
6734
|
const {
|
|
6714
6735
|
items
|
|
@@ -6810,7 +6831,7 @@ const getEditingIcon = async (editingType, value, direntType) => {
|
|
|
6810
6831
|
name: value
|
|
6811
6832
|
});
|
|
6812
6833
|
}
|
|
6813
|
-
if (direntType
|
|
6834
|
+
if (direntType !== undefined && [Directory, EditingFolder, EditingDirectoryExpanded].includes(direntType)) {
|
|
6814
6835
|
return invoke$2('IconTheme.getFolderIcon', {
|
|
6815
6836
|
name: value
|
|
6816
6837
|
});
|