How to do basic shell completion
So you wrote some dumb tool for your coworkers. It works, but no one can remember the dang arguments. Half of them use zsh, the other half use fish, the grumpy loudmouth uses bash, and the new hire uses something that sounds like a tolkein reference. The documentation for everything is garbage, stackoverflow is filled with lies, and most of the available examples take up six pages. Can’t you do this simply?
Yes.
Here are some minimum-viable-shell-completions for popular shells- just enough
to make the <major command> <minor command>
pattern work, you know, like git $command
or aws $product $verb
.
bash
The big kahuna, the default on Linux distributions, and the old default on OS
X, before the GPL v3 and Apple’s Great Terror. There are, as you might expect,
Many Ways To Do It, but my favorite, because it is simple & bloody minded, is
good ‘ol complete
-
:~$ complete -W "fee fi fo fum" giant
:~$ giant <tab>
fee fi fo fum
zsh
The New Hotness in 2005 (I know it dates to 1990), and the default on MacOS for
the past few years. Here there are also Many Ways To Do it, but look, I’m not
going to lie- I like the old, deprecated compctl
, because I am old and
deprecated. Also, you can bang this out in two lines instead of 2 paragraphs,
and brevity is brilliance.
% declare -a _giant_commands=(fee fi fo fum)
% compctl -k _giant_commands giant
% giant <tab><tab>
fee fi fo fum
fish
If you were too cool in 2005 to use something that worked, fish was the shell
for you. That is still sort of true, because dealing with cross-shell
compatibility is still slightly more of a hassle than you really want to put up
with. It also uses the complete
command for completion, but the documentation
is better, and it’s totally different from bash’s.
> complete -c giant -a "fee fi fo fum"
> giant <tab>
fee fi fo fum
elvish
If you like to get in fights on message boards lamenting the lack of structured streams in the shell, Elvish is the shell for you. It is very neat, and has a truly wild feature set, including a built-in multi-pane file manager. Definitely worth a look if you’re feeling like changing your workflow up.
> edit:completion:arg-completer[giant] = [@args]{
possibilities = [fee fi fo fum]
put $@possibilities
}
> giant <tab>
COMPLETING argument
fee fi fo fum
I’m really feeling the namespacing, if I’m being honest. It makes introspection of the shell configuration a lot less like dipping your face into a firehose.