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