pistonite_cu_proc_macros/lib.rs
1use pm::pre::*;
2
3/// **For the Command Line Interface feature set,
4/// please refer to the [`cu::cli`](../pistonite-cu/cli/index.html) module.**
5///
6/// This is the documentation for the `#[cu::cli]` macro.
7///
8/// By annotating the main function, this macro generates
9/// a shim that will reference the `cu::cli::Flags` command line
10/// arguments and initialize logging, printing, and prompting
11/// systems accordingly.
12///
13/// The main function can be async or sync. It should
14/// return a `cu::Result`
15/// ```rust,ignore
16/// #[cu::cli]
17/// fn main(flags: cu::cli::Flags) -> cu::Result<()> {
18/// cu::debug!("flags are {flags:?}");
19/// Ok(())
20/// }
21/// ```
22///
23/// To also define your own flags using the [`clap`](https://docs.rs/clap)
24/// crate, define a CLI struct that derives `clap::Parser`.
25/// Note the prelude import (`cu::pre::*`) automatically
26/// brings `clap` into scope. You don't even need to add it
27/// to `Cargo.toml`!
28///
29/// Make sure to `#[clap(flatten)]` the flags into your struct.
30///
31/// ```rust,ignore
32/// # use pistonite_cu as cu;
33/// use cu::pre::*;
34/// /// My program
35/// ///
36/// /// This is my program, it is very good.
37/// #[derive(clap::Parser, Clone)]
38/// struct Args {
39/// /// Input of the program
40/// #[clap(short, long)]
41/// input: String,
42/// /// Output of the program
43/// #[clap(short, long)]
44/// output: Option<String>,
45/// #[clap(flatten)]
46/// inner: cu::cli::Flags,
47/// }
48/// ```
49/// Now, to tell `cu` where to look for the flags,
50/// specify the name of the field with `flags = "field"`
51/// ```rust,ignore
52/// // use the flags attribute to refer to the cu::cli::Flags field inside the Args struct
53/// #[cu::cli(flags = "inner")]
54/// fn main(args: Args) -> cu::Result<()> {
55/// cu::info!("input is {}", args.input);
56/// cu::info!("output is {:?}", args.output);
57/// Ok(())
58/// }
59/// ```
60///
61/// Alternatively, implement `AsRef<cu::cli::Flag>` for your struct.
62///
63/// ```rust,ignore
64/// # use pistonite_cu as cu;
65/// use cu::pre::*;
66/// #[derive(clap::Parser, Clone)]
67/// struct Args {
68/// input: String,
69/// #[clap(flatten)]
70/// inner: cu::cli::Flags,
71/// }
72/// impl AsRef<cu::cli::Flags> for Args {
73/// fn as_ref(&self) -> cu::cli::Flags {
74/// &self.inner
75/// }
76/// }
77/// #[cu::cli]
78/// fn main(_: Args) -> cu::Result<()> {
79/// Ok(())
80/// }
81/// ```
82///
83/// Or enable the `derive` feature and derive `AsRef` (via [`derive_more`](https://docs.rs/derive_more)).
84/// ```rust,ignore
85/// # use pistonite_cu as cu;
86/// use cu::pre::*;
87/// #[derive(clap::Parser, Clone, AsRef)]
88/// struct Args {
89/// input: String,
90/// #[clap(flatten)]
91/// #[as_ref]
92/// inner: cu::cli::Flags,
93/// }
94/// #[cu::cli]
95/// fn main(_: Args) -> cu::Result<()> {
96/// Ok(())
97/// }
98/// ```
99///
100/// The attribute can also take a `preprocess` function
101/// to process flags before initializing the CLI system.
102/// This can be useful to merge multiple Flags instance
103/// in the CLI. Note that the logging/printing system
104/// will not work during the preprocess.
105///
106/// ```rust,ignore
107/// # use pistonite_cu as cu;
108/// use cu::pre::*;
109///
110/// #[derive(clap::Parser)]
111/// struct Args {
112/// #[clap(subcommand)]
113/// subcommand: Option<Command>,
114/// #[clap(flatten)]
115/// inner: cu::cli::Flags,
116/// }
117/// impl Args {
118/// fn preprocess(&mut self) {
119/// // merge subcommand flags into top level flags
120/// // this way, both `-v foo` and `foo -v` will work
121/// if let Some(Command::Foo(c)) = &self.subcommand {
122/// self.inner.merge(c);
123/// }
124/// }
125/// }
126/// impl AsRef<cu::cli::Flags> for Args {
127/// fn as_ref(&self) -> &cu::cli::Flags {
128/// &self.inner
129/// }
130/// }
131/// #[derive(clap::Subcommand)]
132/// enum Command {
133/// Foo(cu::cli::Flags),
134/// }
135/// #[cu::cli(preprocess = Args::preprocess)]
136/// fn main(args: Args) -> cu::Result<()> {
137/// Ok(())
138/// }
139/// ```
140///
141#[proc_macro_attribute]
142pub fn cli(attr: TokenStream, input: TokenStream) -> TokenStream {
143 pm::flatten(cli::expand(attr, input))
144}
145mod cli;
146
147/// Derive the [`cu::Parse`](../pistonite-cu/trait.Parse.html) trait
148#[proc_macro_derive(Parse)]
149pub fn derive_parse(input: TokenStream) -> TokenStream {
150 pm::flatten(derive_parse::expand(input))
151}
152mod derive_parse;
153
154/// Attribute macro for wrapping a function with an error context
155///
156/// See the [tests](https://github.com/Pistonite/cu/blob/main/packages/copper/tests/context.rs)
157/// for examples
158#[proc_macro_attribute]
159pub fn context(attr: TokenStream, input: TokenStream) -> TokenStream {
160 pm::flatten(context::expand(attr, input))
161}
162mod context;