spf13 / cobra

A Commander for modern Go CLI interactions
https://cobra.dev
Apache License 2.0
38.22k stars 2.85k forks source link

Add a way to bypass the terminal autocomplete matching #1828

Open raphaelvigee opened 2 years ago

raphaelvigee commented 2 years ago

This would allow to support fuzzy completions: Lets say ValidArgsFunction return []string{"some_arg", "some_arg_thats_long"}

$ mycmd arg<TAB>

I should be presented with the autocomplete options:

some_arg
some_arg_thats_long

Currently those would be filtered out because of the use of compgen on bash and _describe on zsh (haven't checked fish) those will be filtered out as the default behavior is to filter based on prefix.

The addition of another directive ShellCompDirectiveNoMatching (something like that) would disable the matching

marckhouzam commented 2 years ago

Hi @raphaelvigee. Fuzzy matching is already possible for ValidArgsFunction and RegisterFlagCompletionFunc. All that is required is for you not to filter on prefix. Helm does this for example: https://github.com/helm/helm/pull/10513.

However, this only works for zsh and fish. I was under the impression that bash did not handle fuzzy matching so the Cobra bash script does not allow it. Could you give an example where you say bash support fuzzy matching?

Finally, for completeness, be aware Cobra does filter on the prefix when it does completion itself. For instance, when completion subcommands and flag names. I have been hesitant to change that as I am not convinced it is a common scenario.

raphaelvigee commented 2 years ago

I can confirm that fuzzy matching does not work on zsh, the situation highlighted above returns no completion in the terminal as they get filtered out in _describe (which follows the user-defined matchers), but i think the CLI author should be able to say "you defo want fuzzy matching here", hence passing the extra directive. Debugging it, i can see the completion up until it passes through _describe.

From the zsh debug:

+_mycmd:68> __mycmd_debug $'completions: some_arg\nsome_arg_thats_long'
...
+_mycmd:160> __mycmd_debug 'Calling _describe'
...
+_mycmd:167> __mycmd_debug '_describe did not find completions.'

A similar thing is happening with bash

I don't have an example in mind that does fuzzy matching, but for my current use-case, fuzzy matching is almost necessary, basically: mycmd takes a single argument which is a list of urls, these urls are long and complicated, and fuzzy matching would make the user life much easier

marckhouzam commented 2 years ago

For fuzzy matching to work for zsh you need to set the matcher-list in zstyle. I get this automatically with oh-my-zsh.

$ zstyle | grep -A1 matcher-list
matcher-list
        :completion:* 'm:{a-zA-Z-_}={A-Za-z_-}' 'r:|=*' 'l:|=* r:|=*'

You can try it by running:

zstyle ':completion:*' matcher-list '' 'm:{a-zA-Z}={A-Za-z}' 'r:|=*' 'l:|=* r:|=*'

This article explains it well: https://thevaluable.dev/zsh-completion-guide-examples/

As for bash, I don't know if it supports this kind of matching. I believe it does not and only matches on prefix

raphaelvigee commented 2 years ago

I do have this matcher in:

$ zstyle | grep -A1 matcher-list
matcher-list
        :completion:* 'm:{a-zA-Z}={A-Za-z}' 'r:|=*' 'l:|=* r:|=*'

But i feel like we should be able to make the matching handled by cobra user-code and not whatever shell I am using. One may decide to do fuzzy matching, or more advanced things (for example when matching a path, one could decide to do some advanced fuzzy matching by path parts, splitting by / and matching the individual units)

marckhouzam commented 2 years ago

I do have this matcher in:

I would expect your example to work with zsh in that case.

But i feel like we should be able to make the matching handled by cobra user-code and not whatever shell I am using.

That would be great. I'm just not aware if you can get the different shells to do what you want.

raphaelvigee commented 2 years ago

I would expect your example to work with zsh in that case.

Same, but zsh does not seem to agree as per the logs in https://github.com/spf13/cobra/issues/1828#issuecomment-1283110025

That would be great. I'm just not aware if you can get the different shells to do what you want.

Well it would be best effort, if some shell doesn't support it, so be it, prefix matching it is!

marckhouzam commented 2 years ago

Same, but zsh does not seem to agree as per the logs in #1828 (comment)

In case it helps, you can at least verify what Cobra sends the shell as completion choices like this: mycmd __complete arg<ENTER>

Well it would be best effort, if some shell doesn't support it, so be it, prefix matching it is!

That's kind of what Cobra does now. If the program returns completion choices that are not filtered on prefix, then zsh and fish will do fuzzy matching if the user has configured the shell to do it.

raphaelvigee commented 2 years ago

In case it helps, you can at least verify what Cobra sends the shell as completion choices like this: mycmd __complete arg

Cobra returns the right value +_mycmd:68> __mycmd_debug $'completions: some_arg\nsome_arg_thats_long'

That's kind of what Cobra does now. If the program returns completion choices that are not filtered on prefix, then zsh and fish will do fuzzy matching if the user has configured the shell to do it.

Well yes and no, it does relies on the user having the right matchers configured (and zsh behaving correctly)

To try and move this forward, would it be acceptable to add a new directive to bypass the shell matching altogether ?

marckhouzam commented 2 years ago

To try and move this forward, would it be acceptable to add a new directive to bypass the shell matching altogether ?

If the final solution is more flexible than what we have now and that the way to use this new solution is user-friendly, then yes, no problem adding a new directive. PR welcome.

github-actions[bot] commented 1 year ago

The Cobra project currently lacks enough contributors to adequately respond to all issues. This bot triages issues and PRs according to the following rules: