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::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/// Same as [`color!`], but bleeds.
35#[proc_macro]
36pub fn colorb(input: TokenStream) -> TokenStream {
37    let input = parse_macro_input!(input as LitStr);
38    let value = input.value();
39    let tokens = match farben_core::lexer::tokenize(&value) {
40        Ok(t) => t,
41        Err(e) => {
42            let msg = e.to_string();
43            return syn::Error::new_spanned(&input, msg)
44                .to_compile_error()
45                .into();
46        }
47    };
48    let result = farben_core::parser::render(tokens);
49    quote! { #result }.into()
50}
51
52/// Validates farben markup at compile time and returns the original string literal unchanged.
53///
54/// On success, emits the input string literal as-is. On failure, emits a compiler error
55/// at the call site. Used internally by `color_fmt!` and `cprintln!` to validate the
56/// format string before runtime processing.
57///
58/// # Examples
59///
60/// ```rust
61/// // Valid markup passes through unchanged
62/// let s = farben_macros::validate_color!("[bold red]");
63/// assert_eq!(s, "[bold red]");
64/// ```
65#[proc_macro]
66pub fn validate_color(input: TokenStream) -> TokenStream {
67    let input = parse_macro_input!(input as LitStr);
68    let value = input.value();
69
70    match farben_core::lexer::tokenize(&value) {
71        Ok(_) => quote! { #input }.into(),
72        Err(e) => {
73            let msg = e.to_string();
74            syn::Error::new_spanned(&input, msg)
75                .to_compile_error()
76                .into()
77        }
78    }
79}