From 6f3802fd9f39c4e5847d130b4417b5cdfb66972d Mon Sep 17 00:00:00 2001 From: nsfisis Date: Sun, 22 Feb 2026 22:53:09 +0900 Subject: refactor(console): add console_format! proc macro and migrate all commands Introduce a Symfony Console-style tag macro that replaces verbose patterns like `console::info(&format!("text {name}"))` with `console_format!("text {name}")`. Supports all 6 tag types (info, comment, error, question, highlight, warning) with format argument distribution across multiple tagged segments. Co-Authored-By: Claude Opus 4.6 --- crates/mozart-console-macros/src/lib.rs | 70 +++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 crates/mozart-console-macros/src/lib.rs (limited to 'crates/mozart-console-macros/src/lib.rs') diff --git a/crates/mozart-console-macros/src/lib.rs b/crates/mozart-console-macros/src/lib.rs new file mode 100644 index 0000000..3af6f82 --- /dev/null +++ b/crates/mozart-console-macros/src/lib.rs @@ -0,0 +1,70 @@ +mod codegen; +mod parser; + +use proc_macro::TokenStream; +use syn::Expr; +use syn::punctuated::Punctuated; + +/// Format a string with Symfony Console-style tags. +/// +/// Supported tags: ``, ``, ``, ``, ``, ``. +/// +/// # Examples +/// +/// ```ignore +/// // Single tagged segment +/// console_format!("All packages are up to date.") +/// +/// // With format arguments +/// console_format!("Removing {name} from require-dev") +/// +/// // Mixed tags +/// console_format!("{} : {}", label, value) +/// +/// // Plain text (equivalent to format!) +/// console_format!("plain text {}", x) +/// ``` +#[proc_macro] +pub fn console_format(input: TokenStream) -> TokenStream { + let input2: proc_macro2::TokenStream = input.into(); + match console_format_impl(input2) { + Ok(tokens) => tokens.into(), + Err(err) => err.into_compile_error().into(), + } +} + +fn console_format_impl( + input: proc_macro2::TokenStream, +) -> Result { + let args: ConsoleFormatArgs = syn::parse2(input)?; + let segments = parser::parse_format_string(&args.format_str) + .map_err(|msg| syn::Error::new(args.format_str_span, msg))?; + Ok(codegen::generate(&segments, &args.extra_args)) +} + +struct ConsoleFormatArgs { + format_str: String, + format_str_span: proc_macro2::Span, + extra_args: Punctuated, +} + +impl syn::parse::Parse for ConsoleFormatArgs { + fn parse(input: syn::parse::ParseStream) -> syn::Result { + let lit: syn::LitStr = input.parse()?; + let format_str = lit.value(); + let format_str_span = lit.span(); + + let extra_args = if input.peek(syn::Token![,]) { + input.parse::()?; + Punctuated::parse_terminated(input)? + } else { + Punctuated::new() + }; + + Ok(ConsoleFormatArgs { + format_str, + format_str_span, + extra_args, + }) + } +} -- cgit v1.3.1