Skip to main content

rich_rs/
lib.rs

1//! Rich-rs: Rich text and beautiful formatting for the terminal
2//!
3//! A Rust port of Python's [Rich](https://github.com/Textualize/rich) library.
4//!
5//! # Example
6//!
7//! ```
8//! use rich_rs::{Console, Text};
9//!
10//! let mut console = Console::new();
11//! // Print plain text
12//! console.print_text("Hello, World!").unwrap();
13//!
14//! // Print styled text using Text and render
15//! let text = Text::from_markup("Hello, [bold red]World[/]!", false).unwrap();
16//! console.print(&text, None, None, None, false, "\n").unwrap();
17//! ```
18
19// Core modules
20mod ansi;
21mod cells;
22mod color;
23mod control;
24mod emoji;
25pub mod error;
26pub mod export_format;
27mod filesize;
28mod measure;
29mod segment;
30mod style;
31pub mod styled;
32pub mod terminal_theme;
33mod theme;
34
35// Higher-level modules
36mod console;
37pub mod file_proxy;
38pub mod highlighter;
39pub mod json;
40pub mod markup;
41pub mod pager;
42pub mod text;
43pub mod wrap;
44
45// Box drawing characters
46pub mod r#box;
47
48// Simple renderables
49pub mod align;
50pub mod bar;
51pub mod columns;
52pub mod constrain;
53pub mod group;
54pub mod layout;
55pub mod live;
56pub mod live_render;
57pub mod loop_helpers;
58pub mod markdown;
59pub mod padding;
60pub mod panel;
61pub mod pretty;
62pub mod progress;
63pub mod progress_bar;
64pub mod prompt;
65pub mod region;
66pub mod rule;
67pub mod scope;
68pub mod screen;
69pub mod recorder;
70pub mod screen_buffer;
71pub mod screen_context;
72pub mod spinner;
73pub mod status;
74pub mod syntax;
75pub mod table;
76pub mod traceback;
77pub mod tree;
78
79// Builtin renderables
80mod renderables;
81
82// Re-exports for public API
83pub use cells::{cell_len, chop_cells, set_cell_size, split_graphemes};
84pub use color::{
85    ANSI_COLOR_NAMES, Color, ColorSystem, ColorTriplet, ColorType, EIGHT_BIT_PALETTE, Palette,
86    STANDARD_PALETTE, SimpleColor, WINDOWS_PALETTE, blend_rgb, parse_rgb_hex,
87};
88pub use console::{
89    Console, ConsoleOptions, JustifyMethod, OverflowMethod, PagerContext, PagerOptions,
90};
91pub use control::{Control, escape_control_codes, strip_control_codes};
92pub use error::{ParseError, Result as ParseResult};
93pub use measure::{Measurement, measure_renderables};
94pub use segment::{ControlType, Segment, SegmentLines, Segments};
95pub use style::{MetaValue, NULL_STYLE, Style, StyleMeta, StyleStack};
96pub use text::{Span, Text, TextPart};
97pub use theme::{Theme, ThemeError, ThemeStack, default_styles};
98pub use wrap::divide_line;
99
100// Emoji re-exports
101pub use ansi::AnsiDecoder;
102pub use emoji::{EMOJI, Emoji, EmojiVariant};
103pub use filesize::{
104    decimal as filesize_decimal, decimal_with_params as filesize_decimal_with_params,
105    pick_unit_and_suffix,
106};
107pub use loop_helpers::{loop_first, loop_first_last, loop_last};
108
109// Highlighter re-exports
110pub use highlighter::{
111    Highlighter, NullHighlighter, RegexHighlighter, combine_regex, iso8601_highlighter,
112    json_highlighter, repr_highlighter,
113};
114
115// JSON re-export
116pub use json::Json;
117
118// Simple renderable re-exports
119pub use align::{Align, VerticalAlignMethod};
120pub use bar::Bar;
121pub use columns::Columns;
122pub use constrain::Constrain;
123pub use group::{Group, Lines, Renderables};
124pub use padding::{Padding, PaddingDimensions};
125pub use panel::Panel;
126pub use rule::{AlignMethod, Rule};
127pub use styled::Styled;
128pub use table::{Column, Row, Table};
129pub use tree::{ASCII_GUIDES, BOLD_TREE_GUIDES, TREE_GUIDES, Tree, TreeGuides, TreeNodeOptions};
130
131// Syntax highlighting re-exports
132pub use syntax::{AnsiTheme, DEFAULT_THEME, Syntax, SyntaxTheme, SyntectTheme};
133
134// Pretty printing re-exports
135pub use pretty::{Pretty, pprint, pretty_repr};
136
137// Scope re-exports
138pub use scope::{ScopeRenderable, render_scope};
139
140// Traceback re-exports
141pub use layout::{Layout, LayoutRender, SplitterKind};
142pub use live::{Live, LiveOptions, VerticalOverflowMethod};
143pub use live_render::LiveRender;
144pub use progress::{
145    BarColumn, DownloadColumn, FileSizeColumn, MofNCompleteColumn, Progress, ProgressColumn,
146    ProgressReader, ProgressTask, RenderableColumn, SpinnerColumn, TaskID, TaskProgressColumn,
147    TextColumn, TimeElapsedColumn, TimeRemainingColumn, TotalFileSizeColumn, TrackConfig,
148    TransferSpeedColumn, WrapFileBuilder,
149};
150pub use progress_bar::ProgressBar;
151pub use recorder::FrameRecorder;
152pub use region::Region;
153pub use screen::Screen;
154pub use screen_buffer::{Cell, ScreenBuffer};
155pub use screen_context::ScreenContext;
156pub use spinner::{Spinner, spinner_names};
157pub use status::Status;
158pub use traceback::{Frame, Stack, SyntaxErrorInfo, Trace, Traceback, TracebackBuilder};
159
160// Prompt re-exports
161pub use prompt::{
162    Confirm, FloatPrompt, IntPrompt, InvalidResponse, Prompt, PromptError, Result as PromptResult,
163};
164
165// Pager re-exports
166pub use file_proxy::FileProxy;
167pub use pager::{BufferPager, NullPager, Pager, SystemPager};
168
169// Terminal theme and export re-exports
170pub use export_format::{CONSOLE_HTML_FORMAT, CONSOLE_SVG_FORMAT};
171pub use terminal_theme::{
172    DEFAULT_TERMINAL_THEME, DIMMED_MONOKAI, MONOKAI, NIGHT_OWLISH, SVG_EXPORT_THEME, TerminalTheme,
173};
174
175// Markup re-export
176pub use markup::escape as escape_markup;
177
178/// A type that can be rendered to the console.
179///
180/// All renderables must be `Send + Sync` to support `Live` and `Progress` features.
181/// The `measure` method has a default implementation that renders and measures
182/// the result; override it for better performance when possible.
183pub trait Renderable: Send + Sync {
184    /// Render this object to a sequence of segments.
185    fn render(&self, console: &Console, options: &ConsoleOptions) -> Segments;
186
187    /// Measure the minimum and maximum width requirements.
188    ///
189    /// Default implementation renders and measures the result.
190    /// Override for better performance.
191    fn measure(&self, console: &Console, options: &ConsoleOptions) -> Measurement {
192        Measurement::from_segments(&self.render(console, options))
193    }
194}
195
196/// A type that can be converted to a Renderable.
197///
198/// Uses an associated type to avoid heap allocation.
199pub trait RichCast {
200    /// The renderable type this converts to.
201    type Output: Renderable;
202
203    /// Convert to a renderable type.
204    fn rich(&self) -> Self::Output;
205}
206
207// Implement Renderable for common types
208impl Renderable for str {
209    fn render(&self, _console: &Console, _options: &ConsoleOptions) -> Segments {
210        // Convert to owned String since Segment requires 'static
211        Segments::from(Segment::new(self.to_owned()))
212    }
213}
214
215impl Renderable for String {
216    fn render(&self, _console: &Console, _options: &ConsoleOptions) -> Segments {
217        Segments::from(Segment::new(self.clone()))
218    }
219}
220
221/// Log a renderable to the console with automatic timestamp and source location.
222///
223/// This macro calls `Console::log()` and automatically captures the file and line
224/// number using `file!()` and `line!()` macros.
225///
226/// # Example
227///
228/// ```ignore
229/// use rich_rs::{Console, Text, log};
230///
231/// let mut console = Console::new();
232/// rich_rs::log!(console, &Text::plain("Server starting..."));
233/// ```
234#[macro_export]
235macro_rules! log {
236    ($console:expr, $renderable:expr) => {
237        $console.log($renderable, Some(file!()), Some(line!()))
238    };
239}
240
241// ============================================================================
242// Global Console
243// ============================================================================
244
245use std::sync::{Mutex, OnceLock};
246
247/// Get a reference to the global console singleton.
248///
249/// The global console is lazily initialized on first access.
250/// Use this for convenience when you don't need a custom console.
251///
252/// # Example
253///
254/// ```ignore
255/// let console = rich_rs::get_console();
256/// console.lock().unwrap().print_text("Hello!").unwrap();
257/// ```
258pub fn get_console() -> &'static Mutex<Console> {
259    static CONSOLE: OnceLock<Mutex<Console>> = OnceLock::new();
260    CONSOLE.get_or_init(|| Mutex::new(Console::new()))
261}
262
263/// Print styled content using the global console.
264///
265/// Accepts a string that may contain Rich markup, and prints it
266/// to the global console.
267///
268/// # Example
269///
270/// ```ignore
271/// rich_rs::rich_print!("[bold red]Hello[/] World");
272/// ```
273#[macro_export]
274macro_rules! rich_print {
275    ($($arg:tt)*) => {{
276        let text = format!($($arg)*);
277        if let Ok(mut console) = $crate::get_console().lock() {
278            let rendered = $crate::Text::from_markup(&text, true)
279                .unwrap_or_else(|_| $crate::Text::plain(&text));
280            let _ = console.print(&rendered, None, None, None, false, "\n");
281        }
282    }};
283}