Skip to main content

ansi/
lib.rs

1//! ansi: ANSI/VT terminal output as data, on the Rust standard library
2//! alone. Zero dependencies.
3//!
4//! Three tightly-related capabilities, all pure bytes in / bytes out:
5//!
6//! * **Build** styled output: [`Style`] + [`Color`] render to SGR escape
7//!   sequences, absolutely ([`Style::sgr`]) or as a minimal transition from a
8//!   previous style ([`Style::transition_to`]).
9//! * **Parse** a terminal byte stream incrementally: [`Parser::feed`] accepts
10//!   chunks split at *any* byte boundary (mid-escape, mid-UTF-8) and yields
11//!   [`Token`]s (text runs, C0 controls, CSI/ESC/OSC sequences).
12//! * **Render by diff**: [`Screen`] is a grid of styled [`Cell`]s;
13//!   [`Screen::diff`] emits the minimal cursor-move/SGR/text bytes that turn
14//!   one screen into another, and [`Screen::render_full`] repaints from
15//!   scratch.
16//!
17//! ```
18//! use ansi::{Color, Style};
19//!
20//! let style = Style { bold: true, fg: Color::Indexed(2), ..Style::default() };
21//! assert_eq!(style.sgr(), "\x1b[0;1;32m");
22//!
23//! let mut p = ansi::Parser::new();
24//! let tokens = p.feed(b"hi\x1b[1;31mred");
25//! assert_eq!(tokens.len(), 3); // Text("hi"), Csi(SGR 1;31), Text("red")
26//! ```
27//!
28//! There is no I/O here: no raw mode, no stdin/stdout, no PTY. Those are the
29//! `rawterm` and `pty` crates' concerns; this crate turns bytes into meaning
30//! and meaning into bytes.
31
32mod parse;
33mod screen;
34mod style;
35
36pub use parse::{Parser, Token};
37pub use screen::{Cell, Screen};
38pub use style::{Color, Style};