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

Have help subcommand show help for other subcommands #416

Closed
crumblingstatue opened this issue Feb 4, 2016 · 6 comments
Closed

Have help subcommand show help for other subcommands #416

crumblingstatue opened this issue Feb 4, 2016 · 6 comments
Labels
A-parsing Area: Parser's logic and needs it changed somehow. E-medium Call for participation: Experience needed to fix: Medium / intermediate

Comments

@crumblingstatue
Copy link

Right now, the auto generated help subcommand seems to ignore trailing arguments, even if
they are names of other subcommands.

What I expect is that it would show the help for the subcommand provided as an argument.
This is how for example Cargo (cargo help build) or Git (git help commit) work.

Example

A simple mock cargo

extern crate clap;

use clap::{App, AppSettings, SubCommand};

fn main() {
    App::new("cargo")
        .setting(AppSettings::SubcommandRequiredElseHelp)
        .about("Rust's mock package manager")
        .subcommand(SubCommand::with_name("build")
                        .about("Compile the current project")
                        .after_help("This is a mock cargo-build command.\nNot real."))
        .get_matches();
}

Help invocation

$ cargo-mock help
cargo 
Rust's mock package manager

USAGE:
    cargo-mock [FLAGS] [SUBCOMMAND]

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

SUBCOMMANDS:
    build    Compile the current project
    help     Prints this message

I want to know more about the build subcommand. The instinctive action is to invoke help with the subcommand name as the argument.

$ cargo-mock help build
cargo 
Rust's mock package manager

USAGE:
    cargo-mock [FLAGS] [SUBCOMMAND]

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

SUBCOMMANDS:
    build    Compile the current project
    help     Prints this message

Strange. It just prints the same thing as before.

What I expect to happen instead:

$ cargo-mock help build # (output was generated by cargo-mock build --help)
cargo-mock-build 
Compile the current project

USAGE:
    cargo-mock build [FLAGS]

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

This is a mock cargo-build command.
Not real.

If possible, it would be nice if it would error if an invalid subcommand was provided as an argument.
Cargo example:

$ cargo help biuld
no such subcommand

    Did you mean `build`?

@kbknapp
Copy link
Member

kbknapp commented Feb 4, 2016

Thanks for taking the time to file this!

This was actually a by-design decision. What you're looking for is implemented in reverse, i.e.

These two are identical

$ cargo-mock build help
$ cargo-mock build --help

While it would be possible to implement a setting to switch this, or allow switching to

$ cargo-mock help build

But I'd prefer that be an opt-in setting and not the default. This is what I'm thinking of in order to implement what you're talking about:

extern crate clap;

use clap::{App, AppSettings, SubCommand};

fn main() {
    App::new("cargo")
        .setting(AppSettings::SubcommandRequiredElseHelp)
        .setting(AppSettings::ReverseHelpSubcommand)
        .about("Rust's mock package manager")
        .subcommand(SubCommand::with_name("build")
                        .about("Compile the current project")
                        .after_help("This is a mock cargo-build command.\nNot real."))
        .get_matches();
}

The downside to this that while matching, once help is matched, you then half to consume the next argument and see if that matches an existing subcommand or not. It's not impossible, and it'd actually be pretty easy to implement, just something to consider.

We would also need to implement an appropriate error in case someone did

$ cargo-mock help

Which now that I'm thinking out loud about it would be simple - if ReverseHelpSubcommand (or whatever it gets called) is set, the help subcommand will get one required argument which must match a list of all given subcommands. Should be simple.

I'll mark this as new-setting, and play with some implementations.

Thanks again 👍

@kbknapp kbknapp added P4: nice to have A-parsing Area: Parser's logic and needs it changed somehow. E-medium Call for participation: Experience needed to fix: Medium / intermediate labels Feb 4, 2016
@kbknapp
Copy link
Member

kbknapp commented Feb 5, 2016

Other names for settings could be GlobalHelpSubcommand

