Load picker: vi-style navigation (j/k) — UX + makes the picker demoable in casts #24

Closed
opened 2026-06-10 18:11:14 +01:00 by claude-clouddev1 · 1 comment
Collaborator

Summary

Add vi-style navigation keys (j / k, and ideally g / G) to the load picker (Modal::LoadPicker, list sub-mode), alongside the existing arrow keys.

Motivation

Two reasons, one UX and one concrete:

  1. UX. vi-style j/k navigation is a near-universal, low-cost convenience in TUI list pickers; many users reach for it reflexively.

  2. It makes the load picker demoable in the documentation casts. The website records asciinema demos with autocast, whose key set is limited to single characters, ASCII control codes (^X), and waits — it cannot send arrow keys, PageUp/PageDown, Home/End, or function keys (those are multi-byte escape sequences; an attempt to fake ESC [ B fails because autocast's per-key delay makes the terminal read a lone Esc). The load picker currently navigates only with Up/Down, so a cast cannot move the selection. This blocks a proper projects demo on the website (the parameterless project commands — save as / new / load — are exactly the ones that read poorly as static text and most need a moving picture). With j/k (plain characters), autocast can drive the picker and we can record a real save as → new → load round-trip that switches projects.

Proposal

In src/app.rs, handle_load_picker_key, the LoadPickerSubMode::List match (around the existing KeyCode::Up / KeyCode::Down arms):

  • KeyCode::Char('j') → move selection down (same as KeyCode::Down).
  • KeyCode::Char('k') → move selection up (same as KeyCode::Up).
  • (optional, nice-to-have) KeyCode::Char('g') → jump to first entry; KeyCode::Char('G') → jump to last entry.

Keep all existing keys (Up/Down/Enter/Esc, and b/B for the path-entry sub-mode). Note b/B is already bound, so vi's horizontal h/l are not needed for this vertical list.

Implementation notes

  • Purely additive to the ADR-0015 load picker; no behaviour change to existing keys, so almost certainly no new ADR required — just this issue + the change.
  • Test-first (per project standards): there are existing picker tests in src/app.rs (search load_picker / LoadPicker). Add unit tests that j/k move the selection and respect the bounds (no wrap past first/last), mirroring the arrow-key tests; add g/G tests if implemented.
  • Consistency (consider, don't have to do here): if other list/confirmation modals would benefit from the same, it could be applied uniformly — but the load picker is the one that unblocks the cast.

Related / out of scope

  • Relates to the website cast pipeline (ADR-website-001 §2) and complements #22 (in-app overlay hints) as another "make the app cast-friendly" item: the website's casts can only use typeable keys (characters, Enter, Tab, Ctrl-C), so any interaction we want to demonstrate must be reachable that way.
  • Out of scope here: output-pane scrolling in casts (needs PageUp/PageDown, same autocast limitation) — that would be a separate enhancement (e.g. vi-style Ctrl-d/Ctrl-u or j/k scroll keys for the output pane) if we want to demo scrolling later. autocast itself cannot be taught arrow keys; the fix is always app-side typeable keys.
## Summary Add **vi-style navigation keys** (`j` / `k`, and ideally `g` / `G`) to the **load picker** (`Modal::LoadPicker`, list sub-mode), alongside the existing arrow keys. ## Motivation Two reasons, one UX and one concrete: 1. **UX.** vi-style `j`/`k` navigation is a near-universal, low-cost convenience in TUI list pickers; many users reach for it reflexively. 2. **It makes the load picker demoable in the documentation casts.** The website records asciinema demos with **autocast**, whose key set is limited to single **characters**, ASCII **control codes** (`^X`), and waits — it cannot send **arrow keys, PageUp/PageDown, Home/End, or function keys** (those are multi-byte escape sequences; an attempt to fake `ESC [ B` fails because autocast's per-key delay makes the terminal read a lone `Esc`). The load picker currently navigates **only** with `Up`/`Down`, so a cast cannot move the selection. This blocks a proper **projects** demo on the website (the parameterless project commands — `save as` / `new` / `load` — are exactly the ones that read poorly as static text and most need a moving picture). With `j`/`k` (plain characters), autocast can drive the picker and we can record a real `save as → new → load` round-trip that switches projects. ## Proposal In `src/app.rs`, `handle_load_picker_key`, the `LoadPickerSubMode::List` match (around the existing `KeyCode::Up` / `KeyCode::Down` arms): - `KeyCode::Char('j')` → move selection **down** (same as `KeyCode::Down`). - `KeyCode::Char('k')` → move selection **up** (same as `KeyCode::Up`). - *(optional, nice-to-have)* `KeyCode::Char('g')` → jump to **first** entry; `KeyCode::Char('G')` → jump to **last** entry. Keep all existing keys (`Up`/`Down`/`Enter`/`Esc`, and `b`/`B` for the path-entry sub-mode). Note `b`/`B` is already bound, so vi's horizontal `h`/`l` are not needed for this vertical list. ## Implementation notes - Purely additive to the ADR-0015 load picker; no behaviour change to existing keys, so almost certainly **no new ADR** required — just this issue + the change. - **Test-first** (per project standards): there are existing picker tests in `src/app.rs` (search `load_picker` / `LoadPicker`). Add unit tests that `j`/`k` move the selection and respect the bounds (no wrap past first/last), mirroring the arrow-key tests; add `g`/`G` tests if implemented. - **Consistency (consider, don't have to do here):** if other list/confirmation modals would benefit from the same, it could be applied uniformly — but the load picker is the one that unblocks the cast. ## Related / out of scope - Relates to the website cast pipeline (**ADR-website-001 §2**) and complements **#22** (in-app overlay hints) as another "make the app cast-friendly" item: the website's casts can only use typeable keys (characters, Enter, Tab, Ctrl-C), so any interaction we want to demonstrate must be reachable that way. - **Out of scope here:** output-pane scrolling in casts (needs `PageUp`/`PageDown`, same autocast limitation) — that would be a separate enhancement (e.g. vi-style `Ctrl-d`/`Ctrl-u` or `j`/`k` scroll keys for the output pane) if we want to demo scrolling later. autocast itself cannot be taught arrow keys; the fix is always app-side typeable keys.
claude-clouddev1 added the enhancement label 2026-06-10 18:11:14 +01:00
Author
Collaborator

Implemented in commit 638b4c9 on main (purely additive to the ADR-0015 load picker; no ADR needed).

Added vi-style keys to the load picker's list sub-mode: j/k mirror Down/Up (bounds-respecting, no wrap), g/G jump to first/last. Existing keys (↑↓/Enter/Esc/b) unchanged; the footer hint is left as-is (new keys unadvertised, per request).

This makes the picker drivable by autocast (which can only send typeable characters, not arrow keys), unblocking a real save as → new → load projects demo on the website.

Tests: load_picker_jk_navigates_like_arrows, load_picker_g_jumps_to_first_and_last (test-first). Closing as done.

Implemented in commit `638b4c9` on `main` (purely additive to the ADR-0015 load picker; no ADR needed). Added vi-style keys to the load picker's list sub-mode: **`j`/`k`** mirror Down/Up (bounds-respecting, no wrap), **`g`/`G`** jump to first/last. Existing keys (↑↓/Enter/Esc/`b`) unchanged; the footer hint is left as-is (new keys unadvertised, per request). This makes the picker drivable by `autocast` (which can only send typeable characters, not arrow keys), unblocking a real `save as → new → load` projects demo on the website. Tests: `load_picker_jk_navigates_like_arrows`, `load_picker_g_jumps_to_first_and_last` (test-first). Closing as done.
Sign in to join this conversation.