Skip to content

Commit f13c908

Browse files
committed
Consistent file sorting
This affects keyboard nav/selection. The solution isn't great as we end up sorting in multiple places, but we need to kick that can down the road a bit further.
1 parent 50d6947 commit f13c908

File tree

3 files changed

+45
-16
lines changed

3 files changed

+45
-16
lines changed

apps/desktop/src/lib/files/filetreeV3.ts

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -74,18 +74,44 @@ export function changesToFileTree(files: TreeChange[]): TreeNode {
7474
return acc;
7575
}
7676

77-
function fileTreeToList(node: TreeNode): TreeChange[] {
78-
const list: TreeChange[] = [];
79-
if (node.kind === 'file') list.push(node.change);
80-
node.children.forEach((child) => {
81-
list.push(...fileTreeToList(child));
82-
});
83-
return list;
84-
}
77+
export function sortLikeFileTree(changes: TreeChange[]): TreeChange[] {
78+
const caseSensitive = false;
79+
const locale = 'en';
80+
const numeric = true;
81+
const separator = '/';
82+
83+
const compareOptions: Intl.CollatorOptions = {
84+
sensitivity: caseSensitive ? 'case' : 'base',
85+
numeric: numeric,
86+
caseFirst: 'lower'
87+
};
88+
89+
return changes.sort((a, b) => {
90+
const partsA = a.path.split(separator);
91+
const partsB = b.path.split(separator);
92+
93+
// Compare directory by directory
94+
const minLength = Math.min(partsA.length, partsB.length);
8595

86-
// Sorts a file list the same way it is sorted in a file tree
87-
export function sortLikeFileTree(files: TreeChange[]): TreeChange[] {
88-
return fileTreeToList(changesToFileTree(files));
96+
for (let i = 0; i < minLength - 1; i++) {
97+
const comparison = partsA[i]!.localeCompare(partsB[i]!, locale, compareOptions);
98+
if (comparison !== 0) {
99+
return comparison;
100+
}
101+
}
102+
103+
// Same parent directory - subfolders first
104+
if (partsA.length !== partsB.length) {
105+
return partsB.length - partsA.length;
106+
}
107+
108+
// Same depth, compare final component
109+
return partsA[partsA.length - 1]!.localeCompare(
110+
partsB[partsB.length - 1]!,
111+
locale,
112+
compareOptions
113+
);
114+
});
89115
}
90116

91117
/**

apps/desktop/src/lib/selection/uncommittedService.svelte.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { sortLikeFileTree } from '$lib/files/filetreeV3';
12
import { type TreeChange } from '$lib/hunks/change';
23
import {
34
hunkHeaderEquals,
@@ -200,7 +201,7 @@ export class UncommittedService {
200201
Array.from(pathSet)
201202
);
202203

203-
return changes;
204+
return sortLikeFileTree(changes);
204205
}
205206

206207
/**
@@ -279,12 +280,14 @@ export class UncommittedService {
279280
}
280281

281282
getChangesByStackId(stackId: string | null): TreeChange[] {
282-
const stackIdChanges = uncommittedSelectors.treeChanges.selectByStackId(this.state, stackId);
283+
const stackIdChanges = sortLikeFileTree(
284+
uncommittedSelectors.treeChanges.selectByStackId(this.state, stackId)
285+
);
283286
return stackIdChanges;
284287
}
285288

286289
changesByStackId(stackId: string | null): Reactive<TreeChange[]> {
287-
const changes = $derived(this.getChangesByStackId(stackId));
290+
const changes = $derived(sortLikeFileTree(this.getChangesByStackId(stackId)));
288291
return reactive(() => changes);
289292
}
290293

apps/desktop/src/lib/stacks/stackService.svelte.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -560,7 +560,7 @@ export class StackService {
560560
{ projectId, commitId },
561561
{
562562
transform: (result) => ({
563-
changes: changesSelectors.selectAll(result.changes),
563+
changes: sortLikeFileTree(changesSelectors.selectAll(result.changes)),
564564
stats: result.stats,
565565
conflictEntries: result.conflictEntries
566566
})
@@ -611,7 +611,7 @@ export class StackService {
611611
},
612612
{
613613
transform: (result) => ({
614-
changes: changesSelectors.selectAll(result.changes),
614+
changes: sortLikeFileTree(changesSelectors.selectAll(result.changes)),
615615
stats: result.stats
616616
})
617617
}

0 commit comments

Comments
 (0)