4 releases
new 0.1.3 | Dec 14, 2024 |
---|---|
0.1.2 | Dec 12, 2024 |
0.1.1 | Dec 9, 2024 |
0.1.0 | Dec 9, 2024 |
#219 in Procedural macros
542 downloads per month
35KB
656 lines
clappen
Flatten prefix for
clap
About
Integrate flatten prefix in your clap
parsers easily.
For more details, see:
Basic usage
use clap::Parser;
// export is the name of the macro generated
#[clappen::clappen(export = nested)]
// this mod definition does not appear in the
// final generated code, it's just a convenient
// wrapper for item definitions
mod unused_mod {
#[derive(clap::Args, Debug, Clone)]
pub struct Remote {
#[arg(env, long)]
id: String,
}
impl Remote {
fn a_function(&self) -> String {
// this `self` reference will be rewritten
// to field prefixed with `test`, ie `self.test_id`.
format!("id: {:?}", self.id)
}
}
}
// export is the name of the macro generated
#[clappen::clappen(export = prefixed_struct_generator)]
// mod definition not used too
mod unused_mod {
#[derive(clap::Parser, Debug, Clone)]
#[command(version, about)]
pub struct Options {
#[arg(env, long)]
url: String,
#[command(flatten)]
// `apply` is the macro export used
// (defined with `Remote` struct earlier)
// `prefix` is optional
#[clappen_command(apply = nested, prefix = "test")]
nested: Remote,
}
}
// generate the default struct without prefix
prefixed_struct_generator!();
fn main() -> Result<(), Box<dyn std::error::Error>> {
let _ = Options::parse();
Ok(())
}
Motivation
clap
unfortunately doesn't preserve field structure and prefix when flattening command
s.
See this issue for more in-depth explanation.
This crate allows fixing that while not requiring custom wrapper to the end clap
parser used. It's just a struct
macro generator that uses clap
default behaviour around arg
attribute.
See clap documentation for arg.
Limitations
-
Providing custom
long
orenv
to your fields is not supported. See Roadmap. -
References to fields with more than 1 nesting level won't work - like
self.my_field_level1.my_field_level2
.
Generally this should not be needed because you want to get something out of your reusable struct parser (and Rust might get in your way for borrow-related things).
If you still want to do that, you can write custom getter functions, and the renamed fields will be picked in theimpl
blocks. -
Probably some edge cases are not covered. For example,
clap
subcommand
s should be working, but it was not tested extensively as my use case is mainly reusingstruct
s in a mono repository fashion.
Roadmap
- Maybe add support for
long
/env
prefix injection.
This would make the integration withclap
tighter and the code more complicated though.
FAQ
Why is clappen_command
required with command(flatten)
even without prefix ?
Because people work with copy/paste.
For example, if this was not required, you might write this
#[clappen::clappen(export = nested)]
mod m {
#[derive(clap::Args)]
pub struct Nested {}
}
#[clappen::clappen(export = copyable_opts)]
mod m {
#[derive(clap::Parser)]
#[command(version, about)]
pub struct CopyableOptions {
#[command(flatten)]
nested: Nested,
}
}
But then if you copy paste this and turn it to a reusable parser, you get this
#[clappen::clappen(export = nested)]
mod m {
#[derive(clap::Args)]
pub struct Nested {}
}
#[clappen::clappen(export = copyable_opts)]
mod m {
#[derive(clap::Args)]
pub struct CopyableOptions {
#[command(flatten)]
nested: Nested,
}
}
#[clappen::clappen(export = parser)]
mod m {
#[derive(clap::Parser)]
#[command(version, about)]
pub struct Options {
#[command(flatten)]
// You're back to original issue, prefix is
// not maintained because `clappen` was not provided
opts: CopyableOptions,
}
}
Making clappen_command
required for all flatten
items avoids having to think about that when refactoring, you know that your prefix will be maintained even when using a single struct without a prefix.
Related stuff
- Project https://github.com/wfraser/clap_wrapper - implements prefix as well, but you can't reuse the struct with another prefix.
- Issue https://github.com/clap-rs/clap/issues/3513#issuecomment-1344372578 for the original idea.
Special thanks
- Big up to @dtolnay and its wonderful work in
syn
,quote
andpaste
.
The initial implementation usedpaste
but it is sadly now unmaintained. - Kudos to @epage for tireless maintaining
clap
and all its great features.
Dependencies
~245–700KB
~17K SLoC