use proc_macro::TokenStream;
use proc_macro2::{Ident, Span};
use quote::quote;
use syn::{parse_macro_input, ItemFn, PatType, Receiver};
#[proc_macro_attribute]
pub fn clap_main(_attr: TokenStream, item: TokenStream) -> TokenStream {
let mut f = parse_macro_input!(item as ItemFn);
let item_type = f
.sig
.inputs
.first()
.expect("Need exactly one argument to the function");
let renamed_main = Ident::new("clap_main_fn", Span::call_site());
f.sig.ident = renamed_main.clone();
let clap_options_type = match item_type {
syn::FnArg::Receiver(Receiver { ty, .. }) | syn::FnArg::Typed(PatType { ty, .. }) => {
match ty.as_ref() {
syn::Type::Path(ty) => ty.path.clone(),
_ => panic!("Expected a path type"),
}
}
};
let main_return_type = f.sig.output.clone();
quote! {
#f
pub fn main() #main_return_type {
use clap::Parser;
use std::io::Write;
let args = match #clap_options_type::try_parse() {
Ok(args) => args,
Err(e) => {
writeln!(&mut std::io::stderr(), "{e}").expect("Could not write to stderr!");
std::process::exit(-1);
}
};
#renamed_main(args)
}
}
.into()
}