cli_errors_macros/
lib.rs

1#![feature(proc_macro_diagnostic)]
2
3use proc_macro::TokenStream;
4
5use quote::quote;
6use syn::{parse_macro_input, ItemFn};
7
8/// Proc macro to correctly handle the exit code and error message returned from
9/// [CliResult][cli_errors::CliResult].
10#[proc_macro_attribute]
11pub fn main(_args: TokenStream, input: TokenStream) -> TokenStream {
12    let input = parse_macro_input!(input as ItemFn);
13
14    if input.sig.ident != "main" {
15        input
16            .sig
17            .ident
18            .span()
19            .unwrap()
20            .error("cli_errors::main must be used on the main method.")
21            .emit();
22    }
23
24    let wrapped_code = input.block;
25    TokenStream::from(quote! {
26        fn main() {
27            if let Err(e) = wrapped_main() {
28                if let Some(source) = e.source {
29                    eprintln!("{:?}", source);
30                }
31                std::process::exit(e.code);
32            }
33        }
34
35        fn wrapped_main() -> cli_errors::CliResult<()> {
36            #wrapped_code
37        }
38    })
39}