mirror of
https://github.com/block/buzz.git
synced 2026-08-18 06:50:31 +02:00
The grid retains 10k lines and nothing could move the viewport off the
live edge: the substrate accumulated trackpad deltas into whole cells
and handed them to `onScroll={() => {}}`, and there was no command on
the other side to call.
Three layers, one new idea each.
`buzz-terminal` gains `scroll`/`scroll_to_bottom`, both returning
whether the viewport *moved*. Capture becomes offset-aware by one
subtraction -- screen row r reads grid line r - display_offset, the
identity at the live edge -- and the cursor plane converts from the
grid's active-area row to the screen row the renderer paints, reporting
itself invisible once scrolling pushes it off the bottom rather than
painting a caret on an unrelated line of history.
`terminal_scroll` is the only place the two sign conventions meet. The
wire carries the DOM's sign and the negation lives there, because the
spec has to be written against `deltaY` rather than against finger
direction: macOS natural scrolling flips what the OS reports, so "swipe
up goes back" is correct for one preference setting and backwards for
the other. Against `deltaY` the rule is stable and matches the page
hosting the terminal -- the gesture that scrolls a page toward the top
of the document scrolls the terminal into history.
Republication goes through `snapshot`, reusing the resize path's
property that it does not consume damage. That is the whole defence
against the silent case: the renderer's per-row hashes describe the
screen it last saw, scrolling changes every row without changing a
cell, and a scroll that ate the full-damage flag would leave those
hashes free to suppress a row that really did change.
Snap-to-bottom lives in `terminal_input` rather than the renderer.
Output alone never returns the viewport -- the grid deliberately pins a
scrolled-back reader and piles new lines above -- so it has to be
explicit, and putting it at the PTY write covers pasted text and
encoded keys for free.
Scope is viewport scrolling: no selection, no search.
Registering the command puts `desktop/src-tauri/src/lib.rs` one line over
the size ratchet, which sits exactly at its 1000-line limit. The line
comes back from deleting `#[cfg(not(buzz_updater_enabled))] let builder =
builder;` -- an identity rebinding that does nothing on either arm of the
cfg, verified by compiling both with a control that proves the enabled
arm is really being exercised -- rather than from deleting blank lines.
Co-authored-by: tlongwell-block <109685178+tlongwell-block@users.noreply.github.com>
Signed-off-by: tlongwell-block <109685178+tlongwell-block@users.noreply.github.com>