Skip to main content

gilt/
lib.rs

1//! # gilt -- Rich Terminal Formatting for Rust
2//!
3//! [![Crates.io](https://img.shields.io/crates/v/gilt.svg)](https://crates.io/crates/gilt)
4//! [![Documentation](https://docs.rs/gilt/badge.svg)](https://docs.rs/gilt)
5//! [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/khalidelborai/gilt/blob/main/LICENSE)
6//!
7//! A Rust port of Python's [rich](https://github.com/Textualize/rich) library -- beautiful
8//! terminal output with styles, tables, trees, syntax highlighting, progress bars, and
9//! more, all rendered as ANSI escape sequences.
10//!
11//! # Quick Start
12//!
13//! Add gilt to your `Cargo.toml`:
14//!
15//! ```toml
16//! [dependencies]
17//! gilt = "0.6"
18//! ```
19//!
20//! Then use the [`prelude`] for convenient access to common types:
21//!
22//! ```rust
23//! use gilt::prelude::*;
24//!
25//! let mut console = Console::builder().width(80).build();
26//! console.begin_capture();
27//! console.print_text("Hello, [bold magenta]gilt[/bold magenta]!");
28//! let output = console.end_capture();
29//! assert!(output.contains("Hello"));
30//! ```
31//!
32//! For quick one-off output, use the **global console** functions:
33//!
34//! ```rust,no_run
35//! gilt::print_text("Hello, [bold]world[/bold]!");
36//! gilt::inspect(&vec![1, 2, 3]);
37//! ```
38//!
39//! # The Console
40//!
41//! [`Console`](console::Console) is the central type in gilt. It manages terminal capabilities,
42//! drives the rendering pipeline, and handles output buffering, capture, and export.
43//!
44//! ## Creating a Console
45//!
46//! ```rust
47//! use gilt::console::Console;
48//!
49//! // Defaults: auto-detect terminal size, TrueColor, markup on
50//! let console = Console::new();
51//!
52//! // Builder pattern for full control
53//! let console = Console::builder()
54//!     .width(120)
55//!     .color_system("truecolor")
56//!     .record(true)       // enable export_html / export_svg
57//!     .no_color(false)
58//!     .build();
59//! ```
60//!
61//! ## Printing
62//!
63//! ```rust
64//! # use gilt::prelude::*;
65//! let mut console = Console::builder().width(80).build();
66//!
67//! // Print with rich markup
68//! console.print_text("[bold red]Error:[/bold red] something went wrong");
69//!
70//! // Print any Renderable (Panel, Table, Tree, ...)
71//! let panel = Panel::new(Text::new("inside a box", Style::null()));
72//! console.print(&panel);
73//! ```
74//!
75//! ## Capture and Export
76//!
77//! Capture lets you collect console output as a plain string instead of writing
78//! to the terminal:
79//!
80//! ```rust
81//! # use gilt::console::Console;
82//! let mut console = Console::builder().width(60).build();
83//! console.begin_capture();
84//! console.print_text("[bold]Captured![/bold]");
85//! let plain = console.end_capture();
86//! assert!(plain.contains("Captured!"));
87//! ```
88//!
89//! For rich export, enable `record(true)` on the builder, then call
90//! [`export_text`](console::Console::export_text),
91//! [`export_html`](console::Console::export_html), or
92//! [`export_svg`](console::Console::export_svg):
93//!
94//! ```rust
95//! # use gilt::console::Console;
96//! let mut console = Console::builder().width(60).record(true).build();
97//! console.print_text("[green]Recorded[/green]");
98//! let html = console.export_html(None, true, true);
99//! assert!(html.contains("<span"));
100//! ```
101//!
102//! # Text and Styling
103//!
104//! ## Style
105//!
106//! [`Style`](style::Style) represents a combination of foreground/background color, text attributes
107//! (bold, italic, underline, ...), extended underline styles, and hyperlinks.
108//!
109//! ```rust
110//! use gilt::style::Style;
111//!
112//! // Parse from a human-readable definition
113//! let style = Style::parse("bold red on white").unwrap();
114//! let subtle = Style::parse("dim italic #808080").unwrap();
115//!
116//! // Combine styles with the + operator (right side wins on conflicts)
117//! let combined = style + subtle;
118//! ```
119//!
120//! ## Markup
121//!
122//! gilt supports inline markup tags in strings, similar to BBCode:
123//!
124//! ```rust
125//! # use gilt::console::Console;
126//! let mut c = Console::builder().width(60).build();
127//! c.begin_capture();
128//! c.print_text("[bold]Bold[/bold], [italic green]green italic[/italic green]");
129//! let out = c.end_capture();
130//! assert!(out.contains("Bold"));
131//! ```
132//!
133//! Closing tags match their opening tag, or use `[/]` to close the most recent:
134//! `"[bold red]error[/] normal text"`.
135//!
136//! ## Text
137//!
138//! [`Text`](text::Text) is the fundamental rich-text type, storing a plain string plus styled spans.
139//!
140//! ```rust
141//! use gilt::text::Text;
142//! use gilt::style::Style;
143//!
144//! // Plain text
145//! let text = Text::new("Hello, world!", Style::null());
146//!
147//! // Styled text (entire string has one style)
148//! let bold = Text::styled("Important", Style::parse("bold").unwrap());
149//!
150//! // From markup (parses [tags])
151//! let rich = Text::from_markup("[red]Error:[/red] file not found").unwrap();
152//! assert!(rich.plain().contains("Error:"));
153//! ```
154//!
155//! ## Stylize Trait
156//!
157//! The [`Stylize`](styled_str::Stylize) trait provides a fluent, Rust-idiomatic API for
158//! building styled text directly from string literals:
159//!
160//! ```rust
161//! use gilt::styled_str::Stylize;
162//!
163//! let styled = "Hello".bold().red().on_blue();
164//! assert_eq!(styled.text, "Hello");
165//! ```
166//!
167//! `StyledStr` implements [`Renderable`](console::Renderable), so it can be passed
168//! directly to [`Console::print`](console::Console::print).
169//!
170//! # Widgets
171//!
172//! ## Panel
173//!
174//! [`Panel`](panel::Panel) wraps content in a bordered box with optional title and subtitle.
175//!
176//! ```rust
177//! use gilt::prelude::*;
178//! use gilt::box_chars::DOUBLE;
179//!
180//! // Expanding panel (fills available width)
181//! let panel = Panel::new(Text::new("content", Style::null()))
182//!     .with_title("My Panel")
183//!     .with_box_chars(&DOUBLE)
184//!     .with_border_style(Style::parse("blue").unwrap());
185//!
186//! // Fit-to-content panel
187//! let compact = Panel::fit(Text::new("snug", Style::null()));
188//! ```
189//!
190//! ## Table
191//!
192//! [`Table`](table::Table) renders data in Unicode box-drawing tables with column alignment,
193//! row striping, headers, footers, and style control.
194//!
195//! ```rust
196//! use gilt::table::Table;
197//!
198//! let mut table = Table::new(&["Name", "Age", "City"]);
199//! table.add_row(&["Alice", "30", "Paris"]);
200//! table.add_row(&["Bob", "25", "London"]);
201//!
202//! let output = format!("{}", table);
203//! assert!(output.contains("Alice"));
204//! ```
205//!
206//! Builder methods customise every aspect of the table:
207//!
208//! ```rust
209//! use gilt::table::Table;
210//! use gilt::box_chars::ROUNDED;
211//!
212//! let table = Table::new(&["Key", "Value"])
213//!     .with_title("Config")
214//!     .with_box_chars(Some(&ROUNDED))
215//!     .with_border_style("cyan")
216//!     .with_row_styles(vec!["".into(), "dim".into()])
217//!     .with_expand(true);
218//! ```
219//!
220//! Use [`Table::grid`](table::Table::grid) for borderless side-by-side layout:
221//!
222//! ```rust
223//! use gilt::table::Table;
224//!
225//! let mut grid = Table::grid(&["A", "B"]);
226//! grid.add_row(&["left", "right"]);
227//! ```
228//!
229//! ## Tree
230//!
231//! [`Tree`](tree::Tree) renders hierarchical data with Unicode guide lines.
232//!
233//! ```rust
234//! use gilt::prelude::*;
235//!
236//! let mut tree = Tree::new(Text::new("root", Style::null()));
237//! let child = tree.add(Text::new("child 1", Style::null()));
238//! child.add(Text::new("grandchild", Style::null()));
239//! tree.add(Text::new("child 2", Style::null()));
240//! ```
241//!
242//! Guide style affects line weight: default is thin lines, `bold` gives thick lines,
243//! and `underline2` selects double lines.
244//!
245//! ## Rule
246//!
247//! [`Rule`](rule::Rule) draws a horizontal line, optionally with a centered title.
248//!
249//! ```rust
250//! use gilt::rule::Rule;
251//!
252//! let rule = Rule::new();                           // plain line
253//! let titled = Rule::with_title("Section Header");  // line with title
254//! ```
255//!
256//! ## Columns
257//!
258//! [`Columns`](columns::Columns) lays out items in an auto-fitting multi-column grid.
259//!
260//! ```rust
261//! use gilt::columns::Columns;
262//!
263//! let mut cols = Columns::new();
264//! cols.add_renderable("one");
265//! cols.add_renderable("two");
266//! cols.add_renderable("three");
267//! ```
268//!
269//! ## Layout
270//!
271//! [`Layout`](layout::Layout) splits the terminal into rows and columns with flexible or
272//! fixed sizing, like a split-pane window manager.
273//!
274//! ```rust
275//! use gilt::layout::Layout;
276//!
277//! let mut root = Layout::new(None, Some("root".into()), None, None, Some(1), None);
278//! root.split_row(vec![
279//!     Layout::new(Some("Left pane".into()), Some("left".into()), None, None, Some(1), None),
280//!     Layout::new(Some("Right pane".into()), Some("right".into()), None, None, Some(2), None),
281//! ]);
282//! ```
283//!
284//! # Terminal Features
285//!
286//! ## Syntax Highlighting
287//!
288//! [`Syntax`](syntax::Syntax) highlights source code using [syntect](https://docs.rs/syntect)
289//! with 150+ language grammars. *(Requires the `syntax` feature, enabled by default.)*
290//!
291//! ```rust
292//! # #[cfg(feature = "syntax")]
293//! # {
294//! use gilt::syntax::Syntax;
295//!
296//! let code = r#"fn main() { println!("hello"); }"#;
297//! let syntax = Syntax::new(code, "rust")
298//!     .with_line_numbers(true)
299//!     .with_theme("base16-ocean.dark");
300//! # }
301//! ```
302//!
303//! ## Markdown
304//!
305//! [`Markdown`](markdown::Markdown) renders Markdown to the terminal with headings,
306//! lists, code blocks, and emphasis. *(Requires the `markdown` feature, enabled by default.)*
307//!
308//! ```rust
309//! # #[cfg(feature = "markdown")]
310//! # {
311//! use gilt::markdown::Markdown;
312//!
313//! let md = Markdown::new("# Hello\n\nThis is **bold** and *italic*.");
314//! # }
315//! ```
316//!
317//! ## JSON Pretty-Printing
318//!
319//! [`Json`](json::Json) parses and syntax-highlights JSON data.
320//! *(Requires the `json` feature, enabled by default.)*
321//!
322//! ```rust
323//! # #[cfg(feature = "json")]
324//! # {
325//! use gilt::json::{Json, JsonOptions};
326//!
327//! let json = Json::new(r#"{"name": "gilt", "version": "0.6.0"}"#, JsonOptions::default()).unwrap();
328//! # }
329//! ```
330//!
331//! The global convenience function makes it even simpler:
332//!
333//! ```rust,no_run
334//! # #[cfg(feature = "json")]
335//! gilt::print_json(r#"{"key": "value"}"#);
336//! ```
337//!
338//! ## Progress Bars
339//!
340//! [`Progress`](progress::Progress) provides a multi-task progress display with customisable columns
341//! (text, bar, spinner, time, speed) and live terminal updates.
342//!
343//! ```rust,no_run
344//! use gilt::progress::Progress;
345//!
346//! let mut progress = Progress::new(vec![]);
347//! let task = progress.add_task("Downloading", Some(100.0));
348//! progress.start();
349//! for _ in 0..100 {
350//!     progress.advance(task, 1.0);
351//! }
352//! progress.stop();
353//! ```
354//!
355//! ### Iterator Progress
356//!
357//! The [`ProgressIteratorExt`](progress::ProgressIteratorExt) trait adds `.progress()` to any iterator:
358//!
359//! ```rust,no_run
360//! use gilt::progress::ProgressIteratorExt;
361//!
362//! let items: Vec<i32> = (0..100).progress("Processing").collect();
363//! ```
364//!
365//! ## Live Display
366//!
367//! [`Live`](live::Live) renders content that updates in-place using cursor control codes.
368//!
369//! ```rust,no_run
370//! use gilt::live::Live;
371//! use gilt::text::Text;
372//! use gilt::style::Style;
373//!
374//! let mut live = Live::new(Text::new("Loading...", Style::null()));
375//! live.start();
376//! // ... update content ...
377//! live.update_renderable(Text::new("Done!", Style::null()), true);
378//! live.stop();
379//! ```
380//!
381//! ## Status Spinner
382//!
383//! [`Status`](status::Status) displays a spinner animation with a status message.
384//!
385//! ```rust,no_run
386//! use gilt::status::Status;
387//!
388//! let mut status = Status::new("Loading...");
389//! status.start();
390//! status.update().status("Processing...").apply();
391//! status.stop();
392//! ```
393//!
394//! # Rust-Native Features
395//!
396//! These features go beyond what Python's rich provides, taking advantage of
397//! Rust's type system and ecosystem.
398//!
399//! ## Gradients
400//!
401//! [`Gradient`](gradient::Gradient) renders text with smoothly interpolated true-color gradients.
402//!
403//! ```rust
404//! use gilt::gradient::Gradient;
405//! use gilt::color::Color;
406//!
407//! let g = Gradient::two_color("Hello!", Color::from_rgb(255, 0, 0), Color::from_rgb(0, 0, 255));
408//! let rainbow = Gradient::rainbow("All the colors!");
409//! ```
410//!
411//! ## Sparkline
412//!
413//! [`Sparkline`](sparkline::Sparkline) renders numeric data as compact inline Unicode bar charts.
414//!
415//! ```rust
416//! use gilt::sparkline::Sparkline;
417//!
418//! let spark = Sparkline::new(&[1.0, 3.0, 5.0, 7.0, 5.0, 3.0, 1.0]);
419//! let output = format!("{}", spark);
420//! assert!(!output.is_empty());
421//! ```
422//!
423//! ## Canvas
424//!
425//! [`Canvas`](canvas::Canvas) provides a Braille dot-matrix for high-resolution terminal graphics.
426//! Each character cell encodes a 2x4 pixel grid, giving sub-character resolution.
427//!
428//! ```rust
429//! use gilt::canvas::Canvas;
430//!
431//! let mut c = Canvas::new(10, 5);
432//! c.line(0, 0, 19, 19);   // diagonal line
433//! c.rect(2, 2, 10, 10);   // rectangle
434//! c.circle(10, 10, 8);    // circle
435//! ```
436//!
437//! ## Diff
438//!
439//! [`Diff`](diff::Diff) computes and renders colored line-level diffs in
440//! unified or side-by-side format.
441//!
442//! ```rust
443//! use gilt::diff::{Diff, DiffStyle};
444//!
445//! let old = "line 1\nline 2\nline 3\n";
446//! let new = "line 1\nline 2 modified\nline 3\nline 4\n";
447//! let diff = Diff::new(old, new).with_labels("before", "after");
448//! let sbs = Diff::side_by_side(old, new);
449//! ```
450//!
451//! ## Figlet
452//!
453//! [`Figlet`](figlet::Figlet) renders large ASCII art text using a built-in 5x7 block font.
454//!
455//! ```rust
456//! use gilt::figlet::Figlet;
457//!
458//! let banner = Figlet::new("HI");
459//! let output = format!("{}", banner);
460//! assert!(!output.is_empty());
461//! ```
462//!
463//! ## Inspect
464//!
465//! [`Inspect`](inspect::Inspect) displays structured information about any
466//! `Debug` value in a styled panel, showing the type name and formatted representation.
467//!
468//! ```rust
469//! use gilt::inspect::Inspect;
470//! use gilt::console::Console;
471//!
472//! let data = vec![1, 2, 3];
473//! let widget = Inspect::new(&data)
474//!     .with_title("My Data")
475//!     .with_label("numbers");
476//!
477//! let mut c = Console::builder().width(80).force_terminal(true).build();
478//! c.begin_capture();
479//! c.print(&widget);
480//! let output = c.end_capture();
481//! assert!(output.contains("Vec"));
482//! ```
483//!
484//! Or use the global shorthand:
485//!
486//! ```rust,no_run
487//! gilt::inspect(&vec![1, 2, 3]);
488//! ```
489//!
490//! ## CsvTable
491//!
492//! [`CsvTable`](csv_table::CsvTable) converts CSV data into a rich [`Table`](table::Table).
493//!
494//! ```rust
495//! use gilt::csv_table::CsvTable;
496//!
497//! let csv = CsvTable::from_csv_str("name,age\nAlice,30\nBob,25").unwrap();
498//! let table = csv.to_table();
499//! ```
500//!
501//! # Derive Macros
502//!
503//! With the `derive` feature enabled, gilt provides seven proc-macro derives that
504//! automatically generate widget conversions from struct definitions:
505//!
506//! | Derive | Generates | Method |
507//! |--------|-----------|--------|
508//! | `Table` | Table from a slice of structs | `Type::to_table(&items)` |
509//! | `Panel` | Panel from a single struct | `value.to_panel()` |
510//! | `Tree` | Tree from a struct | `value.to_tree()` |
511//! | `Columns` | Columns from a struct | `value.to_columns()` |
512//! | `Rule` | Rule from a struct | `value.to_rule()` |
513//! | `Inspect` | Inspect panel from a struct | `value.to_inspect()` |
514//! | `Renderable` | `Renderable` trait impl | `console.print(&value)` |
515//!
516//! ```rust,ignore
517//! use gilt::Table;
518//!
519//! #[derive(Table)]
520//! #[table(title = "Employees", box_style = "ROUNDED")]
521//! struct Employee {
522//!     #[column(header = "Full Name", style = "bold")]
523//!     name: String,
524//!     #[column(justify = "right")]
525//!     age: u32,
526//!     #[column(skip)]
527//!     internal_id: u64,
528//!     #[column(header = "Dept", style = "green")]
529//!     department: String,
530//! }
531//!
532//! let employees = vec![
533//!     Employee { name: "Alice".into(), age: 30, internal_id: 1, department: "Eng".into() },
534//! ];
535//! let table = Employee::to_table(&employees);
536//! ```
537//!
538//! Enable in `Cargo.toml`:
539//!
540//! ```toml
541//! gilt = { version = "0.6", features = ["derive"] }
542//! ```
543//!
544//! # Feature Gates
545//!
546//! | Feature | Default | Crate Dependencies | Description |
547//! |---------|---------|-------------------|-------------|
548//! | `json` | Yes | `serde`, `serde_json` | JSON pretty-printing via [`Json`](json::Json) |
549//! | `markdown` | Yes | `pulldown-cmark` | Terminal Markdown via [`Markdown`](markdown::Markdown) |
550//! | `syntax` | Yes | `syntect` | Syntax highlighting via [`Syntax`](syntax::Syntax) |
551//! | `interactive` | Yes | `rpassword` | Password prompts and selection menus |
552//! | `logging` | Yes | `log` | Logging handler |
553//! | `tracing` | No | `tracing`, `tracing-subscriber` | [`GiltLayer`](tracing_layer::GiltLayer) subscriber |
554//! | `derive` | No | `gilt-derive` | 7 proc-macro derives |
555//! | `miette` | No | `miette` | [`GiltMietteHandler`](miette_handler::GiltMietteHandler) |
556//! | `eyre` | No | `eyre` | [`GiltEyreHandler`](eyre_handler::GiltEyreHandler) |
557//! | `anstyle` | No | `anstyle` | Bidirectional `From` conversions |
558//! | `csv` | No | `csv` | CSV file reading (built-in parser always available) |
559//! | `readline` | No | `rustyline` | Readline-based prompt completions |
560//!
561//! For a minimal build with no heavy dependencies:
562//!
563//! ```toml
564//! gilt = { version = "0.6", default-features = false }
565//! ```
566//!
567//! # Integrations
568//!
569//! ## miette -- Diagnostic Reporting
570//!
571//! Install gilt as the [miette](https://docs.rs/miette) report handler for beautifully
572//! styled diagnostic output. *(Requires the `miette` feature.)*
573//!
574//! ```rust,ignore
575//! gilt::miette_handler::install();
576//! ```
577//!
578//! ## eyre -- Error Reporting
579//!
580//! Install gilt as the [eyre](https://docs.rs/eyre) report handler. *(Requires the `eyre` feature.)*
581//!
582//! ```rust,ignore
583//! gilt::eyre_handler::install().unwrap();
584//! ```
585//!
586//! ## tracing -- Structured Logging
587//!
588//! Use [`GiltLayer`](tracing_layer::GiltLayer) as a tracing subscriber layer for
589//! colored, formatted log output. *(Requires the `tracing` feature.)*
590//!
591//! ```rust,ignore
592//! use gilt::tracing_layer::GiltLayer;
593//! use tracing_subscriber::prelude::*;
594//!
595//! tracing_subscriber::registry()
596//!     .with(GiltLayer::new())
597//!     .init();
598//! ```
599//!
600//! ## anstyle -- Type Conversions
601//!
602//! With the `anstyle` feature, gilt [`Color`](color::Color) and [`Style`](style::Style)
603//! types gain bidirectional `From` conversions with their
604//! [anstyle](https://docs.rs/anstyle) counterparts, enabling interop with clap,
605//! owo-colors, and the anstyle ecosystem.
606//!
607//! # Advanced
608//!
609//! ## Theme System
610//!
611//! gilt's [`Theme`](theme::Theme) maps style names (like `"table.header"` or `"bold red"`)
612//! to [`Style`](style::Style) instances. The default theme provides sensible styling for all built-in
613//! widgets. Push custom themes onto the console's theme stack:
614//!
615//! ```rust
616//! use gilt::console::Console;
617//! use gilt::theme::Theme;
618//! use gilt::style::Style;
619//! use std::collections::HashMap;
620//!
621//! let mut styles = HashMap::new();
622//! styles.insert("info".to_string(), Style::parse("bold cyan").unwrap());
623//!
624//! let mut console = Console::new();
625//! console.push_theme(Theme::new(Some(styles), true));
626//! // All rendering now uses the custom "info" style
627//! console.pop_theme();
628//! ```
629//!
630//! ## Custom Renderables
631//!
632//! Implement the [`Renderable`](console::Renderable) trait to create your own widgets:
633//!
634//! ```rust
635//! use gilt::console::{Console, ConsoleOptions, Renderable};
636//! use gilt::segment::Segment;
637//!
638//! struct Greeting { name: String }
639//!
640//! impl Renderable for Greeting {
641//!     fn gilt_console(&self, _console: &Console, _options: &ConsoleOptions) -> Vec<Segment> {
642//!         vec![
643//!             Segment::text(&format!("Hello, {}!", self.name)),
644//!             Segment::line(),
645//!         ]
646//!     }
647//! }
648//! ```
649//!
650//! ## Accessibility (WCAG Contrast)
651//!
652//! The [`accessibility`] module provides WCAG 2.1 contrast ratio calculations:
653//!
654//! ```rust
655//! use gilt::accessibility::{contrast_ratio, meets_aa, meets_aaa};
656//! use gilt::color_triplet::ColorTriplet;
657//!
658//! let black = ColorTriplet::new(0, 0, 0);
659//! let white = ColorTriplet::new(255, 255, 255);
660//! assert!((contrast_ratio(&black, &white) - 21.0).abs() < 0.1);
661//! assert!(meets_aa(&black, &white));
662//! assert!(meets_aaa(&black, &white));
663//! ```
664//!
665//! ## Environment Variables
666//!
667//! gilt respects standard terminal environment variables with a 5-tier priority system:
668//!
669//! | Variable | Effect |
670//! |----------|--------|
671//! | `NO_COLOR` | Disables all color output ([no-color.org](https://no-color.org)) |
672//! | `FORCE_COLOR` | Forces color output even when not a TTY |
673//! | `CLICOLOR_FORCE` | Same as `FORCE_COLOR` |
674//! | `CLICOLOR=0` | Disables color |
675//! | `COLUMNS` / `LINES` | Overrides terminal size detection |
676//!
677//! Programmatic settings (via [`ConsoleBuilder`](console::ConsoleBuilder)) always take
678//! priority over environment variables.
679//!
680//! ## Console Export (HTML, SVG, Text)
681//!
682//! When recording is enabled, the console can export its output in multiple formats:
683//!
684//! ```rust
685//! # use gilt::console::Console;
686//! let mut c = Console::builder().width(60).record(true).build();
687//! c.print_text("[bold green]Success![/bold green]");
688//!
689//! let text = c.export_text(true, false);             // plain text
690//! let html = c.export_html(None, true, true);         // HTML with inline styles
691//! let svg  = c.export_svg("Title", None, true, None, 0.61); // SVG image
692//! ```
693//!
694//! Files can be written directly with
695//! [`save_text`](console::Console::save_text),
696//! [`save_html`](console::Console::save_html), and
697//! [`save_svg`](console::Console::save_svg).
698//!
699//! # Module Index
700//!
701//! | Module | Description |
702//! |--------|-------------|
703//! | [`console`] | Console engine: rendering, capture, export |
704//! | [`style`] | Text styles: colors, attributes, hyperlinks |
705//! | [`text`] | Rich text with markup parsing and word wrapping |
706//! | [`table`] | Unicode box-drawing tables |
707//! | [`panel`] | Bordered content panels |
708//! | [`tree`] | Hierarchical tree display |
709//! | [`rule`] | Horizontal rules with titles |
710//! | [`columns`] | Auto-fitting multi-column layout |
711//! | [`layout`] | Split-pane terminal layouts |
712//! | [`progress`] | Multi-task progress bars with live display |
713//! | [`live`] | Live-updating terminal display |
714//! | [`status`] | Spinner with status message |
715//! | [`gradient`] | True-color gradient text |
716//! | [`sparkline`] | Inline Unicode sparkline charts |
717//! | [`canvas`] | Braille dot-matrix graphics |
718//! | [`diff`] | Colored unified and side-by-side diffs |
719//! | [`figlet`] | Large ASCII art text |
720//! | [`csv_table`] | CSV-to-Table conversion |
721//! | [`styled_str`] | Stylize trait for `"text".bold().red()` chaining |
722//! | [`mod@inspect`] | Debug any value with rich formatting |
723//! | [`markup`] | Markup tag parser |
724//! | [`color`] | Color types and parsing |
725//! | [`segment`] | Low-level rendering segments |
726//! | [`theme`] | Named style collections |
727//! | [`accessibility`] | WCAG 2.1 contrast checking |
728//! | [`highlighter`] | Regex-based and repr syntax highlighters |
729//! | [`emoji`] | Emoji shortcode replacement |
730//! | [`box_chars`] | 19 box-drawing character sets |
731//! | [`prelude`] | Convenience re-exports |
732
733// Module hierarchy - organized by functionality
734pub mod color;
735pub mod error;
736pub mod live;
737pub mod progress;
738pub mod status;
739pub mod text;
740pub mod utils;
741pub mod widgets;
742
743// Core modules (at root level)
744pub mod accordion;
745pub mod badge;
746#[cfg(feature = "anstyle")]
747pub mod anstyle_adapter;
748pub mod breadcrumbs;
749pub mod canvas;
750pub mod columns;
751pub mod console;
752pub mod csv_table;
753pub mod diff;
754pub mod export_format;
755pub mod figlet;
756pub mod gradient;
757pub mod group;
758pub mod layout;
759#[cfg(feature = "markdown")]
760pub mod markdown;
761pub mod markup;
762pub mod measure;
763pub mod pager;
764pub mod panel;
765pub mod prelude;
766pub mod progress_bar;
767pub mod prompt;
768pub mod region;
769pub mod rule;
770pub mod segment;
771pub mod sparkline;
772pub mod style;
773// styled and styled_str are now in utils/
774pub use utils::styled;
775pub use utils::styled_str;
776#[cfg(feature = "syntax")]
777pub mod syntax;
778pub mod tree;
779pub mod wrap;
780
781// Feature-gated modules
782#[cfg(feature = "async")]
783pub mod r#async;
784#[cfg(feature = "http")]
785pub mod http;
786#[cfg(feature = "json")]
787pub mod json;
788
789// Backward compatible re-exports
790// Backward compatible re-exports for moved modules
791pub use color::{accessibility, color_env, color_triplet, palette, terminal_theme, theme};
792pub use error::traceback;
793#[cfg(feature = "eyre")]
794pub use error::eyre_handler;
795#[cfg(feature = "miette")]
796pub use error::miette_handler;
797#[cfg(feature = "logging")]
798pub use error::logging_handler;
799#[cfg(feature = "tracing")]
800pub use error::tracing_layer;
801pub use live::{live_render, screen};
802pub use status::{spinner, spinners, toast};
803
804// Re-export commonly used utils for backward compatibility
805pub use utils::{align_widget, ansi, bar, box_chars, cells, constrain, containers, control,
806    default_styles, diagnose, emoji, emoji_codes, emoji_replace, filesize, highlighter,
807    inspect, padding, pretty, protocol, ratio, scope};
808
809// Backward compatible re-exports for widgets
810pub use widgets::table;
811
812// Re-export cache management functions
813pub use style::{clear_style_cache, style_cache_size};
814pub use color::{clear_color_cache, color_cache_size};
815
816#[cfg(feature = "derive")]
817pub use gilt_derive::Columns as DeriveColumns;
818#[cfg(feature = "derive")]
819pub use gilt_derive::Inspect as DeriveInspect;
820#[cfg(feature = "derive")]
821pub use gilt_derive::Panel;
822#[cfg(feature = "derive")]
823pub use gilt_derive::Renderable;
824#[cfg(feature = "derive")]
825pub use gilt_derive::Rule as DeriveRule;
826#[cfg(feature = "derive")]
827pub use gilt_derive::Table;
828#[cfg(feature = "derive")]
829pub use gilt_derive::Tree;
830
831use std::sync::LazyLock;
832use std::sync::Mutex;
833
834/// Global default console instance, protected by a mutex for thread safety.
835static DEFAULT_CONSOLE: LazyLock<Mutex<console::Console>> =
836    LazyLock::new(|| Mutex::new(console::Console::new()));
837
838/// Access the global default console.
839///
840/// Locks the mutex and calls the provided closure with a mutable reference
841/// to the console. Panics if the mutex is poisoned.
842pub fn with_console<F, R>(f: F) -> R
843where
844    F: FnOnce(&mut console::Console) -> R,
845{
846    let mut c = DEFAULT_CONSOLE.lock().expect("console mutex poisoned");
847    f(&mut c)
848}
849
850/// Print a renderable to the default console.
851///
852/// This is the Rust equivalent of Python rich's `rich.print()`.
853pub fn print(renderable: &dyn console::Renderable) {
854    with_console(|c| c.print(renderable));
855}
856
857/// Print a text string to the default console, processing markup.
858pub fn print_text(text: &str) {
859    with_console(|c| c.print_text(text));
860}
861
862/// Pretty-print JSON to the default console.
863#[cfg(feature = "json")]
864pub fn print_json(json: &str) {
865    with_console(|c| c.print_json(json));
866}
867
868/// Inspect a value in the default console.
869///
870/// Displays the type name, Debug representation, and optional docs
871/// in a styled panel.
872pub fn inspect<T: std::fmt::Debug + 'static>(value: &T) {
873    with_console(|c| c.inspect(value));
874}