Skip to content

feat(tui): modal keymap, full-text panel, outline and review mode - #6

Merged
AlexanderSlokov merged 3 commits into
developfrom
oxd-031/split-view
Sep 2, 2026
Merged

AlexanderSlokov merged 3 commits into
developfrom
oxd-031/split-view

Conversation

@AlexanderSlokov

Copy link
Copy Markdown
Owner

Phase 3's context features — the half of the design that gives back what RSVP takes away. Spec §0.2 admits the cost of removing the page: no sense of place, no backward glance. Each of these answers one of those.

Closes OXD-030, OXD-031, OXD-032, OXD-034, OXD-036.

What landed

  • Full-text panel beside the reader, auto-scrolling to follow the cursor with the current word highlighted from Token::byte_span. Shown whenever the window is ≥ 80 columns; --mode tui is now the default.
  • Outline sidebar (o) from Document::headings, with the active section marked and Enter to jump. Drawn as an overlay when there is no room for a third column.
  • Review Mode (v): the paragraph just read, verbatim and markup included, from Block::byte_span. Esc resumes at the same word.
  • Modal keymap (Tab, Esc): J/K scroll a focused panel instead of changing speed, resolving the conflict spec §7.1 flagged. The help popup and status hints read the same table, so neither can advertise a key that does something else where you are standing.
  • Golden-frame tests: every mode at 80x24, 200x50, 40x10, plus a style grid asserting the ORP stays bold and underlined and no colour reaches the terminal under NO_COLOR.

Decisions worth a second pair of eyes

Two things departed from the §5 mockup, argued in docs/decisions/split-view-layout.md and back-annotated into the spec:

  1. The status block spans the full width rather than sitting inside the left column. At 80 columns the left column is 38 wide inside its border; the generated key-hint line is 69 and the progress bar needs room beside it.
  2. Panel visibility is a width test, not size_class (which also weighed height). A 100x20 window was losing the panel over four missing rows; §3.4.4 only ever talks about columns.

The panel renders Document::source with markup visible, because that is what byte_span indexes. The mockup draws it that way too. Known limit by design: for Markdown escapes and entities pacing::word_span falls back to highlighting the whole fragment rather than one word — a coarse highlight beats a range that panics on slicing.

Checks

make check and cargo deny check are green locally; 260 tests pass (was 175). .gitattributes pins *.snap to LF so a Windows checkout cannot fail the golden frames spuriously — the OXD-036 criterion "runs in CI across all 3 OS platforms" is what this PR's own CI run verifies.

🤖 Generated with Claude Code

https://claude.ai/code/session_011e2oRctuPGDRf9pLs2xWgr

AlexanderSlokov and others added 3 commits September 2, 2026 15:25
The outline sidebar holds Headings, which carry a block_id, not a token
index. Give it a way to jump there without reaching into the token
stream, and report failure rather than moving somewhere arbitrary when a
block produced no tokens at all — tables and markup-only headings do not
appear in the stream.

Part of OXD-032.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011e2oRctuPGDRf9pLs2xWgr
The half of the design that gives back what RSVP takes away. Spec §0.2
admits the cost: no page, no sense of place, no backward glance. Each of
these answers one of those.

The panel renders Document::source rather than the stripped block text,
because Token::byte_span indexes the source. Rendering anything else
would need a second mapping that could disagree with the first, and a
highlight on the wrong word is worse than no panel. The wrap is cached
and redone only when the panel's inner width changes, so a 50 KB
document is not re-wrapped 25 times a second at 1500 WPM.

The keymap is modal because J/K cannot mean both "speed" and "scroll" at
once (§7.1). A binding now declares the modes it applies in, and the help
popup and status hints read the same table, so neither can advertise a
key that does something else where you are standing.

Two layout decisions departed from the §5 mockup: the status block spans
the full width, and panel visibility is a width test rather than a size
class that also weighed height. Both are argued in ADR 002.

Golden frames cover every mode at 80x24, 200x50 and 40x10, plus a style
grid — the §3.4.1 guarantees are about attributes, so an ORP that quietly
stopped being bold would pass a text-only snapshot.

Closes OXD-030, OXD-031, OXD-032, OXD-034, OXD-036

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011e2oRctuPGDRf9pLs2xWgr
Back-annotate spec §5 with the two layout changes, mark the finished
Phase 3 cards, and note in OXD-033 that everything but the <n>% jump
already shipped in v0.1.0 — its real remaining size is S, not M.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011e2oRctuPGDRf9pLs2xWgr
@AlexanderSlokov
AlexanderSlokov changed the base branch from main to develop September 2, 2026 08:35
@AlexanderSlokov
AlexanderSlokov merged commit fda9955 into develop Sep 2, 2026
9 checks passed
@AlexanderSlokov
AlexanderSlokov deleted the oxd-031/split-view branch September 2, 2026 08:56
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