v0.7.0
Added
-
TerminalBuilder::envssets several child environment variables from an
iterator of key-value pairs. Values keep their iteration and builder-call
order, and remain explicit whenenv_cleardisables inherited variables. -
Screen::linksreports theOSC 8hyperlinks an application emitted.
A hyperlink changes no cell — its label renders exactly as unlinked text
would — so the URL existed nowhere a test could reach, and an assertion
that a TUI linked an issue, a file or a doc page passed identically
against an application that emitted no link at all, or linked the wrong
target. Captured rather than answered, on the same grounds as the
OSC 52clipboard: the only evidence otherwise available is the
application's own visible output, which proves the code path ran and
nothing about where it points.Each span reports its
uri, itsid(spans sharing one are one logical
link), thelabelit wrapped, and whether the application everclosed
it — an unterminated link is a real defect, because in a real terminal
every character written afterwards joins it. Two bounds keep the capture
honest: the log holds the most recent 64 spans and evicts oldest-first, so
a TUI that redraws its links every frame still reports the current
frame's; and a label past the capture bound is reported as unknown
rather than as a prefix, since a prefix of the wrong length is a wrong
answer. -
Screen::cursor_shapeandScreen::cursor_blinkreportDECSCUSR.
A screen where the application asked for a bar and one where it never
asked used to be the sameScreen. The shape is load-bearing behaviour
rather than decoration — a modal editor switches to a bar for insert and
back to a block for normal, and "the mode indicator says INSERT" and "the
terminal was actually put into insert" are different claims. It also makes
the restore assertable, which is the half that ships broken: a program
that changes the cursor and never changes it back leaves the user's
terminal wrong after exit, the same class of defectalternate_screen()
already catches.Shape and blink are one
DECSCUSRparameter but two facts, so they are
reported apart.CursorShape::Default— the application never sent the
escape — is a third state and is reported as itself rather than folded
intoBlock. -
Key::Insert, encodingESC [ 2 ~, and chording like its
neighbours (Key::Insert.shift()→ESC [ 2 ; 2 ~). It was the2
missing from a navigation run that already had3,5and6, so an
application binding Insert could not be tested without hand-writing the
escape.
Changed
-
KeyandSignalare now#[non_exhaustive]. This is breaking for
downstream code thatmatches either without a wildcard arm; adding a
_ => …fixes it, and equality and construction are unaffected.Worth doing now rather than later. Adding a variant to an exhaustive
public enum is itself a breaking change, so every future key and every
future signal would have cost a version of its own —Keyhas no F13+ and
no keypad, andSignalcarries seven of POSIX's thirty, missing
SIGWINCHandSIGCONT, which are exactly what a terminal application
reacts to. Both types are constructed far more often than matched
(t.send(Key::Enter),t.signal(Signal::Int)), so the cost falls almost
entirely on the crate and not on its users.#[non_exhaustive]is
breaking to add, which makes the cheapest moment the earliest one.Coloris deliberately left exhaustive. Default, palette index and 24-bit
RGB is the whole terminal colour model — there is no fourth variant
waiting — andColoris the one enum here that downstream code really
does match on.
Security
-
A decoded image can no longer choose how much memory it allocates.
GraphicsPayload::decodetrusted four sizes that the program under test
writes: kitty'ss=/v=, sixel's raster attributes, its!nrepeat count
and its#ncolour-register index. A compressed kitty payload was also
inflated with no output limit, and zlib reaches about 1000:1. Each turned a
handful of bytes into a request for tens of gigabytes —!4294967295~is
twelve bytes; a declared65535x65535is about twenty and asks for 17 GB
before the pixel data is touched at all.Decoding is now bounded: no image above 4096x4096 (far beyond what a
terminal can place, and 64 MiB of RGBA once built), sixel colour registers
capped at 65536, and a compressed payload inflated only as far as its
declared size needs. Refusals are a newDecodeError::TooLargerather than
a silent clamp —DecodeErroris#[non_exhaustive], so matching on it
already required a wildcard.Present in every release before this one. It sits behind the off-by-default
decodefeature and is reached only when a test callsdecode(), so a
suite that merely counts images was never exposed.SECURITY.mdnow
enumerates these bounds with the rest.
Fixed
-
A hard reset (
RIS,ESC c) returns the cursor shape to the terminal's
default and closes any openOSC 8span.printf '\033c'is one of the
ways a program hands the terminal back on exit, so reporting the last
DECSCUSRafter one claimed a shape the terminal no longer held — and it
did so in exactly the casecursor_shapeexists to check. The window
title, the clipboard, the bell count and the link log are deliberately
left alone: the title is a window propertyRISdoes not restore in
xterm, and the rest are records of what the application emitted rather
than state the terminal still holds. -
The crate's doctests build with default features disabled. The bundled
snapshot macro example is compiled only when itsinstafeature exists,
and CI now runscargo test --workspace --no-default-featuresso this
supported configuration cannot silently rot again.