Because what I imagine (and I'd be curious to hear your input) would be that the top level help would also essentially call the --help of any subcommand regardless of depth.

i.e. Imagine the following fictional subcommand structure

         cargo-mock
      /    |        \
 subcmd   help    do-stuff
 /   \               |
add   filter       list

Calling any of these would be valid:

$ cargo-mock help subcmd
$ cargo-mock help list
$ cargo-mock help filter
$ carg-mock help do-stuff
[ .. etc. ]

Or would you expect something like

$ cargo-mock help subcmd
$ cargo-mock help do-stuff list
$ cargo-mock help subcmd filter
$ carg-mock help do-stuff
[ .. etc. ]

Finally a third option is (which I dont' like as much)

$ cargo-mock help subcmd
$ cargo-mock do-stuff help list
$ cargo-mock subcmd help filter
$ carg-mock help do-stuff
[ .. etc. ]

@crumblingstatue
Copy link
Author

Because what I imagine (and I'd be curious to hear your input) would be that the top level help would also essentially call the --help of any subcommand regardless of depth.

Wouldn't that cause ambiguities if there are multiple subcommands of the same name?

e.g.

         cargo-mock
      /    |        \
 subcmd   help    do-stuff
 /   \               |
add   list         list

Another problem with postfix help subcommand is that subcommands can take positional arguments.

e.g. git rm help would remove a file called help instead of showing help, while git help rm works, and it's unambiguous.

@kbknapp
Copy link
Member

kbknapp commented Feb 5, 2016

Yes, you're correct option 1 wouldn't work. I realized that after posting it.

Post fix such as git rm help is already implemented and works today. It work by first checking if args match a subcommand, then accept them as arguments if they don't. So in order to pass a argument that also matches a subcommand, such as removing a file called help you'd have to do git rm -- help

I do however like the option of adding option 2 as an opt-in setting (only because the default is already set to postfix and changing it would be a breaking change). So git help subcmd list would be different from git help do-stuff list.

@kbknapp
Copy link
Member

kbknapp commented Mar 10, 2016

@Fiedzia Comments from #445

Having "list" subcommand, I'd like to display help for it when called as "help list"
(./prog help list). Currently it displays help for all available options and subcommands.
There seem to be settings NeedsSubcommandHelp for that, but its not documented, so I am not sure what it is supposed to do.

@kbknapp
Copy link
Member

kbknapp commented Mar 10, 2016

There seem to be settings NeedsSubcommandHelp for that, but its not documented, so I am not sure what it is supposed to do

@Fiedzia that is an internal setting which isn't really intended to be used by end users. I have a few other features to implement as well as this one, but I do plan on adding another setting to give the desired effect you're looking for 😉 Subscribe to this issue for updates on the feature.

kbknapp added a commit that referenced this issue Mar 15, 2016
… help subcommand

The `help` subcommand can now accept other subcommands as arguments to
display their help message. This is similar to how many other CLIs
already perform. For example:

```
$ myprog help mysubcmd
```

Would print the help message for `mysubcmd`. But even more, the `help`
subcommand accepts nested subcommands as well, i.e. a grandchild
subcommand such as

```
$ myprog help child grandchild
```

Would print the help message of `grandchild` where `grandchild` is a
subcommand of `child` and `child` is a subcommand of `myprog`.

Closes #416
homu added a commit that referenced this issue Mar 15, 2016
Issue 416 - Help subcommand accepts other subcommands as arguments

Merge *after* #449

Closes #416
homu added a commit that referenced this issue Mar 15, 2016
Issue 416 - Help subcommand accepts other subcommands as arguments

Merge *after* #449

Closes #416
@homu homu closed this as completed in #450 Mar 15, 2016
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-parsing Area: Parser's logic and needs it changed somehow. E-medium Call for participation: Experience needed to fix: Medium / intermediate
Projects
None yet
Development

No branches or pull requests

2 participants