clyle_proc/lib.rs
1#![doc = include_str!("../README.md")]
2
3use proc_macro::TokenStream;
4use proc_macro2::{Ident, Span};
5use quote::{quote, quote_spanned};
6use syn::parse::Parse;
7use syn::{LitStr, parse_macro_input};
8
9/// Compile-time styling for terminal output using HTML-like syntax.
10///
11/// This macro processes styling markup at compile time and returns a `String`
12/// with the styled text, including ANSI escape sequences.
13///
14/// # Arguments
15///
16/// The macro takes a single string literal argument containing HTML-style markup.
17///
18/// # Returns
19///
20/// A `String` containing the input text with ANSI escape codes for styling.
21///
22/// *See the [`crate`] documentation for detailed syntax.*
23///
24/// # Examples
25///
26/// Basic foreground color:
27/// ```rust
28/// # use clye_proc as clyle;
29/// use clyle::clyle;
30/// let red_text = clyle!("<fg=red>Error</>");
31/// ```
32///
33/// Multiple effects:
34/// ```rust
35/// # use clye_proc as clyle;
36/// use clyle::clyle;
37/// let styled = clyle!("<fg=blue bold under>Important</>");
38/// ```
39///
40/// With background:
41/// ```rust
42/// # use clye_proc as clyle;
43/// use clyle::clyle;
44/// let highlighted = clyle!("<fg=black bg=yellow>Warning</>");
45/// ```
46///
47/// RGB colors:
48/// ```rust
49/// # use clye_proc as clyle;
50/// use clyle::clyle;
51/// let custom = clyle!("<fg=#FF8800>Custom orange</>");
52/// ```
53///
54/// # Compile-Time Processing
55///
56/// This macro processes the styling at compile time. If there are any syntax errors
57/// in the markup, compilation will fail with a descriptive error message pointing
58/// to the problem location.
59///
60/// # Performance
61///
62/// Unlike runtime parsing (via `try_clyle`), this macro has **zero runtime overhead**:
63/// - Styling is processed during compilation
64/// - The resulting binary contains only the processed string with ANSI codes
65/// - No parsing or validation happens at runtime
66///
67/// # Errors
68///
69/// Compilation fails if:
70/// - The input is not a string literal
71/// - The markup contains invalid color or effect names
72/// - Tags are improperly nested or closed
73///
74#[proc_macro]
75pub fn clyle(tokens: TokenStream) -> TokenStream {
76 let source = parse_macro_input!(tokens as LitStr);
77 let span = source.span();
78 let parsed = clyle_core::clyle(&source.value());
79
80 let expanded = quote_spanned!(span=> #parsed);
81
82 TokenStream::from(expanded)
83}
84
85struct FormatArgs {
86 s: LitStr,
87 rest: proc_macro2::TokenStream,
88}
89
90impl Parse for FormatArgs {
91 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
92 Ok(FormatArgs {
93 s: input.parse()?,
94 rest: input.parse()?,
95 })
96 }
97}
98
99fn impl_fmt(name: &str, tokens: TokenStream) -> TokenStream {
100 let args = parse_macro_input!(tokens as FormatArgs);
101 let parsed = clyle_core::clyle(&args.s.value());
102 let name = Ident::new(name, Span::call_site());
103 let s = LitStr::new(&parsed, args.s.span());
104 let rest = args.rest;
105
106 let expanded = quote!(::std::#name!(#s #rest));
107
108 TokenStream::from(expanded)
109}
110
111/// Format a styled string with arguments at compile time.
112/// Combines [`clyle!`] styling with [`format!`] functionality.
113#[proc_macro]
114pub fn format(tokens: TokenStream) -> TokenStream {
115 impl_fmt("format", tokens)
116}
117
118/// Print a styled string to stdout at compile time.
119/// Combines [`clyle!`] styling with [`print!`] functionality.
120#[proc_macro]
121pub fn print(tokens: TokenStream) -> TokenStream {
122 impl_fmt("print", tokens)
123}
124
125/// Print a styled string to stdout with newline at compile time.
126/// Combines [`clyle!`] styling with [`println!`] functionality.
127#[proc_macro]
128pub fn println(tokens: TokenStream) -> TokenStream {
129 impl_fmt("println", tokens)
130}
131
132/// Print a styled string to stderr at compile time.
133/// Combines [`clyle!`] styling with [`eprint!`] functionality.
134#[proc_macro]
135pub fn eprint(tokens: TokenStream) -> TokenStream {
136 impl_fmt("eprint", tokens)
137}
138
139/// Print a styled string to stderr with newline at compile time.
140/// Combines [`clyle!`] styling with [`eprintln!`] functionality.
141#[proc_macro]
142pub fn eprintln(tokens: TokenStream) -> TokenStream {
143 impl_fmt("eprintln", tokens)
144}
145
146/// Write a styled string to a writer at compile time.
147/// Combines [`clyle!`] styling with [`write!`] functionality.
148#[proc_macro]
149pub fn write(tokens: TokenStream) -> TokenStream {
150 impl_fmt("write", tokens)
151}
152
153/// Write a styled string to a writer with newline at compile time.
154/// Combines [`clyle!`] styling with [`writeln!`] functionality.
155#[proc_macro]
156pub fn writeln(tokens: TokenStream) -> TokenStream {
157 impl_fmt("writeln", tokens)
158}