clawless_derive/
lib.rs

1#![cfg_attr(not(doctest),doc = include_str!("../README.md"))]
2#![warn(missing_docs)]
3
4use proc_macro::TokenStream;
5use quote::quote;
6use syn::{parse_macro_input, ItemFn};
7
8use crate::app::AppGenerator;
9use crate::command::CommandGenerator;
10use crate::inventory::InventoryGenerator;
11
12mod app;
13mod command;
14mod inventory;
15
16/// Generate a Clawless application
17///
18/// This macro generates an empty Clawless application that can be extended with
19/// subcommands. It is supposed to be called in a module called `commands`,
20/// with commands defined in submodules.
21///
22/// # Example
23///
24/// ```rust,ignore
25/// mod commands {
26///     clawless::app!();
27/// }
28/// ```
29#[proc_macro]
30pub fn app(_input: TokenStream) -> TokenStream {
31    let app_generator = AppGenerator::new();
32    app_generator.app_function().into()
33}
34
35/// Add a command to a Clawless application
36///
37/// This macro attribute can be used to register a function as a (sub)command in
38/// Clawless application. The name of the function will be used as the name of
39/// the command, and it will be automatically registered as a subcommand under
40/// its parent module.
41///
42/// Command functions expect a single argument, which is a `clap::Args` struct
43/// with arguments that will be passed to the command.
44///
45/// # Example
46///
47/// ```rust,ignore
48/// use clap::Args;
49/// use clawless::command;
50///
51/// #[derive(Debug, Args)]
52/// pub struct CommandArgs {
53///     #[arg(short, long)]
54///     name: String,
55/// }
56///
57/// #[command]
58/// pub async fn command(args: CommandArgs) {
59///     println!("Running a command: {}", args.name);
60/// }
61/// ```
62#[proc_macro_attribute]
63pub fn command(attrs: TokenStream, input: TokenStream) -> TokenStream {
64    let input_function = parse_macro_input!(input as ItemFn);
65
66    let command_generator = CommandGenerator::new(attrs.into(), input_function.clone());
67    let inventory_generator = InventoryGenerator::new(&command_generator);
68
69    let inventory_struct_for_subcommands = inventory_generator.inventory();
70    let submit_command_to_inventory = inventory_generator.submit_command();
71
72    let initialization_function_for_command = command_generator.initialization_function();
73    let wrapper_function_for_command = command_generator.wrapper_function();
74
75    let output = quote! {
76        #inventory_struct_for_subcommands
77
78        #input_function
79
80        #initialization_function_for_command
81
82        #wrapper_function_for_command
83
84        #submit_command_to_inventory
85    };
86
87    output.into()
88}