gilt 2.0.0

Fast, beautiful terminal formatting for Rust — styles, tables, trees, syntax highlighting, progress bars, markdown.
Documentation

gilt

Rich terminal output for Rust — a port of Python's rich library.

CI Crates.io Documentation License: MIT MSRV

gilt styles demo

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

[dependencies]
gilt = "1.10"
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 — 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:

gilt table demo

Tree — hierarchical structures with configurable guide characters:

gilt tree demo

Markdown — heading, bold, italic, inline code, fenced code blocks, lists:

gilt markdown demo

Progress — multi-bar progress with description, bar, count, and ETA:

gilt progress demo

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:

cargo install gilt-cli
gilt print '[bold]hello[/] from gilt'
gilt style --fg red --bold 'Error message'
gilt table < data.csv
echo '# Title' | gilt markdown
cat src/main.rs | gilt syntax --lang rust
printf 'Root\n  child1\n  child2\n' | gilt tree
gilt rule 'Deploy complete'
gilt completions bash >> ~/.bash_completion

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 gilt::derives::{Table, Panel, Tree, Columns, Rule, Inspect, Renderable};

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

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):

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:

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.

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é 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 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.