Bash auto-complete seems pretty magic. People who use bash extensively (I'm part of them) tend to have a certain love for the [TAB]
key! It looked mysterious to me until I implemented one for myself. I'm not proficient at Bash, but basic knowledge of arrays and compgen
will make you king of autocomplete.
compgen
magicThis Bash builtin is the base of auto-completion. It takes two arguments: a list of terms, a dictionary, and an input to compare it with. It will return the list of terms in the dictionary which could match with the input. You can use it like this:
$ compgen -W 'init list new compile install lint' -- li
list lint
$ compgen -W 'init list new compile' -- compile
compile
$ compgen -W 'init list new compile' -- lists
The options -W
stands for words. You can find the documentation of this builtin and in man bash
or here.
Let's say we decide to create an auto-complete functionality for goat
, your homemade version of git
. We would like to complete subcommands like goat log
or goat commit
. Firstly you'd need to create a script to let Bash know how to perform the completion. You'd write this script in /etc/bash_completion.d/goat
.
The content would look like this:
_goat()
{
local cur opts
cur="${COMP_WORDS[COMP_CWORD]}"
opts="log commit push pull clone add"
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
}
complete -F _goat goat
COMP_WORDS
, COMP_CWORD
are variables provided by Bash respectively containing an array of each terms in the command line and the index of the word being completed (more documentation on bash internal linked with completion here). The selection of words suggested to the user will be taken from the COMPREPLY
variable. Calling the complete
builtin will allow Bash to perfom the actual completion. Here's the result:
$ goat [TAB]
log commit push pull clone add
$ goat com[TAB]
$ goat commit
$ goat pu[TAB]
push pull
$ goat ad[TAB] some_file
$ goat add some_file
$ goat log [TAB]
log commit push pull clone add
As you can see in the last attempt to complete the sentence, there is no consideration of the place in the command line you are which would do a pretty bad autocompletion feature. Plus there is no completion of options or sub commands.
If you want a smarter completion feature, you'll have to:
Suggest based on subcommands and options available to the user. This means you need to create a tree of possibilities: goat push
supports --force
option but goat pull
does not, etc.
Suggest based on the type of argument expected. For instance Git auto completion will suggest branches and remote repository when using git push [TAB]
.
You can even suggest files based on their types, size, content, etc.
Those tasks might feel simple to achieve, but remember that you also have to deal with Bash language which is not the most elegant one. To give you an idea, docker
has a 3k lines script to perform completion.
I hope this post helped you!