Rewrite the TUI on HQTUI - #35
Conversation
The two-pane browser was ~940 lines of hand-rolled ANSI: its own escape
codes, its own key parser, its own box drawing, and a full-screen repaint
on every keystroke. It is now built on @profullstack/hqtui, which owns the
terminal, diffs frames and parses input, and the file is split three ways:
model.ts state and the pure functions over it (no terminal, no ssh)
view.ts the whole screen as one pure function of a snapshot
app.ts state and effects only
That split is what makes the screen testable. The old TUI wrote straight
to stdout, so the only way to know what it drew was to run it in a pty and
look; a frame is now a value, and view.test.ts asserts on rendered text.
What is new, beyond the same two panes:
- a live transfer panel: progress bar, rate, ETA, running add/update/
unchanged counts, and the files as rsync reports them. `s` used to be a
status line that changed once at the end. `esc` cancels it, through an
AbortSignal into runToCompletion.
- `/` filters a listing as you type, `o` cycles name/size/time sort (`O`
reverses), `.` toggles dotfiles, `?` lists every binding.
- the endpoint picker filters as you type, over names and hostnames both.
- modification times, right-aligned beside the sizes.
- the mouse: click a pane to focus it, click a row to select it, wheel to
scroll.
Three defects found by rendering frames rather than reading the code:
- Title and path share the panel's top border row and the box gives the
path priority. Budgeted against the full pane width, one pane lost its
title and the other lost its path — decided by a one-column rounding
difference between two panes showing the very same directory.
- hqtui's `truncate` keeps the head of a string, which is right for a
label and wrong for a path: every worktree under one repo rendered as
the identical string. Paths are shortened from the left now.
- A finished transfer showed rsync's last printed figure (80% on a
preview that had completed) instead of 100%.
The host-key prompt keeps its behaviour and its regression test: `q` still
quits from inside it, everything else is still swallowed, and a connect
that fails still takes its unanswered question with it.
Verified against the real binary through a pty: both panes list, the picker
loads ~17 ssh_config hosts and narrows to 2 on "see", a real rsync preview
and a real sync stream through the transfer panel, and both `q` and Ctrl+C
exit 0 with the alternate screen and cursor restored.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AKCDDzxxcypufp9u8cjoAk
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
|
Warning Review the following alerts detected in dependencies. According to your organization's Security Policy, it is recommended to resolve "Warn" alerts. Learn more about Socket for GitHub.
|
The two-pane browser was ~940 lines of hand-rolled ANSI: its own escape codes, its own key parser, its own box drawing, and a full-screen repaint on every keystroke. It now runs on
@profullstack/hqtui, and the file is split three ways:model.tsview.tsapp.tsThat split is what makes the screen testable. The old TUI wrote straight to stdout, so the only way to know what it drew was to run it in a pty and look. A frame is now a value, and
view.test.tsasserts on rendered text.New, beyond the same two panes
sused to be a status line that changed once at the end.esccancels it, through anAbortSignalintorunToCompletion./filters a listing as you type;ocycles name/size/time sort (Oreverses);.toggles dotfiles;?lists every binding.Three defects found by rendering frames rather than reading code
truncatekeeps the head of a string, which is right for a label and wrong for a path: every worktree under one repo rendered as the identical string. Paths are shortened from the left now.The host-key prompt keeps its behaviour and its regression test:
qstill quits from inside it, everything else is still swallowed, and a connect that fails still takes its unanswered question with it.Verification
601 tests pass (59 of them for the TUI, up from 15),
pnpm typecheckandpnpm buildare clean, and the real binary was driven through a pty: both panes list, the picker loads ~17ssh_confighosts and narrows to 2 on "see", a real rsync preview and a real sync stream through the transfer panel, and bothqand Ctrl+C exit 0 with the alternate screen and cursor restored.🤖 Generated with Claude Code
https://claude.ai/code/session_01AKCDDzxxcypufp9u8cjoAk