Skip to main content

farben_macros/
lib.rs

1//! Procedural macros for the Farben terminal styling library.
2//!
3//! Provides compile-time processing of farben markup and inline markdown,
4//! baking the final ANSI-escaped strings directly into the binary with zero
5//! runtime overhead. All macros in this crate are re-exported through
6//! [`farben`] and should not be used directly in most cases.
7//!
8//! ## Features
9//!
10//! - `markdown`: enables [`markdown!`] and [`colorb!`] for compile-time
11//!   markdown rendering via [`farben_md`].
12
13use proc_macro::TokenStream;
14use quote::quote;
15use syn::{LitStr, parse_macro_input};
16
17/// Parses and colorizes a farben markup string at compile time.
18///
19/// Tokenizes and renders the input at compile time, emitting the final ANSI-escaped
20/// string as a string literal baked into the binary. Invalid markup produces a
21/// compiler error at the call site.
22///
23/// # Examples
24///
25/// ```rust
26/// use farben_macros::color;
27/// println!("{}", color!("[bold red]Hello!"));
28/// ```
29#[proc_macro]
30pub fn color(input: TokenStream) -> TokenStream {
31    let input = parse_macro_input!(input as LitStr);
32    let value = input.value();
33    let tokens = match farben_core::lexer::tokenize(&value) {
34        Ok(t) => t,
35        Err(e) => {
36            let msg = e.to_string();
37            return syn::Error::new_spanned(&input, msg)
38                .to_compile_error()
39                .into();
40        }
41    };
42    let result = format!("{}\x1b[0m", farben_core::parser::render(tokens));
43    quote! { #result }.into()
44}
45
46/// Parses and colorizes a farben markup string at compile time, without appending a
47/// trailing SGR reset.
48///
49/// Behaves identically to [`color!`] except the final `\x1b[0m` reset is omitted.
50/// Styles applied by this macro bleed into subsequent terminal output, making it
51/// useful for chaining multiple colored segments where the style should carry forward.
52///
53/// Invalid markup produces a compiler error at the call site.
54///
55/// # Examples
56///
57/// ```rust
58/// use farben_macros::colorb;
59/// // Style bleeds — subsequent output inherits bold red until a reset is issued.
60/// print!("{}", colorb!("[bold red]Warning: "));
61/// println!("this text is still bold red");
62/// ```
63#[proc_macro]
64pub fn colorb(input: TokenStream) -> TokenStream {
65    let input = parse_macro_input!(input as LitStr);
66    let value = input.value();
67    let tokens = match farben_core::lexer::tokenize(&value) {
68        Ok(t) => t,
69        Err(e) => {
70            let msg = e.to_string();
71            return syn::Error::new_spanned(&input, msg)
72                .to_compile_error()
73                .into();
74        }
75    };
76    let result = farben_core::parser::render(tokens);
77    quote! { #result }.into()
78}
79
80/// Validates farben markup at compile time and returns the original string literal unchanged.
81///
82/// On success, emits the input string literal as-is. On failure, emits a compiler error
83/// at the call site. Used internally by `color_fmt!`, `cprint!`, and `cprintln!` to validate
84/// the format string before runtime processing with format arguments.
85///
86/// This macro is part of the internal API. Prefer [`color!`] for static strings or
87/// [`color_fmt!`] for strings with format arguments.
88#[proc_macro]
89pub fn validate_color(input: TokenStream) -> TokenStream {
90    let input = parse_macro_input!(input as LitStr);
91    let value = input.value();
92
93    match farben_core::lexer::tokenize(&value) {
94        Ok(_) => quote! { #input }.into(),
95        Err(e) => {
96            let msg = e.to_string();
97            syn::Error::new_spanned(&input, msg)
98                .to_compile_error()
99                .into()
100        }
101    }
102}
103
104/// Parses and renders an inline markdown string at compile time.
105///
106/// Tokenizes and renders the input at compile time, emitting the final
107/// ANSI-escaped string as a string literal baked into the binary.
108/// Supports `**bold**`, `*italic*`, `_italic_`, `__underline__`,
109/// `~~strikethrough~~`, and `` `inline code` ``.
110///
111/// # Examples
112///
113/// ```rust
114/// use farben_macros::markdown;
115/// println!("{}", markdown!("**bold** and *italic*"));
116/// ```
117#[cfg(feature = "markdown")]
118#[proc_macro]
119pub fn markdown(input: TokenStream) -> TokenStream {
120    let input = parse_macro_input!(input as LitStr);
121    let result = farben_md::renderer::render(&farben_md::lexer::tokenize(&input.value()));
122    quote! { #result }.into()
123}