100 lines
5.4 KiB
Markdown
100 lines
5.4 KiB
Markdown
# Plan — queue selection, visual mode, and the register
|
||
|
||
Executes `architecture/queue-register.md` against
|
||
`quality/queue-register.md`. Ordered by dependency. Three commits: **(A)**
|
||
the shared mark/visual trait with the library moved onto it, **(B)** queue
|
||
marks + the register in `cbd-tui`, **(C)** `cbd-web` parity + docs.
|
||
|
||
No server work: `Remove` already takes many positions and `Insert` takes a
|
||
path list (G25).
|
||
|
||
## A — Shared mark and visual behaviour (`cbd-tui`)
|
||
|
||
- [ ] **A1 — Fill in `MarkedPane`** in `app/list.rs`: `toggle_visual`,
|
||
`toggle_mark`, `toggle_mark_view`, `paint_between`, `selection` — moved
|
||
verbatim in behaviour from `library.rs`, with the `markable` gate taken
|
||
from the implementor. *Verifies:* G11, G12, G16.
|
||
- [ ] **A2 — `impl MarkedPane for Library`**, deleting the now-duplicated
|
||
inherent methods and keeping `get_selected` as a thin wrapper over
|
||
`selection` so existing call sites are untouched. `markable` =
|
||
`is_queable`. *Verifies:* the existing library visual-mode suite passes
|
||
unchanged (G11, G12).
|
||
- [ ] **A3 — `carry_marks`** in `app/list.rs`: greedy in-order path match,
|
||
drop marks whose track is gone, all-false when nothing matches, tolerant
|
||
of a short `old_marked`. *Verifies:* the ten `carry_marks_tests` (G2, G3).
|
||
- [ ] **A4 — Commit A.** Existing 91 tests plus the `carry_marks` suite
|
||
green; clippy and fmt clean. No behaviour change yet.
|
||
|
||
## B — Queue marks and the register (`cbd-tui`)
|
||
|
||
- [ ] **B1 — `impl MarkedPane for Queue`** with `markable` = always, and a
|
||
`visual: Option<usize>` field on `Queue`. *Verifies:* G12.
|
||
- [ ] **B2 — `update_queue` carries marks** through `carry_marks` instead of
|
||
rebuilding them as `false`: keep the previous path list and mark flags,
|
||
reconcile, apply. *Verifies:* G1, G2.
|
||
- [ ] **B3 — `Register::set`** (replace the `todo!()`) and an `App.register`
|
||
field. *Verifies:* the register suite (G6, G10).
|
||
- [ ] **B4 — `y` in both panes.** New `Action::LibraryYank` and
|
||
`Action::QueueYank`; each takes `selection()`, writes the register, and
|
||
clears the marks it consumed. *Verifies:* G5, G14, G15.
|
||
- [ ] **B5 — `d` in the queue deletes every marked row** (cursor row when
|
||
none), writing them to the register first, in one `RemoveTracks` call with
|
||
positions from the current list. Replaces the `FIXME`. *Verifies:* G1,
|
||
G13, G14, G15.
|
||
- [ ] **B6 — `c`/`C` fill the register** with the tracks they drop (`C`
|
||
everything, `c` everything but the current track). *Verifies:* G4.
|
||
- [ ] **B7 — `p`/`P` paste the register.** `Action::QueuePaste` /
|
||
`QueuePasteBefore` send `InsertTracks(register.paths(), pos)` with `pos` =
|
||
cursor + 1 for `p`, cursor for `P`; a no-op on an empty register; the
|
||
register survives. `QueueInsertHere`'s old cross-pane behaviour is gone.
|
||
*Verifies:* G7, G8, G9.
|
||
- [ ] **B8 — Queue visual mode in dispatch.** A `queue_move` wrapper
|
||
mirroring `library_move`, and the visual auto-leave guard generalized to
|
||
whichever pane is in visual mode with its own movement whitelist.
|
||
*Verifies:* G11.
|
||
- [ ] **B9 — Bindings + help.** Queue scope gains `s`, `v`, `V`, `y`, `P`;
|
||
library gains `y`; `p`'s description changes. The help modal derives from
|
||
`BINDINGS`, so it follows. *Verifies:* G19, G20.
|
||
- [ ] **B10 — Status feedback.** The pane title shows `— VISUAL` in the
|
||
queue as in the library, and a non-empty register is visible somewhere
|
||
(title or now-playing line) so paste is not blind. *Verifies:* G22 in
|
||
spirit; keeps G9's no-op explicable.
|
||
- [ ] **B11 — Dispatch tests** for the gates named above. *Verifies:* G1,
|
||
G4, G5, G7–G9, G13–G15.
|
||
- [ ] **B12 — Commit B** with the whole `cbd-tui` suite, clippy `-D
|
||
warnings`, and fmt clean (G24, G26).
|
||
|
||
## C — `cbd-web` parity and docs
|
||
|
||
- [ ] **C1 — `Register` + `carry_marks` in `cbd-web/src/state.rs`**, same
|
||
shape and same test cases as the TUI's. *Verifies:* G17, G18.
|
||
- [ ] **C2 — Library visual mode** (the piece deferred when `v`/`V` landed
|
||
in the TUI): `visual: Option<usize>` on `LibraryPane`, the same anchored
|
||
paint, `Action::LibraryVisualMode` on `v`/`V`, auto-leave on non-movement.
|
||
*Verifies:* G17.
|
||
- [ ] **C3 — Queue marks beside the signal.** The web queue owns no list, so
|
||
hold `marks: Vec<bool>` plus the path list they were taken against, and
|
||
reconcile on each `Queue` update. *Verifies:* G18.
|
||
- [ ] **C4 — Queue actions:** `QueueToggleMark`, `QueueVisualMode`,
|
||
`QueueYank`, `QueuePaste`, `QueuePasteBefore`, plus `d`/`c`/`C` writing the
|
||
register — same semantics as the TUI. *Verifies:* G17.
|
||
- [ ] **C5 — Keymap + `HELP` table** rows for all of the above, keeping the
|
||
lockstep test green; clickable equivalents where the web client has them.
|
||
*Verifies:* G19.
|
||
- [ ] **C6 — Verify the web half properly:** clippy for native **and**
|
||
`wasm32-unknown-unknown`, `cargo test -p cbd-web`, and a trunk bundle
|
||
build. *Verifies:* G26.
|
||
- [ ] **C7 — Docs.** `docs/src/clients/tui.md` (key table + a register
|
||
section), `docs/src/clients/web.md`, `docs/src/queue.md` (what the register
|
||
is and is not), and the README usage section. State plainly that `p`
|
||
changed meaning. *Verifies:* G21, G22, G23.
|
||
- [ ] **C8 — `plan/summary.md`** entry, then commit C.
|
||
|
||
## Deferred (recorded, not dropped)
|
||
|
||
- Named registers (`"a`) — `Register` is shaped for it; not built.
|
||
- A numbered/history register stack, and any cross-client or persistent
|
||
register.
|
||
- A per-entry queue id in the proto, which would make mark reconciliation
|
||
exact instead of a greedy path match.
|