use crate::*;
use inflector::Inflector;
use proc_macro2::TokenStream;
use quote::quote;
pub(crate) struct Configure<'a>(&'a ClapItemData);
pub(crate) fn item<'a>(item: &'a ClapItemData) -> Configure<'a> {
Configure(item)
}
impl<'a> quote::ToTokens for Configure<'a> {
fn to_tokens(&self, tokens: &mut TokenStream) {
match &self.0 {
ClapItemData::Struct(s) => {
for field in s.fields.iter() {
let name = field.name();
let ty = &field.ty;
let help = match &field.help {
None => quote! { None },
Some(v) => quote! { Some(#v) },
};
(quote! {{
<#ty as ::preftool_clap::ClapConfig>::configure(app, context.child(#name), #help);
}})
.to_tokens(tokens);
}
}
ClapItemData::Enum(e) => {
(quote! {
assert!(!context.is_list(), "Enums does not work in list contexts.");
assert!(!context.is_variant(), "Enums does not work in variant contexts.");
let context = context.variant();
})
.to_tokens(tokens);
let mut sub_app_names = Vec::with_capacity(e.variants.len());
for variant in e.variants.iter() {
let variant_name = &variant.name;
let sub_app_name = format!("{}_app", variant_name.to_string().to_snake_case());
let sub_app_name = Ident::new(sub_app_name.as_ref(), variant_name.span());
sub_app_names.push(sub_app_name.clone());
let inner = ClapItemData::Struct(variant.clone());
let inner = Configure(&inner);
(quote! {
let #sub_app_name = {
let mut app_holder = ::preftool_clap::AppBuilder::new();
let app = &mut app_holder;
#inner
app_holder
};
})
.to_tokens(tokens);
}
(quote! {
app.variants(&[
#(#sub_app_names,)*
]);
})
.to_tokens(tokens);
}
}
}
}