Clap: Questions about zsh completion generated for ripgrep

Created on 22 Feb 2017  路  14Comments  路  Source: clap-rs/clap

Rust Version

N/A

Affected Version of clap

2.20.5

Expected Behavior Summary

Case 1:

rg <TAB>

will either complete flags, or complete nothing (because completing a search pattern isn't feasible)

Case 2:

rg somepattern <TAB>

will complete a path

Actual Behavior Summary

Case 1:

rg <TAB>

will produce two incorrect completions: PATTERN, PATH.

Case 2:

rg somepattern <TAB>

will produce flag/option completions (completion path is expected)

Steps to Reproduce the issue

Use ripgrep's build to generate the zsh completion script.

See: https://github.com/BurntSushi/ripgrep/blob/3f515afbb4cb3d22520729453bea5af050c0eb00/build.rs

Sample Code or Link to Sample Code

Here is the generated zsh completion for _rg:

https://gist.github.com/kastiglione/c9e09a89ca547d1f2288a62af7a8f439

Debug output

N/A

Reference

https://github.com/BurntSushi/ripgrep/issues/375

generator medium want to have enhancement

Most helpful comment

@kastiglione I hadn't seen the zsh-completions page before and they actually have some great tips for how I could improve the generated ZSH script. So thanks for that link!

Here's my thoughts on what I could realistically provide over the next few days (and longer):

  • [ ] Improve the positional/free argument indexes (I'd actually go so far as to say this would be a bug-fix)
  • [ ] Add some sort of CompletionValue enum with some generic options and be passed to a Arg::completion_value. Some of these values will be supported by some shells, but not others and that's OK.
  • [ ] Longer term (my time will be the limiting factor here) add #568 implemented via passing a function/closure to Arg::complete_with which has a different signature such as |clap::Shell, &ArgMatches, &str| -> String i.e. something with more context about what is trying to be completed (think completing different values based off what has already been passed to the command line in previous args)

All 14 comments

I think this has to do with ZSH completion scripts in general and not specifically how clap is generating them. Of course, if I'm wrong I'm more than happy to fix or be told where the actual error lies.

What I observe (appears correct to me):

$ rg <tab>
PAT

$ rg -<tab>
[.. list of flags/options]

$ rg --<tab>
[ .. list of flags/options that start with --]

Of course, completing paths is perhaps possible, but not everyone is accepting a path as an argument. Bash does however fallback to path completion when nothing else fits (I'm unsure of how to do this in Zsh though).

The final bit is I'm working on allowing arbitrary Rust code to run during a completion (Issue #568) but it hasn't been implemented yet. I'm also not sure which shells will allow this and which ones won't.

As for completing $ rg somepattern <tab>, yes, this should be either the literal PATH (see comments above) or list options/flags if no other positional/free args exist. However, unlike in Bash I'm not aware of a way to say, "This arg comes first, this one second, etc." in Zsh. If someone knows a way, I'd love to hear it! (Seriously. I'm not being facetious)

I forgot to say it above, but

Case 1:
rg <TAB>
will produce two incorrect completions: PATTERN, PATH.
[ ... ] It should produce either options/flags or nothing (because completing a pattern isn't feasible)

I think comleting nothing is highly subjective, as some would then assume completion scripts are totally broken at that point. As for completing flags/options, I believe ZSH requires a leading - to complete flags/options (unless no positiona/free args exist, or all have been used). This isn't something clap is choosing.

The same can be seen if you try:

$ cp <tab>
[ .. files ]

$ cp -<tab>
[.. options/flags]

As for completing $ rg somepattern , yes, this should be either the literal PATH (see comments above) or list options/flags if no other positional/free args exist.

I think I'm with you on everything except for this. It seems like the expected behavior from a user's perspective in this case would be to complete file paths instead? Or will it start completing file paths if you type $ rg somepattern ./<tab>?

I totally agree, but there's not a way for clap to know, "this positional arg accepts file paths" and to therefore tell ZSH such. Right now clap is dumb and just tells ZSH to complete the arg name since it can't know what that arg actually represents. #568 would remedy that.

There's also the possibility of adding either a special case to clap to use file path completion based on arg names or to have a standard set of completion possibilities in lieu of #568 such as Completion::RelativeFilePath where a particular she'll may or may not support such (in which case the shell would just ignore it).

I'm less inclined to support special casing based on arg names, but adding a specific setting that tells clap what to generate may be doable.

I should also say the positional arg index issue listed above (telling ZSH which args are which indexes) would also need to be fixed...And the ZSH completion documentation is..."Interesting" to say the least.

Finally, if there's a similar method to bash of which I'm currently unaware that says to fallback file path completion, that would work as well.

I'm rather unfamiliar with the context of clap, and the context of bash. But a positive I can bring to the discussion is how other similar completions behave.

The completion for grep does the following:

$ grep <tab>
[ no output / bell ]

$ grep somepattern <tab>
[ .. files ]

The _rg completion provided by zsh-completions, also follows this behavior of no completion for the pattern (first positional argument), completing files after (second positional argument).

I love that this functionality exists. Since we're looking at behavior, I'd love it if clap could do one thing that the other rg completion does: complete file types for the -t option.

In hindsight the original title I used was a bit pompous, so I've tried to make it a little better. Sorry about that, I thought the behavior was unexpected. It's mainly the lack of file completion that led me to say it's not usable, since I had come to expect that functionality from the zsh-completions implementation.

A custom made completion script will nearly always be better than a purely generic auto-generated one. There are pros and cons to both approaches. A custom script must ALWAYS be kept up to date with changes to the base program, whereas an auto-generated one doesn't have that issue at the expense of being slightly more generic.

I do think there is some things we can do to make our ZSH completions better, such as specifying what needs to be completed. I'm also going to start looking back into the index issue. So I'll mark this is a improvement issue and post back here with whatever I find :wink:

In fact, when I originally started implementing the auto-generation scripts I intended them to be used as a base script that could then be customized a little. I.e. just get the boiler plate out of the way and I'll add the last 5% polish. But it turned out they worked good enough (minus this issue you've encountered) that adding that extra 5% polish wasn't really worth it given the drawbacks of having to stay in sync again, over what you actually gain.

I think in this case in particular we can close that gap a few more percent!

I love that this functionality exists. Since we're looking at behavior, I'd love it if clap could do one thing that the other rg completion does: complete file types for the -t option.

This should be totally possible if I add that CompleterValue type enum. Stay tuned to see how this goes!

@kastiglione I hadn't seen the zsh-completions page before and they actually have some great tips for how I could improve the generated ZSH script. So thanks for that link!

Here's my thoughts on what I could realistically provide over the next few days (and longer):

  • [ ] Improve the positional/free argument indexes (I'd actually go so far as to say this would be a bug-fix)
  • [ ] Add some sort of CompletionValue enum with some generic options and be passed to a Arg::completion_value. Some of these values will be supported by some shells, but not others and that's OK.
  • [ ] Longer term (my time will be the limiting factor here) add #568 implemented via passing a function/closure to Arg::complete_with which has a different signature such as |clap::Shell, &ArgMatches, &str| -> String i.e. something with more context about what is trying to be completed (think completing different values based off what has already been passed to the command line in previous args)

The way, I think, you are supposed to handle positional arguments that you don't know how to complete is to complete nothing but popup a message, or better yet, default to completing files (Which is what most bash completion scripts do by using -o default). Like this (For _arguments, not _describe that is used now):

:Some message that explain that you need to enter X:()

# or

:Some message that explain that you need to enter X:_files

This is what most completions that I know of do. Completing the metavar/placeholder is sub-optimal it's never a valid argument.

For arguments that you do know what the completions are, you should complete that, of course. If you know that an argument doesn't take files than completing nothing with a message is better of course. But if you don't know, it's best to default to completing files since that's common and often less aggravating than trying to complete a file and getting nothing.

This should be closed - the generated zsh script even for ripgrep is working and falls back to file completion as one would expect (this is all thanks to @segevfiner !)

Was this page helpful?
0 / 5 - 0 ratings

Related issues

kbknapp picture kbknapp  路  16Comments

kbknapp picture kbknapp  路  30Comments

kbknapp picture kbknapp  路  23Comments

joshtriplett picture joshtriplett  路  41Comments

casey picture casey  路  25Comments