Skip to content

0.0.19 cohort: layout, editing, isolation and docs you can see

Published on 2026-10-19, with rs-rich 0.0.7 on PyPI. See Publication.

0.0.19 is stage 1 of the plan to 1.0.0, planned in detail in the 0.0.19 plan:

  • Flex alignment and wrapping. Rows and columns align their children across the axis (align_items, align_self), share the room they leave along it (justify), and wrap onto new lines (wrap, align_content), as CSS flexbox does; the stylesheet takes CSS's names. A container that sets none of them lays out as before.
  • A text area. text_area(signal): a multi-line editor with syntax highlighting, line numbers, soft wrap or sideways scrolling, selection with the keyboard and the mouse, undo and redo, and the clipboard. It draws only the lines in view, so a 100,000-line file stays quick. Its editing is rich_interact::edit::Buffer, which rs-rich-interact's own TextArea now shares.
  • One process per browser session. rs-rich-web runs each tab's app in a process of its own by default, so a crash, a hang or a runaway allocation ends that tab alone. The server proves itself to each process and the process to the server; each process can be capped in memory and CPU time on Unix; a killed server takes its sessions, and what they started, with it (a process group on Unix, a job object on Windows). Isolation::Threads keeps 0.0.18's behaviour.
  • A Surface for positioned drawing. rs-rich-ext's Surface renders any rich renderable into rectangles of the terminal, full screen or inline, and writes only the cells that changed, as ratatui's Frame does, without a framework. intuiTUIve's screen now is that surface.
  • Responsive layout and an error state. hide_below(80) and @media (max-width: 79) hide or reflow panes on a narrow terminal; error_when sets :error, which themes and stylesheets style and assistive technology hears as invalid.
  • Snapshot tests for apps. assert_screen! compares an app's screen with a readable text file, shows a diff when it differs, and rewrites it with UPDATE_SNAPSHOTS=1.
  • Wide and long tables. intuiTUIve tables and TableSelect scroll across with scroll_x(), keep frozen columns in place, and keep the header over its columns; the pager and rich pager keep a table's header on top while its rows scroll.
  • Reordering, dates and times. Reorder and .reorderable() put a list in order with the keyboard or a drag; date, time and date-and-time pickers with a range, in rs-rich-interact, intuiTUIve and rich date.
  • An inspector you can work with. Shift+F12 gives intuiTUIve's inspector the keys: pick a node in the tree or with the pointer and see its bounds, constraints and states, per-node draw counts and times, and a trace of input, focus, signal writes, timers and tasks. Nothing is measured while it is closed.
  • What ratatui draws, in intuiTUIve. Panel titles on both edges, every border kind and shadows, layers, collapsed borders, effects that draw over children, ratio sizes and layout by hand; list and table options, scrollbars on every scrolling widget, single-line and number inputs, modal shadows, printing above an inline app; and in rs-rich-ext's charts, gauges, taller sparklines, grouped bars, area charts, a world map, more canvas markers and the Tailwind and Material palettes. ratatui's demo and demo2 are rebuilt on intuiTUIve as examples, with the mouse, help and a palette added. A comparison with ratatui marks what is equal, partial, missing or different by design.
  • rich log that keeps up. --level warn+ and --where 'latency_ms>500' filter while records stream; --follow tails a file through rotation; repeats fold, records group by trace, and a summary says which groups failed. Plain-text lines (logfmt, LEVEL message, access logs) are read too, and -i opens a live view.
  • rich deps as a CI gate. --sizes reports each crate's artifact size; --baseline compares build times or sizes with a saved report and fails on a regression; --policy checks licences against an allow and deny list (or cargo-deny's), flags conflicts with your crate's licence, and reads SPDX and CycloneDX SBOMs.
  • Charts you can hear. Every chart describes itself to a screen reader; Distribution draws quantiles as a strip, SmallMultiples a grid of charts on one scale; VirtualTable windows thousands of columns.
  • Nested JSON Lines and style rules. rich profile profiles JSON Lines path by path with the mix of types per path, and --style-rule 'latency>500:bold red' styles any data table by value.
  • Micro assets over two rows. 2×2 icons and 3×2 animations, with their rows reserved in text, tables and panels.
  • Share with care. --export-png saves any output as an image, and --redact-preview shows every secret --redact would mask, and what would replace it, before anything is written.
  • Review and jump. rich approve walks a queue of items to approve, reject or skip, with reasons; rich jump finds a file, heading, symbol or command from one fuzzy box. Both are components in rs-rich-interact.
  • Banners and shell integration. rich banner draws FIGlet text in gradients; GIFs take a speed, a frame rate and limits; rich shell init adds completions, prompt marks and a status line to bash, zsh, fish and PowerShell.
  • Org, AsciiDoc and man pages. rich notes.org, rich guide.adoc and rich greet.1 render beside Markdown and reStructuredText, found by the extension (and the content, for a man page's section number), in the look of core's Markdown. rich_ext::document holds the formats in one registry that a plugin can join.
  • Docs you can see. Every Rust guide page shows what its example prints, the Python site's pages show theirs, and everything 0.0.18 and 0.0.19 added has a recording.

A default build of rs-rich is unchanged, still 0.0.9, and still renders exactly like upstream rich 15.0.0.

Independent package versions

Package Version Release role
rs-rich-ext 0.0.16 Surface; document (Org, AsciiDoc, man pages); gauges, grouped bars, area charts, the map, palettes; log_stream; deps::{sizes, compare, policy, sbom}
rs-rich-interact 0.0.7 edit::Buffer, wide tables, sticky headers, Reorder, date and time pickers, LogView, ApprovalQueue, Jump; requires ext 0.0.16
rs-rich-intuituive 0.0.4 Alignment and wrapping, the text area, the surface, responsive layout, :error, snapshot tests, wide tables, reordering, date and time pickers, the inspector's selection, timings and trace; titles, borders, layers, effects, ratio sizes, list and table options, scrollbars and inputs after ratatui
rs-rich-web 0.0.2 One process per session (job objects on Windows)
rs-rich-embed 0.0.2 Manifest only: requires intuituive 0.0.4
rs-rich-micro 0.0.5 Two-row assets; requires ext 0.0.16
rs-rich-record 0.0.7 PNG rendering of any output; requires ext 0.0.16
rs-rich-data 0.0.3 Nested JSON Lines profiles; requires ext 0.0.16
rs-rich-ratatui 0.0.4 Manifest only: requires interact 0.0.7
rs-rich-cli 0.0.19 rich date, rich pager --sticky, --org, --asciidoc, --man, rich log's filters, follow mode and groups, rich deps --sizes, --baseline and --policy, rich approve, rich jump, rich banner, rich shell, --export-png, --redact-preview; requires the versions above

rs-rich 0.0.9, rs-rich-macros 0.0.3, rs-rich-plugin-api 0.0.3, rs-rich-art 0.0.12, rs-rich-diagram 0.0.2, rs-rich-mermaid 0.0.5 and rs-rich-lumis 0.0.3 do not change.

The Python package, rs-rich 0.0.7 on PyPI, carries tui.text_area, alignment on Node, rs_rich.ext.surface, the server's isolation options, and the additions: hide_below, error_when, viewport() and the snapshot helpers in rs_rich.tui; table scroll_x and freeze_columns; the pager's sticky_header; Reorder, DatePicker, TimePicker and DateTimePicker in rs_rich.interact; and reorderable, time_picker and datetime_picker on intuiTUIve nodes; rs_rich.ext.document for Org, AsciiDoc and man pages; Border, Shadow, layers, effect, input, number_input, Scrollbar, ModalOptions and the new Node builders in rs_rich.tui; rs_rich.ext.log_stream and rs_rich.interact.LogView; Distribution, DistributionSet and SmallMultiples in rs_rich.chart; StyleRule and StyleRules in rs_rich.ext.table; nested profiles in rs_rich.data; two-row sizes in rs_rich.micro; and FillGauge, LineGauge, BarGroup and the new sparkline and bar options in rs_rich.chart.

Migration

  • rs-rich-web serves each tab from a process of its own. An app needs no change, but main now runs again in each session's process, up to the same serve (or Server::bind) call. A program that cannot start itself again, and tests (a test binary started again would run its tests again), use .isolation(Isolation::Threads). A session_command must be the program, or exec it. See One process per session.
  • rich_intuituive::screen::{Screen, Painter, Rect, Cell} are re-exports of rich_ext::surface's types, under the same names. Painter::repaint now writes the cells it is given whether they changed or not.
  • Isolation is #[non_exhaustive]: a match on it needs a _ arm.
  • rich pager keeps a table's header on top when its input starts with a table; --sticky 0 gives 0.0.18's paging.
  • intuiTUIve's Date lives in rich_interact::datetime now, and is re-exported where it was, under the same name.
  • On Windows, a session's process that cannot be put in a job object (a server inside a job that forbids nesting) does not start, and the page says why.
  • intuiTUIve's CalendarOptions is Clone, no longer Copy, since it can hold a function that styles dates; clone it where it was copied.
  • intuiTUIve's Size is #[non_exhaustive] and has Size::Ratio: a match on it needs a _ arm.
  • A panel title too long for its panel is cut with … now, where it was cut without one.
  • intuiTUIve's Column, TableOptions and FrameStats have new public fields: code that builds them field by field, rather than with their constructors, needs the new ones.
  • In intuiTUIve's text mode every scrollbar is blank, a scroll view's default one included.
  • rich profile on JSON Lines profiles nested paths by default, with a "N records, M paths" heading; a malformed line is counted and noted, and exits 0 where it exited 4. --flat gives 0.0.18's profile.
  • A vertical BarChart with an explicit thickness or gap keeps it and leaves off the bars that do not fit, as ratatui does, where it used to squeeze them.
  • A Sparkline or plot Canvas without its own height fills the height it is given (a fixed-height Panel, a Layout region, an intuiTUIve node), as ratatui's do, where it drew at its natural height. Set .rows(n) or .height(n) to keep a fixed one.
  • --watch-interval takes at most 86400 seconds; a larger value is a usage error (exit 2).
  • banner, shell, approve and jump are subcommands now: a file of one of those names needs a path, such as rich ./banner.
  • rich log reads a line that is not JSON (logfmt, LEVEL message, an access log, or plain text) where it used to fail on it.

Release test

  • Each workstream PR's CI passed: fmt, clippy, tests on Linux, macOS and Windows, the feature matrix, MSRV, golden parity, the tapes, the docs site, and the intuiTUIve-against-ratatui benchmark gate (#744–#749).
  • Three independent audits of the 0.0.19 delta (intuiTUIve and the surface; process isolation; Python, docs and packaging) found 24 distinct defects, each reproduced first; all are fixed, each with a regression test, most of them the auditor's own reproduction (see the CHANGELOG, "0.0.19 release test", and "One process per browser session"):
  • Process isolation (two of them security): a session's process whose server died served whoever took over its port; idle or trickling connections to that port held up a session and stopping the server; a startup could outrun its memory limit on one CPU; a killed server left what a session started running; RS_RICH_WEB_SESSION broke any program the app ran that served too.
  • The surface: a link URL could drive the terminal; drawing over half of a wide character put the screen model out of step with the terminal; an inline region taller than the terminal lost rows.
  • The edit buffer and the text area: moving through a long line, and a character limit, were quadratic or worse (23 s, 46 s and 776 ms a key); the caret could stop inside a grapheme cluster; a long wrapped line was re-wrapped once per row of the view; the wheel jumped back in a long last line.
  • Wrapping layout: percentages and flexible items in wrapped lines did not lay out as the docs (and CSS) say; align_self was lost under .padding() and .panel(); the spacing arithmetic could overflow. A Codex review of the fix then caught flexible items being shared out from zero rather than from their basis (#749).
  • Python: REPLs other than plain python and Jupyter kernels got processes and every tab failed; a script that changed directory could not be run again; a huge session_cpu panicked; a Surface lost what a failed write did not send, and one left open at exit did not give the terminal back.
  • A second round of two audits, over workstreams 7 to 10, found 22 more defects, none high, each reproduced first and fixed with a regression test (see the CHANGELOG, "A second round of audits"):
  • intuiTUIve: a node hidden by hide_below or @media was still drawn inside a split, a scroll or a switch; typing an hour against a range's start lost the minutes; an empty range said nothing.
  • Reorder and the pickers: the wheel while an item was grabbed, and clicks after a scroll, moved the wrong item; Tab could not leave a time picker in a form; without seconds, a limit with seconds refused what was shown; a default outside the range was answered without a terminal.
  • Sticky headers: sticky lines taller than the page hid lines for good; a header-less table with row lines had its first row pinned.
  • Windows: a program a session ran that served an app too was taken for a session; two CI steps ignored all but their last command.
  • scripts/validate_release.py --tag rs-rich-cli-v0.0.19 passed on the release head (fmt, clippy with and without features, 3,899 tests, the runtime plugin loaders' tests, the release tooling's tests, the version and CLI reference checks, staged packages, the release plan).
  • Every tape (41) matches its recording, capture_guide.py --check and capture_python_docs.py --check pass, and the golden fixtures are unchanged: core does not change in this cohort.
  • The browser screenshots on the web page were regenerated for this release with scripts/capture_web.mjs, as decided (they are not checked in CI).

Not yet done, and by whom

  • A real-terminal pass of the text area (selection, the clipboard, bracketed paste) and the inline surface in kitty, WezTerm, iTerm2 and Windows Terminal: the maintainer's, before tagging. CI and the PTY tests cover the bytes, not what a person sees.
  • The termion and termwiz backends in real terminals, carried over from 0.0.18: the mouse, resizes and Ctrl+Z, and termwiz in Windows Terminal (mouse and resizes; Windows has no Ctrl+Z). It cannot be done in CI: the maintainer's. CI now builds termwiz on Windows and runs the headless suites there (#721); the PTY suites cover Linux and macOS.

Known limits

  • The Chrome web view's DevTools port can still be reached by other local users while the view is open. The pipe that replaces it moved to 0.0.20: Windows cannot pass Chrome the pipe's handles without unsafe, and it ships on every platform or none (see workstream 5).
  • A process a session starts that leaves its process group (setsid, a daemon) is not ended with the session.
  • On Windows a session's memory and CPU limits are not applied: no safe API sets a job object's limits. What a program starts before it reaches serve, in the moment before the server puts it in its job, is not ended with the session.
  • The date pickers' "today" is the UTC day unless the caller gives one (today(..), --value): finding the local zone safely needs a dependency this release does not take.
  • .reorderable() works on an intuiTUIve list, not yet on a virtual list, a table or a list inside .panel().
  • On macOS a session's memory limit is not applied (the system refuses one); its CPU limit is.

Publication

Tagged crate by crate, each tag starting its own release run (none is a new crate, so each published through Trusted Publishing):

  1. From 22da468: rs-rich-ext-v0.0.16, rs-rich-micro-v0.0.5, rs-rich-record-v0.0.7 and rs-rich-interact-v0.0.7.
  2. From 2fc9772: rs-rich-ratatui-v0.0.4, rs-rich-intuituive-v0.0.4, rs-rich-embed-v0.0.2, rs-rich-web-v0.0.2, rs-rich-data-v0.0.3 and rs-rich-cli-v0.0.19; then python-v0.0.7 through pypi-release.yml.

The cohort spans two commits, and main changed some of its crates under their published numbers afterwards; the 0.0.20 cohort moves those to new numbers and is published from one commit by one release run (see the 0.0.20 notes).