Support per-shell custom completion functions
C-enhancementA-completionS-triage
### Please complete the following tasks
- [x] I have searched the [discussions](https://github.com/clap-rs/clap/discussions)
- [x] I have searched the [open](https://github.com/clap-rs/clap/issues) and [rejected](https://github.com/clap-rs/clap/issues?q=is%3Aissue+label%3AS-wont-fix+is%3Aclosed) issues
### Clap Version
3.2.2
### Describe your use case
I use custom layouts frequently with [zellij](https://github.com/zellij-org/zellij) and wanted to enumerate files in its layouts directory if an obvious relative file path wasn't specified. Looking at the docs for `ValueHint`, I don't see a way to do this.
I made the following changes to the generated one from homebrew:
```diff
0a1,34
> _zellij_complete_layouts() {
> local current layouts_dir layout
> local -a layouts
>
> current="${1}"
>
> if [[ "${current}" == */* || "${current}" == .* || "${current}" == ~* || "${current}" == *.kdl* ]] ; then
> compopt -o filenames +o default +o bashdefault 2>/dev/null
> COMPREPLY=($(compgen -f -- "${current}"))
> return 0
> fi
>
> compopt +o default +o bashdefault 2>/dev/null
>
> layouts_dir="${XDG_CONFIG_HOME:-${HOME}/.config}/zellij/layouts"
> if [[ -d "${layouts_dir}" ]] ; then
> local old_nullglob
> old_nullglob="$(shopt -p nullglob)"
> shopt -s nullglob
> for layout in "${layouts_dir}"/*.kdl
> do
> layout="${layout##*/}"
> layouts+=("${layout%.kdl}")
> done
> eval "${old_nullglob}"
> fi
>
> COMPREPLY=()
> for layout in "${layouts[@]}"
> do
> [[ "${layout}" == "${current}"* ]] && COMPREPLY+=("${layout}")
> done
> }
>
331c365
< COMPREPLY=($(compgen -f "${cur}"))
---
> _zellij_complete_layouts "${cur}"
335c369
< COMPREPLY=($(compgen -f "${cur}"))
---
> _zellij_complete_layouts "${cur}"
343c377
< COMPREPLY=($(compgen -f "${cur}"))
---
> _zellij_complete_layouts "${cur}"
1177c1211
< COMPREPLY=($(compgen -f "${cur}"))
---
> _zellij_complete_layouts "${cur}"
1181c1215
< COMPREPLY=($(compgen -f "${cur}"))
---
> _zellij_complete_layouts "${cur}"
1243c1277
< if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then
---
> if [[ ${cur} == -* ]] ; then
1246a1281,1284
> if [[ ${COMP_CWORD} -eq 3 ]] ; then
> _zellij_complete_layouts "${cur}"
> return 0
> fi
1829c1867
< COMPREPLY=($(compgen -f "${cur}"))
---
> _zellij_complete_layouts "${cur}"
1833c1871
< COMPREPLY=($(compgen -f "${cur}"))
---
> _zellij_complete_layouts "${cur}"
2187c2225
< COMPREPLY=($(compgen -f "${cur}"))
---
> _zellij_complete_layouts "${cur}"
2583c2621
< COMPREPLY=($(compgen -f "${cur}"))
---
> _zellij_complete_layouts "${cur}"
```
Seems to work like I want, though may not be perfect - unrelated issue, though.
### Describe the solution you'd like
I appreciate these can't easily be generated, though maybe there are some common patterns someone could specify with additional `ValueHint` variants, but the main idea I was thinking was a `ValueHint` that lets you supply a custom expression. It would be up to author to define those, like dumping extra functions per-shell like https://github.com/zellij-org/zellij/blob/e9173cba163506491becbeacad162315d6e8f726/zellij-utils/src/setup.rs#L559-L572
So maybe something like a `ValueHint::Expression(Cow<'static, str>)`. That said, I'm not very experienced with completions to know if a single expression could be good enough for all of them. If not, maybe this hypothetical `Expression` variant needs to take a struct with members for each supported shell's expression that works for the shell. That's really the only questionable part, it seems, since apps can inject function definitions per-shell fairly easily as linked above in Zellij.
### Alternatives, if applicable
If there are 1 or a few common patterns like this - enumerating files in a particular directory - maybe those common shell-specific functions could be still be generated e.g., given a relative path under `$XDG_CONFIG_HOME` (which, as appropriate for each shell, could default to `$HOME/.config`), functions to enumerate some pattern could be generated e.g.,
```rust
ValueHint::BasenamesUnderConfigDir("zellij/layouts", "*.kdl")
```
### Additional Context
_No response_
1 条评论