Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding subcommands to a pre-existing structopt #327

Closed
cecton opened this issue Jan 14, 2020 · 10 comments · Fixed by #329
Closed

Adding subcommands to a pre-existing structopt #327

cecton opened this issue Jan 14, 2020 · 10 comments · Fixed by #329

Comments

@cecton
Copy link
Contributor

cecton commented Jan 14, 2020

@CreepySkeleton I think that's the missing feature: we would like to be able to extend an enum of subcommands from another crate.

To be clear it doesn't have to use flatten in this fashion. But it would be nice if there would be a way to add a subcommand to an existing list of subcommands. Unfortunately Rust won't allow adding variants in the enum, the usual way to deal with this is this: https://stackoverflow.com/questions/25214064/can-i-extend-an-enum-with-additional-values#25214677 so there should be a way to tell structopt that the subcommands in the variant (BaseCli::Command1) should be at the same level than the subcommands in the parent enum (ExtendedCli::Command2).

This issue relates to #20 but is different as this is importing a StructOpt from a different crate.

This issue relates to #307

Code

use structopt::StructOpt;

// This come from another crate
#[derive(Debug, StructOpt)]
enum BaseCli {
    Command1(Command1),
}

#[derive(Debug, StructOpt)]
struct Command1 {
    argument1: String,
}

// This is the structopt for this crate
#[derive(Debug, StructOpt)]
enum ExtendedCli {
    #[structopt(flatten)]
    BaseCli(BaseCli),
    Command2(Command2),
}

#[derive(Debug, StructOpt)]
struct Command2 {
    argument2: String,
}

fn main() {
    let cli = ExtendedCli::from_args();
    println!("{:?}", cli);
}

Expected Result

test-struct-opt 0.1.0

USAGE:
    test-struct-opt <SUBCOMMAND>

FLAGS:
    -h, --help       Prints help information
    -V, --version    Prints version information

SUBCOMMANDS:
    command1
    command2
    help        Prints this message or the help of the given subcommand(s)

Actual Result

error: flatten is only allowed on fields
  --> src/main.rs:15:17
   |
15 |     #[structopt(flatten)]
   |                 ^^^^^^^
@CreepySkeleton
Copy link
Collaborator

CreepySkeleton commented Jan 14, 2020

I would go for subcommand here instead of flatten, but... don't know, both names are good enough.

Also, I would like it to be a part of clap_derive, I'm not going to work on this personally because... come on, let's get clap_derive working already!

@TeXitoi
Copy link
Owner

TeXitoi commented Jan 14, 2020

Can't we do this kind of thing with #314 and reparsing the Vec into your extended opt using from_iter?

@cecton
Copy link
Contributor Author

cecton commented Jan 14, 2020

Actually this ticket seems totally related to #130

@CreepySkeleton
Copy link
Collaborator

CreepySkeleton commented Jan 14, 2020

#130 is already implemented in #314 . And no, this is different.

@TeXitoi
Copy link
Owner

TeXitoi commented Jan 14, 2020

That's not the asked syntax, but it might resolve the needed feature.

@cecton
Copy link
Contributor Author

cecton commented Jan 14, 2020

I'm afraid it won't because I can't just import an instantiated Vec from one crate to another...

@CreepySkeleton
Copy link
Collaborator

Not really. What he's asking for is "flatten subcommands in the same manner we're flattening structs", he's not asking to "accept every possible subcommand".

@cecton
Copy link
Contributor Author

cecton commented Jan 14, 2020

*she

But yes this is very different

@CreepySkeleton
Copy link
Collaborator

@cecton sorry, I don't really look at avatars...

@TeXitoi
Copy link
Owner

TeXitoi commented Jan 14, 2020

The feature needed is "allow to have an Enum for extended subcommand". While maybe less ergonomic, it would be possible with something like that:

let opt = BaseOpt::from_args();
let extended = match &opt.cmd {
    Some(Extended(v)) => Some(ExtendedOpt::from_iter(v)),
    _ => None,
};

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants