Currently, to support an enum field, a user has to
arg_enumraw to list possible valuesraw to list default valueInstead being able to do this would be nice
#[derive(StructOpt)]
struct Opt {
#[structopt(long="format)]
format: Format,
}
#[derive(StructOpt)]
enum Format {
Txt,
Md,
Html,
}
For me, that's not StructOpt job, it should be clap's or an external crate as strum.
Some kind of parse(try_from_enum) can be added to make integration in StructOpt more easy.
In which case do you need raw for default value?
Could you clarify what you do feel structopt's job is?
I feel like using an enum for an argument's choices is a reasonably common enough use case. Probably 1 in 3 CLIs I write (I do a lot of tooling at my job) involve doing this. Currently, to use an arg enum, you have to do this:
#[structopt(long = "format",
raw(possible_values = "&Format::variants()", case_insensitive = "true"),
raw(default_value = "DEFAULT_FORMAT"))]
pub format: Format,
(the raw on default_value could be simplified in other cases, I just needed it to be platform-specific)
How to use the raw API is non-obvious and I've frequently gotten crashes (panics?) in doing so such that I've shied away from it where possible. Maybe I'm just spoiled by serde but I look at this and know that the macros have sufficient information to streamline this so I can just express what I need through normal Rust means, like enums, Default, etc and the macros pick up on the boiler plate that in some cases can be obtuse.
For me, structopt's job is to change a struct into a clap::App using custom derive, and reparse it back.
Serialization and deserialisation of enum is above that, it can be used without StructOpt directly with clap, and there is also a lot of other usages outside of cli argument parsing.
But I agree that it's a common need for cli argument, and thus having some sugar (as my proposed parse(try_from_enum) to generate the boilerplate) might be a good idea. But we need a commonly accepted interface to do that.
Oh, I missed your other comment about try_from_enum (I think it was posted while I was writing mine).
In which case do you need raw for default value?
I've since answered this
Some kind of parse(try_from_enum) can be added to make integration in StructOpt more easy.
an ArgEnum already has a FromStr, so this wouldn't be needed. The issue is more so dropping to raw for listing possible values.
Serialization and deserialisation of enum is above that, it can be used without StructOpt directly with clap, and there is also a lot of other usages outside of cli argument parsing.
I'm mixed. As a user, this is all a part of me describing my CLI, so it feels like it'd be a part of StructOpt. Also as a user, sometimes my enums are at a layer below my CLI and I don't want to have that layer coupled to a CLI crate if I'm even in position to modify the code and if it makes sense in context (newtypes to the rescue?). It would be good to have a general enum crate that structopt is interoperating with and possible re-exporting. In my opinion, the interoperating is key.
For anyone needing a quick fix until this issue is properly resolved, I've written a small derive crate that ought to work for simple use cases: https://github.com/Palladinium/arg-enum
I don't see how your arg-enum crate is better than strum. With strum, you have EnumVariantNames to give the possible_values to clap, and a lot of other functionnalities.
Yeah, you're right - I hadn't looked into strum thinking it was another cli parser library along the lines of clap and paw, and now I wish I had before sitting down to write my own implementation :laughing:
With strum, and the new raw syntax, you can now:
use structopt::StructOpt;
use strum::{EnumString, EnumVariantNames, VariantNames};
const DEFAULT: &str = "txt";
#[derive(StructOpt, Debug)]
struct Opt {
#[structopt(
long,
possible_values = Format::VARIANTS,
case_insensitive = true,
default_value = DEFAULT,
)]
format: Format,
}
#[derive(EnumString, EnumVariantNames, Debug)]
#[strum(serialize_all = "kebab_case")]
enum Format {
Txt,
Md,
Html,
}
fn main() {
println!("{:?}", Opt::from_args());
}
So, OK to close this?
Feel free to reopen if you think something else should be done.
Most helpful comment
Oh, I missed your other comment about
try_from_enum(I think it was posted while I was writing mine).I've since answered this
an ArgEnum already has a
FromStr, so this wouldn't be needed. The issue is more so dropping to raw for listing possible values.I'm mixed. As a user, this is all a part of me describing my CLI, so it feels like it'd be a part of StructOpt. Also as a user, sometimes my enums are at a layer below my CLI and I don't want to have that layer coupled to a CLI crate if I'm even in position to modify the code and if it makes sense in context (newtypes to the rescue?). It would be good to have a general enum crate that structopt is interoperating with and possible re-exporting. In my opinion, the interoperating is key.