ANSI escape codes in Rust
Rust string literals support `\x1b` directly — `println!("\x1b[31mred\x1b[0m")` works with no dependencies. For ergonomic colour APIs reach for `owo-colors` (zero-allocation, compile-time) or `colored` (more dynamic). For NO_COLOR / isatty handling without writing the env-check yourself, `termcolor` mirrors the Go pattern. For full TUI work — windows, cursor, raw mode, mouse — use `crossterm`; for higher-level layouts, `ratatui` (formerly tui-rs) sits on top of it.
Recommended libraries
- owo-colors
Zero-allocation colour extension on every string-like type — `"error".red().bold()` produces no heap traffic. Compile-time style colors via const generics. ANSI only; no terminfo lookup.
- colored
The original `"text".red().bold()` API — more flexible than owo-colors (runtime palette, custom colours) at the cost of allocation. Honours `NO_COLOR` and `CLICOLOR_FORCE` out of the box.
- termcolor
ripgrep's colour layer — a `WriteColor` trait over stdout/stderr that handles ANSI on POSIX and the Windows console API on Windows. `ColorChoice::Auto` does NO_COLOR + isatty for you.
- crossterm
Full cross-platform terminal toolkit — cursor, colour, raw mode, alternate screen, mouse / focus / paste events, keyboard input. The foundation under `ratatui`. Use directly for CLIs; layer ratatui for full-screen TUIs.
Idiomatic patterns
fn main() {
println!("\x1b[1;31merror:\x1b[0m permission denied");
}use owo_colors::OwoColorize;
fn main() {
println!("{} permission denied", "error:".red().bold());
}use std::io::Write;
use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};
fn main() -> std::io::Result<()> {
// Auto downgrades to plain text under NO_COLOR= or non-tty stdout.
let mut out = StandardStream::stdout(ColorChoice::Auto);
out.set_color(ColorSpec::new().set_fg(Some(Color::Red)).set_bold(true))?;
write!(out, "error:")?;
out.reset()?;
writeln!(out, " permission denied")?;
Ok(())
}use std::io::{stdout, Write};
use crossterm::{
cursor::{Hide, Show},
execute,
terminal::{disable_raw_mode, enable_raw_mode},
};
fn main() -> std::io::Result<()> {
enable_raw_mode()?;
execute!(stdout(), Hide)?;
// ... read keys, render UI ...
execute!(stdout(), Show)?; // always restore
disable_raw_mode()?;
Ok(())
}