You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This commit was created on GitHub.com and signed with GitHub’s verified signature.
Added
The three rules for race-free waits — one predicate, wait on the last
thing painted, settle before whole-screen snapshots — and the resize stale-frame trap are now documented where you'll meet them: on wait_until and resize in the rustdoc, and in docs/DESIGN.md §2
with the first real user's before/after failures.
Process ergonomics: TerminalBuilder::current_dir(dir) runs the child
in a chosen working directory (no more cd … && … through a shell); Terminal::pid() exposes the child's process id; Terminal::signal(Signal::Term) (Unix) delivers real signals so
graceful-shutdown paths are testable — with a guard that refuses to
signal an already-reaped pid, which the OS may have reused; and wait_until_for(pred, timeout) gives the one known-slow wait its own
deadline instead of dragging the builder default up for every wait.
Three Screen query helpers, each earned by a documented pain in the
first real user's test suite: rect_text(cols, rows) — the text
inside a rectangle (any range expression, clamped to the screen), for
asserting on one pane of a split layout; find_by(|cell| …) — the
first cell matching a predicate, for "where did the highlight go";
and find now locates multi-row needles (find("one\ntwo"))
with exactly the matching semantics contains always had for them.
Out-of-band terminal state is readable from every Screen snapshot: title() (tracked from OSC 0/OSC 2 by termlens itself — the
emulator backend doesn't need to support it), alternate_screen(), bracketed_paste(), application_cursor(), and mouse_mode() (the
new public MouseMode enum, reporting the exact tracking mode the
application enabled). State that previously could only be inferred
from grid contents is now a plain assertion: wait_until(|s| s.alternate_screen()). None of it appears in the
snapshot text format — existing snapshot files stay valid.
Cursor keys are mode-aware: while the application has DECCKM
(application cursor mode) set, send(Key::Up) emits the ESC O A
form a real terminal would — the emulator knows the mode. Key::encode
still documents the default-mode bytes, and the Esc-then-key wire
ambiguity (identical to an Alt chord) is now documented on Key::Esc
with the working idiom.
Terminal::paste(text): pastes the way a terminal pastes — wrapped in
bracketed-paste markers when the application enabled mode 2004 (one Paste event, not a burst of key presses), plain bytes when it
didn't.
Modifier chords over special keys: Key::Right.ctrl(), Key::Up.shift(), Key::F(5).ctrl().shift() — the xterm
CSI-modifier encodings, chainable, accepted by the same Terminal::send. Character chords stay Key::Ctrl(c) / Key::Alt(c)
(the builder methods say so loudly if you mix them up).
Terminal::click(col, row) and Terminal::scroll(col, row, Scroll):
typed mouse input, encoded exactly as the tracking mode and encoding the application enabled (SGR 1006 or the legacy byte form), with a
press-only form for X10 mode. Clicking while the app never enabled
mouse tracking is a typed Error::Input instead of bytes the app
would misparse.
Screen::with_styles(): the plain snapshot rendering followed by a
compact styles: block (run-length spans per row, format specified in docs/DESIGN.md §3) — a highlight moving to another row or a color
changing is now a visible snapshot diff. Plain snapshots stay
text-only; this is the opt-in.
termlens now answers terminal queries (on by default): DSR cursor
position — exact as of the query byte — operating status, DA1/DA2
device attributes, CSI 18 t text-area size, and OSC 10/11 color
queries (TerminalBuilder::background_rgb configures the reported
background). Capability-probing applications run instead of hanging.
Recognized-but-unanswerable questions (XTGETTCAP, kitty CSI ? u,
pixel-size reports, …) are named inside the next wait timeout error,
turning a silent hang into a diagnosis; answer_queries(false) mutes
the responder while keeping the diagnosis.
Terminal::wait_frame(pred): evaluates the predicate only on complete
frames for applications that bracket repaints in DEC 2026 synchronized
updates — a torn, half-painted repaint is never observable. Apps that
don't emit synchronized output get a timeout error that says so and
points at wait_until.
Changed
wait_idle no longer resolves while a synchronized update is open: a
begun-but-unfinished repaint is mid-update by definition.