Skip to content

v0.2.0

Choose a tag to compare

@github-actions github-actions released this 10 Aug 22:25
· 226 commits to main since this release
b2a5f53

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.