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

Custom argument display groups #805

Closed
RazrFalcon opened this issue Jan 3, 2017 · 16 comments
Closed

Custom argument display groups #805

RazrFalcon opened this issue Jan 3, 2017 · 16 comments
Labels
A-help Area: documentation, including docs.rs, readme, examples, etc... E-hard Call for participation: Experience needed to fix: Hard / a lot

Comments

@RazrFalcon
Copy link

Hello. I want to group options into categories, like this. See: Elements, Attributes, Paths, etc.

It there a way to do this in the current clap version or is it will be implemented?

@kbknapp
Copy link
Member

kbknapp commented Jan 3, 2017

Unfortunately it's not supported at this time unless you simply write the help message yourself (copy/paste your example into App::help). That's not a horrible answer, as you still get all the benefits of clap like context sensitive usage statements/errors, validations, aliases, relationships, etc. But you do miss out on having the help generated/updated for you. If that doesn't sound like something you'd want to do, there's also docopt which is another argv parser that basically takes your help message as you have written and uses that to generate the valid arguments.

For completeness sake, you could force it to happen in clap, but it'd be very hacky even though functional. If you want to see, I can give you a demo 😉


Having said all this, it'd be possible for me to add this is feature, and I'd be curious to know if others want this same thing. I personally think it'd be somewhat of a pain to enter, arg.help_group("foo") for every arg unless you're using a macro (which many actually do). Of course, I could also add an App::help_group("group", &["arg1", "arg2", "arg3"]) but you'd still risk not keeping that list up to date as your list of args changes and evolves.

I'd like to hear some thoughts on the matter :)

@kbknapp
Copy link
Member

kbknapp commented Jan 3, 2017

Possibly relates to #686

@RazrFalcon
Copy link
Author

That's not a horrible answer

Well... it's not, since it what I'm doing right now.

I don't really know what kind of API I want, but since I prefer that options should be in a specific order (I forgot to mention this in OP. In example, there are not only groups that matter, but also an order of options inside. Yes, it's visual only and do not change parsing in any way.), so I guess something like:
Arg::group_to("group_name").group_pos(1)
but it's looks to specific for my case and I don't know it anyone will want to use it.

I'll think about how it can be implemented, API-wise. Sounds like keeping an own help file is the easiest way...

@kbknapp
Copy link
Member

kbknapp commented Jan 3, 2017

The order of arguments can already be specified manually (using Arg::display_order), or placed in the order that you define them (using AppSettings::DeriveDisplayOrder)

In fact, the hack I hinted at uses those options, along with afew others to trick the generated help message.

@kbknapp
Copy link
Member

kbknapp commented Jan 4, 2017

Here's what I meant by the hack to make it work

Is this any better than copy/pasting the help? I know it's looks uglier, but it has the benefit of never falling out of date. Granted, there are drawbacks such as the "can't have a default here" portions. Although there are ways around that; such as unless you have a really good reason not to (like porting a well known CLI), it's considered better UX to use flags instead of options for the true/false values. This would also remove the need for defaults. If you do need to use an option for true/false you could just use value_of("option").unwrap_or(default) for those 4 or so args which isn't too big a deal.

@RazrFalcon
Copy link
Author

DeriveDisplayOrder is a good stuff, I didn't notice it.

Adding newlines to help() is an interesting idea, sadly I need default values. Maybe there is a way to insert dummy/custom text between args?

About true/false: yes, I don't like it either, but most of options should be enabled by default and I don't know is it possible for flags. Only way I see is too name default options as keep-*(or similar) and disabled as remove-*(or similar). So flag will able to disable enabled options and enable disabled. But then to change the default value I have to rename it...

@kbknapp
Copy link
Member

kbknapp commented Jan 4, 2017

About true/false

I think convention is to use --no-* for something that defaults to true and --* for something that defaults to false.

Such as --remove-comments <FLAG> [defualt: true] -> --comments, or --remove-gradient-attributes <FLAG> [defualt: false] -> --no-gradient-attributes

Another option is to group like functionality into a single option. For example, all the "removal" flags become:

--remove-element <ELEMENT>...    Removes a particular element [values: comments, declarations,
                                 nonsvg-elements, unused-defs, title, desc, metadata, 
                                 dupl-lineargradient, dupl-radialgradient, dupl-fegaussianblur, 
                                 invalid-stops, invisible-elements]

Then you could set this up to allow --remove-element <element1> <element2> or --remove-element <element1> --remove-element <element2> depending on whichever you prefer.

We're digressing from the original topic, but that's fine because I enjoy CLI UX 😄


I'm going to play with adding, "display groups" and see how it feels. I'll post back here with an example once I have it working.

@RazrFalcon
Copy link
Author

--no-* is a great idea, it's like in GCC, but is such behavior handled by clap? Or is there should be two flags for each option?

I thought about groping, but it's harder to generate, from GUI for example, and also it's harder to write, because it will be one, very long line. And I'm already have more than 50 options. In current version I can separate each option with the \ (for new lines). Which is useful.

Actual problem with flags, is that most of them are enabled by default. So it will be just a bunch of keys which disables staff, like: --keep-*, --skip-*, etc. Which is counter-intuitive.

