Skip to content

desktop: sortable file list headers, on both panes - #34

Merged
ralyodio merged 1 commit into
mainfrom
worktree-filelist-sorting
Sep 6, 2026
Merged

desktop: sortable file list headers, on both panes#34
ralyodio merged 1 commit into
mainfrom
worktree-filelist-sorting

Conversation

@ralyodio

@ralyodio ralyodio commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

Click Name, Size or Modified to sort a listing; click the same column again to reverse it. Size and Modified open descending, because nobody clicks Size to find the smallest file.

Both panes get it from the one component, and each keeps its own sort, so a server pane sorts exactly like a local one. It is a client-side reorder of rows the app already holds: no second listing, no SSH round trip, no rsync.

Rules that hold in every direction

  • Directories stay above files, so reversing Size does not scatter folders through the list.
  • Sorting by size leaves the folder block on name. A directory reports its own inode size rather than the size of its contents, which is why that column already draws an em dash for them.

Two details that would otherwise bite

  • Names collate naturally and case-insensitively, so file10 sorts after file2 and Photos does not form a block above every lowercase name. Every comparison falls back to the exact string, because a collator that ignores case calls README and readme equal, and equal entries keep arrival order — which differs between the local lister and SFTP, so the same folder would draw one way on the left and another on the right.
  • The keyboard cursor follows its row. It is an index into the visible rows, so re-sorting without moving it left it pointing at whatever row slid into that position.

Verification

  • 17 unit tests on the comparator (natural order, folder grouping, both directions per column, an unparseable mtime, tie-breaking, and that the caller's array is not reordered).
  • pnpm typecheck clean across all 8 projects; pnpm test 568 passing.
  • Driven in headless Chromium under the window's real CSP with a mocked preload bridge: all three columns in both directions, dark and light, and at the 960x600 minimum window. No CSP refusals.

Not included: the CLI's two-pane TUI. It has no column headers to click and its entries carry no mtime, so sorting there is a keybinding plus listing plumbing rather than the same change.

🤖 Generated with Claude Code

https://claude.ai/code/session_012Q2bt449mEJSHoEZzaemCn

Click Name, Size or Modified to sort a listing; click the same column
again to reverse it. Size and Modified open descending, because nobody
clicks Size to find the smallest file.

Both panes get it from the one component, and each keeps its own sort:
a server pane sorts exactly like a local one. It is a client-side
reorder of rows the app already holds, so it costs no second listing,
no SSH round trip and no rsync.

Directories stay above files in every direction, so reversing Size does
not scatter folders through the list, and sorting by size leaves the
folder block on name -- a directory reports its own inode size, not the
size of its contents, which is why that column already draws an em dash
for them.

Two details that would otherwise bite:

- Names now collate naturally and case-insensitively, so file10 sorts
  after file2 and Photos does not form a block above every lowercase
  name. Every comparison falls back to the exact string, because a
  collator that ignores case calls README and readme equal, and equal
  entries keep arrival order -- which differs between the local lister
  and SFTP, so the same folder would draw one way on the left and
  another on the right.
- The keyboard cursor is an index into the visible rows, so re-sorting
  without moving it leaves it pointing at whatever row slid into that
  position. It now follows the row it was on.

Verified in headless Chromium under the window's real CSP with a mocked
bridge: all three columns in both directions, both themes, and at the
960x600 minimum window.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012Q2bt449mEJSHoEZzaemCn
@ralyodio
ralyodio merged commit d1312c0 into main Sep 6, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant