Skip to main content

farben_macros/
lib.rs

1use proc_macro::TokenStream;
2use quote::quote;
3use syn::{LitStr, parse_macro_input};
4
5/// Parses and colorizes a farben markup string at compile time.
6///
7/// Tokenizes and renders the input at compile time, emitting the final ANSI-escaped
8/// string as a string literal baked into the binary. Invalid markup produces a
9/// compiler error at the call site.
10///
11/// # Examples
12///
13/// ```rust
14/// use farben_macros::color;
15/// println!("{}", color!("[bold red]Hello!"));
16/// ```
17#[proc_macro]
18pub fn color(input: TokenStream) -> TokenStream {
19    let input = parse_macro_input!(input as LitStr);
20    let value = input.value();
21    let tokens = match farben_core::lexer::tokenize(&value) {
22        Ok(t) => t,
23        Err(e) => {
24            let msg = e.to_string();
25            return syn::Error::new_spanned(&input, msg)
26                .to_compile_error()
27                .into();
28        }
29    };
30    let result = format!("{}\x1b[0m", farben_core::parser::render(tokens));
31    quote! { #result }.into()
32}
33
34/// Parses and colorizes a farben markup string at compile time, without appending a
35/// trailing SGR reset.
36///
37/// Behaves identically to [`color!`] except the final `\x1b[0m` reset is omitted.
38/// Styles applied by this macro bleed into subsequent terminal output, making it
39/// useful for chaining multiple colored segments where the style should carry forward.
40///
41/// Invalid markup produces a compiler error at the call site.
42///
43/// # Examples
44///
45/// ```rust
46/// use farben_macros::colorb;
47/// // Style bleeds — subsequent output inherits bold red until a reset is issued.
48/// print!("{}", colorb!("[bold red]Warning: "));
49/// println!("this text is still bold red");
50/// ```
51#[proc_macro]
52pub fn colorb(input: TokenStream) -> TokenStream {
53    let input = parse_macro_input!(input as LitStr);
54    let value = input.value();
55    let tokens = match farben_core::lexer::tokenize(&value) {
56        Ok(t) => t,
57        Err(e) => {
58            let msg = e.to_string();
59            return syn::Error::new_spanned(&input, msg)
60                .to_compile_error()
61                .into();
62        }
63    };
64    let result = farben_core::parser::render(tokens);
65    quote! { #result }.into()
66}
67
68/// Validates farben markup at compile time and returns the original string literal unchanged.
69///
70/// On success, emits the input string literal as-is. On failure, emits a compiler error
71/// at the call site. Used internally by `color_fmt!`, `cprint!`, and `cprintln!` to validate
72/// the format string before runtime processing with format arguments.
73///
74/// This macro is part of the internal API. Prefer [`color!`] for static strings or
75/// [`color_fmt!`] for strings with format arguments.
76#[proc_macro]
77pub fn validate_color(input: TokenStream) -> TokenStream {
78    let input = parse_macro_input!(input as LitStr);
79    let value = input.value();
80
81    match farben_core::lexer::tokenize(&value) {
82        Ok(_) => quote! { #input }.into(),
83        Err(e) => {
84            let msg = e.to_string();
85            syn::Error::new_spanned(&input, msg)
86                .to_compile_error()
87                .into()
88        }
89    }
90}