# gilt
**Rich terminal output for Rust** — a port of Python's [rich](https://github.com/Textualize/rich) library.
[](https://github.com/khalidelborai/gilt/actions)
[](https://crates.io/crates/gilt)
[](https://docs.rs/gilt)
[](LICENSE)
[](https://blog.rust-lang.org/2024/10/17/Rust-1.82.0.html)

## 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](https://crates.io/crates/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
```toml
[dependencies]
gilt = "1.10"
```
```rust
use gilt::console::Console;
fn main() {
let mut console = Console::default();
console.print_text("Hello, [bold magenta]gilt[/bold magenta]!");
}
```
**Upgrading from 0.13.x?** See [MIGRATION_v1.md](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-features`
> and 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:
```sh
cargo install gilt-cli
```
```sh
gilt print '[bold]hello[/] from gilt'
gilt style --fg red --bold 'Error message'
gilt table < data.csv
printf 'Root\n child1\n child2\n' | gilt tree
gilt rule 'Deploy complete'
gilt completions bash >> ~/.bash_completion
```
See [`crates/gilt-cli/`](crates/gilt-cli/README.md) 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)
```rust
use gilt::derives::{Table, Panel, Tree, Columns, Rule, Inspect, Renderable};
```
Auto-generate widget conversions from struct definitions. See [`crates/gilt-derive/README.md`](crates/gilt-derive/README.md).
### Optional integrations
`miette` · `eyre` · `tracing` · `anstyle`
## Why gilt over alternatives?
| 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
| API docs | [docs.rs/gilt](https://docs.rs/gilt) |
| Release notes | [CHANGELOG.md](CHANGELOG.md) |
| **v1.0 migration guide** | [MIGRATION_v1.md](MIGRATION_v1.md) |
| Live & streaming guide | [docs/live-and-streaming.md](docs/live-and-streaming.md) |
| Derive macros | [crates/gilt-derive/](crates/gilt-derive/README.md) · [docs.rs/gilt-derive](https://docs.rs/gilt-derive) |
| Examples | [`examples/`](examples/) — run any with `cargo run --example <name>` |
| Feature flags & deps | [docs.rs/crate/gilt/latest/features](https://docs.rs/crate/gilt/latest/features) |
## Examples
```bash
cargo run --example showcase --all-features # full feature tour
cargo run --example table # core widget demos
cargo run --example progress
cargo run --example markdown
cargo run --example derive_table --features derive
cargo run --example gen_readme_demos --all-features # regenerate README SVGs
```
## 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):
```toml
gilt = { version = "1.10", default-features = false, features = ["json", "markdown", "syntax"] }
```
The intended browser path is record-mode + export — always set the width
explicitly since there is no terminal to query:
```rust
let mut console = Console::builder().width(80).record(true).build();
console.print(&my_widget);
let ansi = console.export_text(false, true); // pipe into xterm.js
let html = console.export_html(None, false, true); // inject into the DOM
```
See [`examples/wasm_export.rs`](examples/wasm_export.rs).
## Unicode handling
gilt computes visible cell width via [`unicode-width`](https://docs.rs/unicode-width)
and iterates by extended grapheme cluster (UAX #29) via
[`unicode-segmentation`](https://docs.rs/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é` as `cafe + ́`) — 0-width combining stays with its base
**Not supported (out of scope, deferred):**
- Bidi text direction (Arabic, Hebrew RTL). `Columns::right_to_left` reverses 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](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](LICENSE).