Skip to content

Getting started

Assumes you have Rust installed and can run commands in a terminal. If you do not, rustup.rs is the one-line installer.

Requirements

Rust 1.90 or later (the MSRV, checked in CI)
Terminal any VT-capable terminal. On Windows use Windows Terminal — the legacy cmd.exe console is not supported
Tested on Linux (ubuntu-latest) and macOS in CI, the whole suite; Windows in CI for what differs there (the pager, batch paths, browser sessions, the interactive crates and time zones), and developed and exercised on Windows 11
Cost none — MIT licensed, no account, no network calls except the optional URL-fetch feature

Install

cargo add rs-rich
cargo install rs-rich-cli
[dependencies]
rs-rich = "0.0.10"

Published on crates.io

rs-rich · rs-rich-cli · rs-rich-ext · rs-rich-art · rs-rich-macros · rs-rich-plugin-api · rs-rich-mermaid · rs-rich-lumis (new in 0.0.12) · rs-rich-interact · rs-rich-record (new in 0.0.13) · rs-rich-micro (new in 0.0.14) · rs-rich-diagram (new in 0.0.15) · rs-rich-data (new in 0.0.16) · rs-rich-ratatui · rs-rich-intuituive (both new in 0.0.17) · rs-rich-web · rs-rich-embed (both new in 0.0.18) — follow the links for current published versions, and see the version table for this checkout's. API documentation is on docs.rs.

Check the install worked

rich --version

The output reports the installed rs-rich-cli package version. For a build from this checkout, compare it with the manifest-version table. It does not report the Python upstream version or the core library version.

If the shell reports "command not found", Cargo's binary directory is not on your PATH. It is ~/.cargo/bin (%USERPROFILE%\.cargo\bin on Windows) — add it and open a new shell, since PATH changes do not apply to shells that are already running.

Then render something:

rich --print "[bold magenta]Hello[/] [green]World[/]"

Hello in bold magenta and World in green

The picture is that command's own output, exported with --export-svg by scripts/smoke_cli.py --screenshots.

Uninstall

cargo uninstall rs-rich-cli

rich writes no configuration files of its own. Two things can stay behind: micro assets you added with rich micro add, install or create --add (under ~/.config/rich/micro/), and the cache of fitted micro-asset images (RICH_CACHE_DIR/micro, else $XDG_CACHE_HOME/rich/micro, ~/.cache/rich/micro, ~/Library/Caches/rich/micro on macOS or %LOCALAPPDATA%\rich\cache\micro on Windows). Delete those directories to remove it completely. For the library, delete the dependency from your Cargo.toml.

The package is rs-rich, the crate is rich

rich was already taken on crates.io by an unrelated crate, so the published package carries an rs- prefix. The library target keeps the short name, so the dependency and the use line differ:

rs-rich = "0.0.10"     # the 0.0.20 release's core
use rich::Console;      // what you write

The same applies to the others: rs-rich-ext is rich_ext, rs-rich-art is rich_art, rs-rich-diagram is rich_diagram, and so on. rs-rich-macros is used through rich_ext (its macros feature), for example rich_ext::richf!. The CLI package rs-rich-cli installs a binary called rich.

Hello, world

use rich::Console;

fn main() {
    let console = Console::new();
    hello(&console);
}

fn hello(console: &Console) {
    console.print_str("[bold magenta]Hello[/] [green]World[/]");
}
[bold magenta]Hello[/] [green]World[/]

The same two words from the library: Hello in bold magenta, World in green

The snippets on this page come from guide_getting_started.rs, which prints to your terminal, or with -- --svg DIR writes the picture above:

cargo run -p rs-rich-ext --example guide_getting_started

Console::new() detects the terminal: whether it is one, how wide it is, and which colour system it supports (truecolor, 256 or 16 colours). When output is redirected to a file, styling is dropped automatically — so piping to less or a log file gives clean text without you doing anything.

Controlling the console

Detection is right most of the time. When it isn't — in tests, in CI, when generating documentation — configure it explicitly:

fn controlling() {
    let console = Console::builder()
        .force_terminal(true) // style even when redirected
        .color_system(Some(ColorSystem::Truecolor))
        .width(80) // ignore the real width
        .build();
    assert_eq!(console.width(), 80);
}

Reproducible output

For snapshot tests, pin width, force_terminal and color_system. Otherwise the same code produces different bytes on a different terminal, and your snapshots will fight you.

Capturing instead of printing

Any render can be captured as a string rather than written out:

fn capturing() {
    let console = Console::builder()
        .force_terminal(true)
        .color_system(Some(ColorSystem::Truecolor))
        .build();
    let ansi = console.capture(|c| c.print_str("[bold]hi[/]"));
    assert_eq!(ansi, "\x1b[1mhi\x1b[0m\n");
}

That is also how the exports work — see Exporting and the export guide.

Where next

  • The tutorial builds up from a line of text to a live progress display.
  • The gallery is the fastest way to see what exists.
  • Parity explains what "a port" means here, and where it stops.
  • Terminal apps builds full-screen programs with intuiTUIve, and Interactive asks questions in a program or a script.