use proc_macro::TokenStream;
use proc_macro2::TokenStream as TokenStream2;
use quote::{ToTokens, quote};
use syn::LitStr;
use crate::color_context::Context;
use crate::error::{Error, SpanError};
use crate::format_args::{
Node, get_args_and_format_string, get_format_string, parse_args, parse_format_string,
};
pub fn get_format_args(input: TokenStream) -> Result<TokenStream2, SpanError> {
let (format_string_token, args) = get_args_and_format_string(input)?;
let format_string = format_string_token.value();
let format_nodes = parse_format_string(&format_string, &format_string_token)?;
let final_format_string = get_format_string_from_nodes(format_nodes)?;
let final_format_string = LitStr::new(&final_format_string, format_string_token.span());
let args = args.iter().map(|arg| arg.to_token_stream()).skip(1); let final_args = std::iter::once(quote! { #final_format_string }).chain(args);
Ok(quote! { #(#final_args),* })
}
#[cfg(feature = "doc")]
pub fn get_format_args_doc(input: TokenStream) -> Result<TokenStream2, SpanError> {
let (format_string_token, args) = get_args_and_format_string(input)?;
let format_string = format_string_token.value();
let format_nodes = parse_format_string(&format_string, &format_string_token)?;
let final_format_string = get_format_string_from_nodes(format_nodes)?;
let final_format_string = unindent::unindent(&final_format_string);
let final_format_string = LitStr::new(&final_format_string, format_string_token.span());
let args = args.iter().map(|arg| arg.to_token_stream()).skip(1); let final_args = std::iter::once(quote! { #final_format_string }).chain(args);
Ok(quote! { #(#final_args),* })
}
pub fn get_cstr(input: TokenStream) -> Result<TokenStream2, SpanError> {
let args = parse_args(input)?;
let format_string_token = get_format_string(args.first())?;
let format_string = format_string_token.value();
if args.len() > 1 {
return Err(SpanError::new(Error::TooManyArgs, None));
}
let format_nodes = parse_format_string(&format_string, &format_string_token)?;
let final_format_string = get_format_string_from_nodes(format_nodes)?;
let final_format_string = LitStr::new(&final_format_string, format_string_token.span());
Ok(quote! { #final_format_string })
}
fn get_format_string_from_nodes(nodes: Vec<Node>) -> Result<String, SpanError> {
let mut format_string = String::new();
let mut color_context = Context::new();
for node in nodes {
match node {
Node::Text(s) | Node::Placeholder(s) => {
format_string.push_str(s);
},
Node::ColorTagGroup(tag_group) => {
let ansi_string = color_context.ansi_apply_tags(tag_group)?;
format_string.push_str(&ansi_string);
},
}
}
Ok(format_string)
}