clap
clap copied to clipboard
derive feature: an attribute to add a prefix to all arg names in a struct, for use with flatten
Please complete the following tasks
- [X] I have searched the discussions
- [X] I have searched the open and rejected issues
Clap Version
3.1.2
Describe your use case
I work on a large Rust project that has many different modules which have command-line options to add to the program. For readability and to reduce collisions, we prefix the name of the flags with the name of the module it belongs to. For example, we have a module log
, with a struct with several fields, and each of them has a corresponding flag like --log.whatever
. The main program then combines all these together into one big options struct.
We've been using docopt, which lets you omit the prefix from the struct field name at least, but you still have to type it manually in the help text for each flag, which doesn't scale well.
Clap lets me use #[clap(flatten)]
to separate these options into their own struct like I've been doing with docopt, but I'd have to add the prefix to all the field names, which then leaks into all the code that accesses it (yuck). It also doesn't let me preserve the --prefix.name
argument style we've already established.
What I'd like is some way to add a prefix to all the arguments used with a particular struct.
Describe the solution you'd like
A similar feature was discussed in https://github.com/clap-rs/clap/issues/3117, which proposed a prefix
attribute to be placed alongside flatten
, at the point of the sub-struct's inclusion into the main one. This was ultimately dismissed as being ugly and/or difficult to implement given how the derive code works.
This proposal is to attach the attribute to the sub-struct itself, which is much more easily implemented, and, at least for my use case, works just as well.
I have an implementation ready (https://github.com/wfraser/clap/tree/flatten-prefix) which makes it another type of casing style, using the rename_all
attribute. The precise syntax is #[clap(rename_all = "prefix:foo")]
. It can be combined with another prefix style as well: #[clap(rename_all = "prefix:foo,snake")]
.
Example:
#[derive(Parser, Debug, PartialEq)]
struct Main {
#[clap(long)]
some_string: String,
#[clap(flatten)]
foo_args: Foo,
#[clap(flatten)]
bar_args: Bar,
}
#[derive(Parser, Debug, PartialEq)]
#[clap(rename_all = "prefix:foo", next_help_heading = "Foo options")]
struct Foo {
#[clap(long)]
some_param: String,
}
#[derive(Parser, Debug, PartialEq)]
#[clap(rename_all = "prefix:bar,pascal", next_help_heading = "Bar options")]
struct Bar {
#[clap(long)]
another_param: String,
}
help text:
clap-nesting
USAGE:
clap-nesting [OPTIONS]
OPTIONS:
-h, --help Print help information
--some-string <SOME_STRING>
Foo options:
--foo.some-param <SOME_PARAM>
Bar options:
--bar.AnotherParam <ANOTHER_PARAM>
If this approach looks acceptable, I can submit my branch as a PR.
Alternatives, if applicable
No response
Additional Context
No response