The last quality of life feature we will add is the ability to show completion descriptions when tabbing on a complete word:
$ foo apple
For example, the Mill build tool does this so if you’re not sure what a flag or command does, you can press on it to see more details:
Tab-completion is a common way to explore unfamiliar APIs, and just because someone finished writing a flat or command doesn’t mean they aren’t curious about what it does! But while Zsh tab-completion displays descriptions when multiple options match the prefix, and we managed to hack Bash tab-completion to do the same thing, neither displays any information if the word you are tab-completing is already complete.
This behavior can be annoying, if the user wants to see the description, they will need to first:
Delete enough characters to make the token match multiple completions
Press
Visually scan the multiple completions printed to find the word description they care about
Type back in all the missing characters so they can run the command
To solve this, we can hack Bash and Zsh to print tab-completion descriptions even if the token is already a complete word. We do this by checking if the token is a complete word, and if so adding a second "dummy" completion: this makes the tab-completion ambiguous, which cases Bash and Zsh to print out the completions and descriptions for the user to see.
Doing this in _complete_foo_bash looks like the following:
_complete_foo_bash() { local IFS=$'
' local raw=($(_generate_foo_completions "$COMP_CWORD" "${COMP_WORDS[@]}")) local trimmed=() trimmed+=( "${raw[@]}" ) if (( ${#raw[@]} == 1 )); then trimmed+=( "${raw[0]%%:*}" ) fi COMPREPLY=( "${trimmed[@]}" ) }
Instead of checking the length of raw to decide whether we add a trimmed and non-trimmed lines to trimmed , we now instead always add the non-trimmed lines that contain the completion descriptions, and in the case where there’s only one line we then add an additional word-only completion with the description trimmed off.
This means that all completions are ambiguous and will print the description - even completions with a single real choice - but the additional trimmed line when there is only 1 real choice ensures that the description text never gets inserted into the user’s command
In Zsh, this can be similarly done via:
_complete_foo_zsh() { local -a raw trimmed local IFS=$'
' raw=($(_generate_foo_completions "$CURRENT" "${words[@]}")) for d in $raw; do trimmed+=( "${d%%:*}" ); done if (( ${#raw} == 1 )); then trimmed+=( "${raw[1]}" ) raw+=( "${trimmed[1]}" ) fi compadd -d raw -- $trimmed }
The change here is similar to the Bash snippet above: when the number of completions is 1, we add an additional completion to make it ambiguous so Zsh prints the description. But because Zsh expects to pass two parallel arrays of descriptions and tokens to compadd , our if block needs to append items to both trimmed and raw .
Using this, it now looks like
$ foo apple apple apple: a common fruit