preftool-clap-derive 0.2.0

Configuration library for CLI tools/servers.
Documentation
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);
      }
    }
  }
}