grid: stop marking the cursor row on cursor-only moves #463
No reviewers
Labels
No labels
priority/P0
priority/P1
priority/P2
release/v0.1.0
status/blocked
status/planned
type/bug
type/design
type/test-gap
type/tracker
No milestone
No project
No assignees
1 participant
Due date
No due date set.
Dependencies
No dependencies set
Reference
natsukium/felis!463
Loading…
Reference in a new issue
No description provided.
Delete branch "cursor-454"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
A move of the cursor alone no longer marks the cursor's row dirty. Each of those marks cost a full row on the wire. A program that prints a line per frame now ships 2 rows per cycle instead of 3. The wire format is unchanged.
Why
docs/explanation/rendering/damage-tracking.md"Correctness" (and REQ-1203) requires a cursor-only move to leave damage empty: the cursor ships asCursorStateand the client draws it as an overlay. The grid still marked the cursor row on CR, on LF / RI when they don't scroll, and on BS, HT, CUU/CUD/CUF/CUB, CUP, CHA, VPA, CHT, CBT, DECRC, DECSLRM and DECOM. Since #455, a scroll moves each dirty mark along with its row. The mark a\rleaves before each line feed therefore turned into one extra row shipped every frame.What changed
?41(MoreFix). That handler sets a row's soft-wrap bit without writing a cell, and the soft-wrap bit is part of the row payload.compose_diffscompares the cursor with what each subscriber last received on every compose, whether or not anything is marked.set_cursor_statemarks nothing.RowDelta/Hyperlink, and a cursor move changes neither.damage_correctness.rsnow requires damage to be empty after each cursor-only handler. It also runs a property over random motion sequences on a non-empty screen, which includes DECSTBM, DECSLRM, DECOM and the reverse-wrap modes. A new case checks that a CRLF at the bottom leaves only the row it vacated marked. All three tests fail onmain.every_mirror_ends_each_compose_holding_the_grids_cellsnow also feeds cursor motion,?41/?45/?1045and?25. On top of the cells, it compares each shadow's cursor (row, col, visible) and soft-wrap bits with the grid's. If the MoreFix mark is removed, the property fails on the soft-wrap bit; the committed regression seed is that case. It passes at 30 000 cases in release.synchronized_output_holds_writes_into_one_damage_burstused to rely on a bare\r\nmarking row 1. It now writes to that row.Measurements
I used the method from #455: a temporary counter in the client that records, for each pull cycle, the
RowDeltarows and payload bytes and theScrolleddirectives it receives. Setup: release build, 212x93 window. This host has no monitor connected, so the window ran under a headless sway at 60 Hz. Each workload ran 3 times per build; the table shows medians of the per-cycle values. The one-minute load average was 3.7 to 14.8 because CI jobs were running; the row counts do not depend on load.Scrolled/ cycleprintf "\n...")vim -u NONE,^Eevery 30 msless,jevery 30 mslessstays at 3, contrary to the issue's prediction. Its bytes for ajare\r\x1b[K<new line>\x1b[m\r\n:\x1b[K: it writes the new line on the bottom row before its CRLF. The row above the prompt is therefore really written that cycle, and no cursor mark was involved. The pager workload is the case the issue measured, and it drops to 2.Review
Independent review with
pi(sol) overorigin/main...HEAD. Round 1: PASS, no findings.Closes #454