Closes the second half of Phase A's deferred finding A8. The producer
now emits DecorationKind::CurrentLine derived from the active window's
cursor; pmacs-gpu paints it as a very subtle blue-grey wash under the
line carrying the cursor.
## Q-stance implementation status
- **Q#1 stance (α) — producer-side emission**: `scoped_decorations`
reads `core.active_window_for(self.frontend_id).cursor`, derives the
enclosing line via a new `current_line_range` helper, and pushes a
`Decoration { kind: CurrentLine, range }` clipped to the viewport.
Same per-frontend access path used for Selection (line 378).
- **Q#3 stance (β) — per-line cadence**: implementation-revealed
simplification. The framing doc proposed a `last_cursor_line` cache
on SemanticRenderState; in practice the existing M11.4 diff
(`changed_intervals`) already gives this for free. A same-line
cursor move produces a byte-identical decoration Vec, so
`changed_intervals` returns empty and nothing ships. A line change
produces a different range and re-emission fires. No extra state
needed. Recorded as a small finding under rule (iii); the stance
holds, only the implementation tightens.
- **Q#2 (render order)** continues to apply from 9.1 — quad
backgrounds first, text second, minimap last.
- **Q#4 (search backgrounds)** still deferred awaiting search.
## Producer
- New `current_line_range(line_starts, source_len, cursor) -> (u64,
u64)` helper at `src/semantic_render.rs`: binary-searches line_starts
for the largest `start <= cursor`, returns the half-open byte range
`(line_start, next_line_start_or_source_len)`. Clamps to source_len
so a cursor at or past EOF resolves to the last line cleanly.
- `scoped_decorations` restructured: the Selection branch and the new
CurrentLine branch share the `win.buffer_id == vp.buffer_id` gate so
per-window state never leaks into a viewport projecting a different
buffer (the `decorations_use_vp_buffer_not_active_buffer` invariant).
- Four new tests:
- `current_line_range_finds_enclosing_line` — unit test covering
line-zero, mid-line, start-of-line, last-line, and past-EOF.
- `current_line_projects_as_a_decoration_for_cursor_on_seed` —
cursor at byte 0 of "abc\\nde" emits CurrentLine for [0, 4).
- `current_line_skipped_when_active_window_is_a_different_buffer` —
multi-frontend invariant: projecting a non-active buffer does not
emit CurrentLine.
- `same_line_cursor_motion_does_not_re_emit_decorations` — Q#3
cadence: horizontal motion within a line is silent; crossing `\n`
re-emits.
- Existing test `diagnostics_project_with_line_col_to_byte_and_severity`
updated: the seeded "abc\\nde" buffer now produces both a
DiagnosticWarning and a CurrentLine. The test now finds the warning
by `kind` and asserts its byte range rather than asserting a total
count of 1.
## Consumer
- `decoration_kind_to_bg_color` in pmacs-gpu/src/main.rs adds the
CurrentLine arm: `[0.55, 0.60, 0.75, 0.08]` — a very subtle blue-grey
with low alpha. CurrentLine is always on, so it wants to be visually
quietest of the four background kinds; just enough tint to track
cursor line, not enough to compete with Selection or syntax color.
- `bg_color_helper_covers_selection_and_returns_none_for_unrendered_kinds`
renamed to `bg_color_helper_covers_selection_and_current_line` and
updated to assert CurrentLine now returns Some.
- `fg_and_bg_helpers_are_disjoint_total_cover` updated: CurrentLine is
no longer in the "deferred neither yet" set, only the search pair.
## Bet status
- **Bet #2 (overlap composition between Selection and CurrentLine)**:
exercised. CurrentLine has alpha 0.08, Selection 0.30. When both
cover the same bytes (cursor on a selected line), they alpha-blend
in draw order. Composition is left to the M11.4 dirty-merge ordering
(decorations sorted by range.start): CurrentLine paints first
(covers the whole line, lower start), Selection paints on top. The
resulting visual is selection-blue with a slight CurrentLine tint
visible at the line's non-selected ends. Honest composition rule
if surfaced as wrong: refine.
- **Bet #3 (cadence)**: predicted producer-side `last_cursor_line`
cache; implementation revealed the M11.4 diff already throttles.
Score: predicted category surfaced (true positive on the cadence
concern), but the *implementation* category for the resolution did
not match. Recorded as rule-(iii) small finding.
## Gates (all green)
- `cargo fmt --all -- --check`
- `cargo clippy --all-targets --workspace -- -D warnings`
- `cargo clippy --all-targets --workspace --features crdt -- -D warnings`
- pmacs lib + pmacs-protocol: **1329 + 11 = 1340** (+4 new producer
tests)
- pmacs-gpu unit: **13** (unchanged count; one test renamed +
re-scoped)
- m4_acceptance: **88**, m11_5_semantic_acceptance (--features crdt):
**2**
## Manual validation walkthrough
Same daemon + TUI attach + pmacs-gpu attach shape. In the GPU window:
- Verify a subtle blue-grey wash appears under the cursor's line.
- Move the cursor up/down — the wash tracks the new line.
- Move the cursor left/right within a line — visible behavior should
be identical (Q#3 cadence: no re-render needed).
- Select text crossing the current line — Selection paints over
CurrentLine; both alpha-blends visible at the line's non-selected
edges.
- Resize the window — both backgrounds reshape correctly.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>