PS: I don't mind discussing CLI UX, since there are not mach articles about it. And docopt doc, which you mention, is one of them. Also there are not much applications with a lot of CLI arguments. I look up for: gcc, clang, mpv. And they all simply shows alphabetically sorted list of options. Some exceptions are qmake, which uses grouping just like me. But the way they do this is not really interesting. And eix, but they do the same.

@kbknapp
Copy link
Member

kbknapp commented Jan 4, 2017

is such behavior handled by clap? Or is there should be two flags for each option?

No, if an argument defaults to true, that means the functionality is "on" by default. So the user not passing the flag is consent for that action to take place (default true), but then you have a --no-* to change the default functionality, or turn off that functionality. So you only need one flag per item.

Here's the comparison for items defaulting to true:

New Previous
nothing --option true
--no-option --option false

The inverse also applies. Something that defaults to false, doesn't do some particular action. Then supplying --action turns that feature back on.

New Previous
--option --option true
nothing --option false

It makes your CLI more concise, and help messages are easier to read as well.

grouping [..] it's harder to write, because it will be one, very long line.

clap handles this part of your help message for you (Look up Arg::possible_values, work proxy is preventing me from linking to it). So no writing required (other than specifying the options that are valid). You can also prevent them from being printed in the help message if you think it's too long via AppSettings::HidePossibleValues

Actual problem with flags, is that most of them are enabled by default. So it will be just a bunch of keys which disables staff, like: --keep-, --skip-, etc. Which is counter-intuitive.

I think it's actually the opposite. And your help message for that flag can say, "By default svgcleaner removes X, this flag disables that removal" Because the other way around, what you'll end up seeing is people running svgcleaner --option true even though it's the default, they'll think you have to specify something, "Or else it wouldn't be an option."

There's other oddities as well, such as users forgetting whether it's true/false, yes/no, on/off, y/n or any other variant. So you may end creating parser to allow any of the above, or translating a true/false instead of simply checking if --no-* was used or not. Done.

I'm not saying it's wrong, as it can totally be done with true/false it's just slightly harder :)

I don't mind discussing CLI UX, since there are not mach articles about it.

I'm actually working on releasing an mdBook (same as Rust book) about CLI UX in general, and using Rust, since it's something I really enjoy working on and thinking about. It'll be a while before it's ready though.

@RazrFalcon
Copy link
Author

Thanks. I'll keep thinking about it.

Waiting for a book.

@kbknapp kbknapp changed the title Custom options grouping categories Custom argument display groups Jan 30, 2017
@kbknapp
Copy link
Member

kbknapp commented Apr 5, 2017

I did some playing with this and ergonomics aren't great. It's also a huge rework of how clap writes a help message and thus I'm gonna have to close this for now as it's not feasible to include in the current version. Perhaps 3.x will make this more doable, but it's still unlikely.

I am, however, still open to suggestions on how this could work.

@kbknapp kbknapp closed this as completed Apr 5, 2017
@RazrFalcon
Copy link
Author

Ok. I've ended up thinking that a custom help is the best solution.

@kbknapp
Copy link
Member

kbknapp commented Apr 5, 2017

Bah, I'm gonna keep this open. It is something I'd like to have. It probably won't happen soon, but I do want this style of feature.

@kbknapp kbknapp reopened this Apr 5, 2017
@kbknapp kbknapp added C: args A-help Area: documentation, including docs.rs, readme, examples, etc... E-hard Call for participation: Experience needed to fix: Hard / a lot and removed T: RFC / question labels Apr 5, 2017
@rtsuk
Copy link

rtsuk commented Aug 8, 2017

Adding my vote for this feature. My Fuchsia-specific cargo wrapper Fargo could really benefit from it.

@kbknapp
Copy link
Member

kbknapp commented Aug 9, 2017

I'm trying to get 3.x out the door in the coming weeks so I can start knocking out all the current feature/bug reports. This particular feature is high on my list though 😉

@kbknapp kbknapp mentioned this issue Feb 15, 2018
87 tasks
kbknapp added a commit to willmurphyscode/clap-rs that referenced this issue Apr 4, 2018
Args can now be added to custom help sections. This breaks up the builder pattern a little by adding help section declarations inline, but it's the most intuitive method and doesn't require strange nesting that feels awkward.

```rust
app::new("foo")
    .arg(Arg::with_name("arg1")) // under normal headers
    .help_heading("SPECIAL")
    .arg(Arg::with_name("arg2")) // under SPECIAL: heading
```

Closes clap-rs#805
kbknapp added a commit to willmurphyscode/clap-rs that referenced this issue Apr 4, 2018
Args can now be added to custom help sections. This breaks up the builder pattern a little by adding help section declarations inline, but it's the most intuitive method and doesn't require strange nesting that feels awkward.

```rust
app::new("foo")
    .arg(Arg::with_name("arg1")) // under normal headers
    .help_heading("SPECIAL")
    .arg(Arg::with_name("arg2")) // under SPECIAL: heading
```

Closes clap-rs#805
@kbknapp
Copy link
Member

kbknapp commented Apr 4, 2018

Closed with #1211 (will be released in v3)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-help Area: documentation, including docs.rs, readme, examples, etc... E-hard Call for participation: Experience needed to fix: Hard / a lot
Projects
None yet
Development

No branches or pull requests

3 participants