gilt
Rich terminal output for Rust — a port of Python's rich library.
What gilt is — and is not
gilt is a retained-print / inline-output library that emits scrolling
styled ANSI output (styles, tables, trees, syntax, markdown, progress bars, live
displays) that drops straight into any CLI. You print renderables and they
scroll by just like normal terminal output.
gilt is NOT a full-screen TUI framework. It does not own the alternate
screen, does not run an event loop, and does not need crossterm for basic
output. Reach for ratatui when you need a
full-screen interactive app. Use gilt for CLI output, log styling, CI reports,
build dashboards, and streaming output.
Quick start
[]
= "1.10"
use Console;
Upgrading from 0.13.x? See MIGRATION_v1.md — most code
becomes shorter (Style::parse, ergonomic Text::styled, Status::run,
Live::from_renderable, Padding::wrap, …).
Visual gallery
Table — Unicode box-drawing tables with titles, styled headers, and columns:
Tree — hierarchical structures with configurable guide characters:
Markdown — heading, bold, italic, inline code, fenced code blocks, lists:
Progress — multi-bar progress with description, bar, count, and ETA:
SVGs are generated by
cargo run --example gen_readme_demos --all-featuresand committed so they render on GitHub and docs.rs without a server.
gilt-cli — rich output without Rust
Install the binary to use gilt from shell scripts, Makefiles, and CI:
|
|
|
See crates/gilt-cli/ for the full subcommand
reference.
Features
Core widgets
Text · Table · Panel · Tree · Columns · Layout · Padding · Align · Group
Terminal features
Syntax (150+ languages) · Markdown · Json · Progress (multi-bar with ETA, speed, spinner) · Live (in-place updates) · Status
Rust-native extensions
Gradient · Sparkline · Canvas (Braille drawing) · Diff (unified + side-by-side) · Figlet · CsvTable · Stylize trait ("hi".bold().red()) · iterator .progress() · Inspect (any Debug value) · environment detection (NO_COLOR, FORCE_COLOR, CLICOLOR) · WCAG 2.1 contrast checking · extended underlines (curly, dotted, dashed, double) · bidirectional anstyle interop
Derive macros (feature-gated)
use ;
Auto-generate widget conversions from struct definitions. See crates/gilt-derive/README.md.
Optional integrations
miette · eyre · tracing · anstyle
Why gilt over alternatives?
| gilt | rich (Python) | ratatui | Spectre.Console (.NET) | |
|---|---|---|---|---|
| Language | Rust | Python | Rust | C# |
| Full-screen TUI | no | no | yes | no |
| Inline scrolling output | yes | yes | no | yes |
Compile-time text! macro |
yes | no | no | no |
| WASM-safe | yes | no | no | no |
| Derive macros | yes | no | no | partial |
| Inline images (Kitty/Sixel/halfblock) | yes | partial | no | no |
| Asciinema export | yes | no | no | no |
| Dep-light (library) | yes | no | no | no |
gilt is the natural choice when you want rich-style inline output in a Rust CLI or library, especially if WASM portability, dep minimisation, or compile-time macros matter to you.
Documentation
| Resource | Where |
|---|---|
| API docs | docs.rs/gilt |
| Release notes | CHANGELOG.md |
| v1.0 migration guide | MIGRATION_v1.md |
| Live & streaming guide | docs/live-and-streaming.md |
| Derive macros | crates/gilt-derive/ · docs.rs/gilt-derive |
| Examples | examples/ — run any with cargo run --example <name> |
| Feature flags & deps | docs.rs/crate/gilt/latest/features |
Examples
WebAssembly
gilt compiles for wasm32-unknown-unknown with --no-default-features — no
libc, crossterm, or terminal-syscall dependencies. Build with the
browser-safe feature set (the default-on terminal-size and interactive
features are native-only and excluded here):
= { = "1.10", = false, = ["json", "markdown", "syntax"] }
The intended browser path is record-mode + export — always set the width explicitly since there is no terminal to query:
let mut console = builder.width.record.build;
console.print;
let ansi = console.export_text; // pipe into xterm.js
let html = console.export_html; // inject into the DOM
Unicode handling
gilt computes visible cell width via unicode-width
and iterates by extended grapheme cluster (UAX #29) via
unicode-segmentation where
correctness matters.
Supported (correct visible width and intact iteration):
- ASCII, Latin-1, Latin Extended
- CJK fullwidth (Chinese, Japanese, Korean) — 2 cells
- Single-codepoint emoji — 2 cells
- ZWJ family clusters (
👨👩👧) — single 2-cell unit, never split mid-cluster - Flag emoji (
🇺🇸= 2 regional-indicator codepoints) — single 2-cell unit - Variation selector sequences (
❤️=❤+ VS-16) — emoji-presentation width - Combining mark sequences (
caféascafe + ́) — 0-width combining stays with its base
Not supported (out of scope, deferred):
- Bidi text direction (Arabic, Hebrew RTL).
Columns::right_to_leftreverses column order, not character bidi. - NFC/NFD normalisation — input is used as-is.
- Vertical text layout (Mongolian, classical Chinese).
Truncation and cropping (Console::truncate, Text::truncate,
Text::right_crop, anything routing through set_cell_size) snap to
grapheme-cluster boundaries — a 3-cell crop of "👨👩👧 family" will
not leave a dangling ZWJ joiner.
Performance
cargo bench runs the criterion suite (~80 benchmarks). See CHANGELOG.md for v0.10.x → v0.11.0 perf wins (T8 lock-free Live +21,000×, table render -46%, etc.).
Minimum Supported Rust Version
1.82.0 (for std::sync::LazyLock).
License
MIT — see LICENSE.