Reputation: 21218
I currently have a Bash completion file which completes a single parameter from a list of allowed commands for a script called pbt
. This is the working Bash completion file:
_pbt_complete()
{
local cur goals
COMPREPLY=()
cur=${COMP_WORDS[COMP_CWORD]}
goals='asadmin clean deploy'
cur=`echo $cur`
COMPREPLY=($(compgen -W "${goals}" ${cur}))
}
complete -F _pbt_complete pbt
So if I call
pbt <tab>
Bash completes to all allowed commands (asadmin
, clean
, deploy
), which is okay. Now I want to add a second level to the completion. So for example if I type
pbt asadmin <tab>
I want it to complete only options that are available inside the asadmin
"environment" (which I'll also define inside the Bash completion file). For example pbt asadmin [start-domain|stop-domain]
. But if I type
pbt deploy <tab>
It should complete to another set of options. For example, pbt deploy [all|current]
. So the options for the second command should always depend on the first command.
How can I do that in the completion file?
Upvotes: 26
Views: 7608
Reputation: 982
Btw, here are two useful tips on better tab completion:
bind 'set show-all-if-ambiguous on'
# this makes only one Tab necessary to show possible completionsHere is more info on how to use the complete
command to adjust tab completetion. This page has an incredible breakdown, and discusses known application using "cobra (Golang), click (Python) and clap (Rust) tools"
https://echorand.me/posts/linux_shell_autocompletion/ (and how Git uses Compgen)
Here is a link the the GH repo for Debian bash-completion
: https://github.com/scop/bash-completion
Q. What is the search order for the completion file of each target command?
A. The completion files of commands are looked up by the shell function __load_completion. Here, the search order in bash-completion >= 2.12 is explained.
The completion files of the name or .bash, where is the name of the target command, are searched in the above completion directories in order. The file that is found first is used. When no completion file is found in any completion directories in this process, the completion files of the name _ is next searched in the completion directories in order.
Upvotes: 2
Reputation: 21218
Thanks to mkb's comment, I looked into the p4
example, which was—unlike the Git example—simple enough for me to adapt to my case. Here is the working version which does exactly what I asked for:
have pbt &&
_pbt_complete()
{
local cur prev
COMPREPLY=()
cur=${COMP_WORDS[COMP_CWORD]}
prev=${COMP_WORDS[COMP_CWORD-1]}
if [ $COMP_CWORD -eq 1 ]; then
COMPREPLY=( $(compgen -W "asadmin deploy" -- $cur) )
elif [ $COMP_CWORD -eq 2 ]; then
case "$prev" in
"asadmin")
COMPREPLY=( $(compgen -W "start-domain stop-domain" -- $cur) )
;;
"deploy")
COMPREPLY=( $(compgen -W "all current" -- $cur) )
;;
*)
;;
esac
fi
return 0
} &&
complete -F _pbt_complete pbt
Upvotes: 37
Reputation: 74750
You may want to look at how the completion for git is done, as an example. (This takes 2257 lines of function definitions and additional 14 variables in my bash setup.)
Upvotes: 1