Skip to main content

gilt/
lib.rs

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