Skip to main content

standout_render/
lib.rs

1//! # Standout Render - Styled Terminal Output Library
2//!
3//! `standout-render` combines templating, theming, and adaptive color handling so you
4//! can ship consistent terminal UI without re-implementing styling utilities.
5//! Although it powers the `standout` CLI framework, the crate is fully usable as a
6//! stand-alone renderer for any Rust application that needs rich TTY output.
7//!
8//! ## Core Concepts
9//!
10//! - [`Theme`]: Named, adaptive styles that automatically respect [`ColorMode`]
11//! - [`Renderer`]: Compile and reuse templates for fast repeated rendering
12//! - [`validate_template`]: Surface typos or unknown tags before you ship templates
13//! - [`OutputMode`]: Control how content is emitted (Auto/Term/Text/TermDebug/Json/Yaml)
14//! - Style syntax: Tag-based `[name]content[/name]` markup for inline styling
15//!
16//! ## Quick Start
17//!
18//! Create a [`Theme`], pass serializable data, and call [`render`] to produce a styled
19//! `String` that you can print, persist, or feed into other systems:
20//!
21//! ```rust
22//! use standout_render::{render, Theme};
23//! use console::Style;
24//! use serde::Serialize;
25//!
26//! #[derive(Serialize)]
27//! struct Summary {
28//!     title: String,
29//!     total: usize,
30//! }
31//!
32//! let theme = Theme::new()
33//!     .add("title", Style::new().bold())
34//!     .add("count", Style::new().cyan());
35//!
36//! let template = r#"
37//! [title]{{ title }}[/title]
38//! ---------------------------
39//! Total items: [count]{{ total }}[/count]
40//! "#;
41//!
42//! let output = render(
43//!     template,
44//!     &Summary { title: "Report".into(), total: 3 },
45//!     &theme,
46//! ).unwrap();
47//! println!("{}", output);
48//! ```
49//!
50//! ## Tag-Based Styling
51//!
52//! Templates use lightweight `[name]content[/name]` tags, so you can mix static text
53//! and template variables without sprinkling manual `console::Style` calls. The
54//! renderer resolves each tag to the appropriate entry in your [`Theme`]:
55//!
56//! ```rust
57//! use standout_render::{render_with_output, Theme, OutputMode};
58//! use console::Style;
59//! use serde::Serialize;
60//!
61//! #[derive(Serialize)]
62//! struct Data { name: String, count: usize }
63//!
64//! let theme = Theme::new()
65//!     .add("title", Style::new().bold())
66//!     .add("count", Style::new().cyan());
67//!
68//! let template = r#"[title]Report[/title]: [count]{{ count }}[/count] items by {{ name }}"#;
69//!
70//! let output = render_with_output(
71//!     template,
72//!     &Data { name: "Alice".into(), count: 42 },
73//!     &theme,
74//!     OutputMode::Text,
75//! ).unwrap();
76//!
77//! assert_eq!(output, "Report: 42 items by Alice");
78//! ```
79//!
80//! ## Adaptive Themes (Light & Dark)
81//!
82//! Styles automatically adapt to the current [`ColorMode`]. Provide explicit
83//! overrides for light and dark variants, or rely on a shared default when you
84//! do not need per-mode differences:
85//!
86//! ```rust
87//! use standout_render::Theme;
88//! use console::Style;
89//!
90//! let theme = Theme::new()
91//!     // Non-adaptive style (same in all modes)
92//!     .add("header", Style::new().bold().cyan())
93//!     // Adaptive style with light/dark variants
94//!     .add_adaptive(
95//!         "panel",
96//!         Style::new(),                                  // Base
97//!         Some(Style::new().fg(console::Color::Black)), // Light mode
98//!         Some(Style::new().fg(console::Color::White)), // Dark mode
99//!     );
100//! ```
101//!
102//! ## YAML-Based Themes
103//!
104//! Ship themes alongside your application or allow users to bring their own. The
105//! [`Theme::from_yaml`] helper loads named styles (and adaptive overrides) directly
106//! from a YAML definition:
107//!
108//! ```rust
109//! use standout_render::Theme;
110//!
111//! let theme = Theme::from_yaml(r#"
112//! header:
113//!   fg: cyan
114//!   bold: true
115//! panel:
116//!   fg: gray
117//!   light:
118//!     fg: black
119//!   dark:
120//!     fg: white
121//! title: header
122//! "#).unwrap();
123//! ```
124//!
125//! ## Renderer Example
126//!
127//! For larger applications, use [`Renderer`] to register templates once and render
128//! them repeatedly without reparsing:
129//!
130//! ```rust
131//! use standout_render::{Renderer, Theme};
132//! use console::Style;
133//! use serde::Serialize;
134//!
135//! #[derive(Serialize)]
136//! struct Entry { label: String, value: i32 }
137//!
138//! let theme = Theme::new()
139//!     .add("label", Style::new().bold())
140//!     .add("value", Style::new().green());
141//!
142//! let mut renderer = Renderer::new(theme).unwrap();
143//! renderer.add_template("row", "[label]{{ label }}[/label]: [value]{{ value }}[/value]").unwrap();
144//! let rendered = renderer.render("row", &Entry { label: "Count".into(), value: 42 }).unwrap();
145//! assert_eq!(rendered, "Count: 42");
146//! ```
147
148// Internal modules
149pub mod context;
150mod embedded;
151mod error;
152pub mod file_loader;
153pub mod output;
154pub mod prelude;
155pub mod style;
156pub mod tabular;
157pub mod template;
158pub mod theme;
159mod util;
160
161// Error type
162pub use error::RenderError;
163
164// Style module exports (including former stylesheet exports)
165pub use style::{
166    parse_css, parse_stylesheet, ColorDef, StyleAttributes, StyleDefinition, StyleValidationError,
167    StyleValue, Styles, StylesheetError, StylesheetRegistry, ThemeVariants,
168    DEFAULT_MISSING_STYLE_INDICATOR, STYLESHEET_EXTENSIONS,
169};
170
171// Theme module exports
172pub use theme::{detect_color_mode, set_theme_detector, ColorMode, Theme};
173
174// Output module exports
175pub use output::{write_binary_output, write_output, OutputDestination, OutputMode};
176
177// Render module exports
178pub use template::{
179    render,
180    render_auto,
181    render_auto_with_context,
182    render_auto_with_engine,
183    render_auto_with_spec,
184    render_with_context,
185    render_with_mode,
186    render_with_output,
187    render_with_vars,
188    validate_template,
189    // Template registry
190    walk_template_dir,
191    // Template engine abstraction
192    MiniJinjaEngine,
193    RegistryError,
194    Renderer,
195    ResolvedTemplate,
196    TemplateEngine,
197    TemplateFile,
198    TemplateRegistry,
199    TEMPLATE_EXTENSIONS,
200};
201
202// Re-export BBParser types for template validation
203pub use standout_bbparser::{UnknownTagError, UnknownTagErrors, UnknownTagKind};
204
205// Utility exports
206pub use util::{flatten_json_for_csv, rgb_to_ansi256, rgb_to_truecolor, truncate_to_width};
207
208// File loader exports
209pub use file_loader::{
210    build_embedded_registry, extension_priority, strip_extension, walk_dir, FileRegistry,
211    FileRegistryConfig, LoadError, LoadedEntry, LoadedFile,
212};
213
214// Embedded source types (for macros)
215pub use embedded::{
216    EmbeddedSource, EmbeddedStyles, EmbeddedTemplates, StylesheetResource, TemplateResource,
217};