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 isrich_interact::edit::Buffer, which rs-rich-interact's ownTextAreanow 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::Threadskeeps 0.0.18's behaviour. - A
Surfacefor positioned drawing. rs-rich-ext'sSurfacerenders any rich renderable into rectangles of the terminal, full screen or inline, and writes only the cells that changed, as ratatui'sFramedoes, 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_whensets: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 withUPDATE_SNAPSHOTS=1. - Wide and long tables. intuiTUIve tables and
TableSelectscroll across withscroll_x(), keep frozen columns in place, and keep the header over its columns; the pager andrich pagerkeep a table's header on top while its rows scroll. - Reordering, dates and times.
Reorderand.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 andrich 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
demoanddemo2are 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 logthat keeps up.--level warn+and--where 'latency_ms>500'filter while records stream;--followtails 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-iopens a live view.rich depsas a CI gate.--sizesreports each crate's artifact size;--baselinecompares build times or sizes with a saved report and fails on a regression;--policychecks 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;
Distributiondraws quantiles as a strip,SmallMultiplesa grid of charts on one scale;VirtualTablewindows thousands of columns. - Nested JSON Lines and style rules.
rich profileprofiles 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-pngsaves any output as an image, and--redact-previewshows every secret--redactwould mask, and what would replace it, before anything is written. - Review and jump.
rich approvewalks a queue of items to approve, reject or skip, with reasons;rich jumpfinds a file, heading, symbol or command from one fuzzy box. Both are components in rs-rich-interact. - Banners and shell integration.
rich bannerdraws FIGlet text in gradients; GIFs take a speed, a frame rate and limits;rich shell initadds completions, prompt marks and a status line to bash, zsh, fish and PowerShell. - Org, AsciiDoc and man pages.
rich notes.org,rich guide.adocandrich greet.1render beside Markdown and reStructuredText, found by the extension (and the content, for a man page's section number), in the look of core'sMarkdown.rich_ext::documentholds 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
mainnow runs again in each session's process, up to the sameserve(orServer::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). Asession_commandmust be the program, orexecit. See One process per session. rich_intuituive::screen::{Screen, Painter, Rect, Cell}are re-exports ofrich_ext::surface's types, under the same names.Painter::repaintnow writes the cells it is given whether they changed or not.Isolationis#[non_exhaustive]: amatchon it needs a_arm.rich pagerkeeps a table's header on top when its input starts with a table;--sticky 0gives 0.0.18's paging.- intuiTUIve's
Datelives inrich_interact::datetimenow, 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
CalendarOptionsisClone, no longerCopy, since it can hold a function that styles dates; clone it where it was copied. - intuiTUIve's
Sizeis#[non_exhaustive]and hasSize::Ratio: amatchon 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,TableOptionsandFrameStatshave 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 profileon 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.--flatgives 0.0.18's profile.- A vertical
BarChartwith 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
Sparklineor plotCanvaswithout its own height fills the height it is given (a fixed-heightPanel, aLayoutregion, 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-intervaltakes at most 86400 seconds; a larger value is a usage error (exit 2).banner,shell,approveandjumpare subcommands now: a file of one of those names needs a path, such asrich ./banner.rich logreads 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_SESSIONbroke 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_selfwas 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
pythonand Jupyter kernels got processes and every tab failed; a script that changed directory could not be run again; a hugesession_cpupanicked; aSurfacelost 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_belowor@mediawas 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.19passed 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 --checkandcapture_python_docs.py --checkpass, 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 intuiTUIvelist, 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):
- From
22da468:rs-rich-ext-v0.0.16,rs-rich-micro-v0.0.5,rs-rich-record-v0.0.7andrs-rich-interact-v0.0.7. - 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.3andrs-rich-cli-v0.0.19; thenpython-v0.0.7throughpypi-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).