use proc_macro::TokenStream;
use proc_macro2::{Span, 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, format_string_token.span())?;
let args = args.iter().map(|arg| arg.to_token_stream()).skip(1); let final_args = std::iter::once(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)?;
get_format_string_from_nodes(format_nodes, format_string_token.span())
}
fn get_format_string_from_nodes(
nodes: Vec<Node>,
original_span: Span,
) -> Result<TokenStream2, 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);
},
}
}
let format_string = LitStr::new(&format_string, original_span);
Ok(quote! { #format_string })
}