use proc_macro2::TokenStream;
use syn::{
Attribute, Expr, ExprLit, FieldValue, Ident, LitStr, parse::Parse, punctuated::Punctuated,
spanned::Spanned, token::Comma,
};
use crate::{
args::{self, Arg},
hook, key,
};
pub fn template_hole_with_hook(
attrs: &[Attribute],
hole: &ExprLit,
interpolated: bool,
captured: bool,
) -> syn::Result<TokenStream> {
let interpolated_expr = if interpolated {
quote!(.__private_interpolated())
} else {
quote!(.__private_uninterpolated())
};
let captured_expr = if captured {
quote!(.__private_captured())
} else {
quote!(.__private_uncaptured())
};
let hole = key::key_with_hook(&[], hole, interpolated, captured);
hook::eval_hooks(
&attrs,
syn::parse_quote_spanned!(hole.span()=>
#[allow(unused_imports)]
{
use emit::__private::{__PrivateFmtHook as _, __PrivateInterpolatedHook as _};
emit::template::Part::hole_str(#hole).__private_fmt_as_default()#interpolated_expr #captured_expr
}
),
)
}
pub struct Args {
pub flags: String,
}
impl Parse for Args {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
if input.peek(LitStr) {
let flags: LitStr = input.parse()?;
return Ok(Args {
flags: flags.value(),
});
}
let mut flags = Arg::str("flags");
args::set_from_field_values(
input.parse_terminated(FieldValue::parse, Token![,])?.iter(),
[&mut flags],
)?;
Ok(Args {
flags: flags.take_or_default(),
})
}
}
impl Args {
fn to_format_args(&self) -> String {
if self.flags.is_empty() {
"{}".to_owned()
} else {
format!("{{:{}}}", self.flags)
}
}
}
pub struct RenameHookTokens {
pub args: TokenStream,
pub expr: TokenStream,
}
pub fn rename_hook_tokens(opts: RenameHookTokens) -> Result<TokenStream, syn::Error> {
hook::rename_hook_tokens(hook::RenameHookTokens {
name: "fmt",
target: "values in templates or event macros",
args: opts.args,
expr: opts.expr,
predicate: |ident: &str| {
ident.starts_with("__private_fmt") || ident.starts_with("__private_interpolated")
},
to: move |args: &Args, ident: &Ident, _: &Punctuated<Expr, Comma>| {
if ident.to_string().starts_with("__private_interpolated") {
return None;
}
let fmt = args.to_format_args();
let to_ident = quote!(__private_fmt_as);
let to_arg = quote!(emit::template::Formatter::new(|v, f| {
emit::__private::core::write!(f, #fmt, v)
}));
Some((to_ident, to_arg))
},
})
}