2 min read
ZSH scripts with dynamic command completion
ZSH/Bash completion guides sure are confusing. I personally had difficulties wrapping my head around those arbitrary compdef, _describe, _arguments, compadd
commands. Moreover, in my case I wanted to complete a script that is placed in multiple folders and should load completion arguments dynamically. Luckily I found a simple solution.
We assume that zsh and oh-my-zsh are configured.
For every project I create task
script and a task.md
file that contains a list of available commands, their options and descriptions.
Running task help
gives the content of task.md
. So each task script has various subcommands that perform different tasks.
Here is an example for such a task file.
/**/task
#!/bin/bash
set -eo pipefail
# load env vars
if [ -f .env ]
then
export $(cat .env | sed 's/#.*//g' | xargs)
fi
function help() {
echo
echo "$1 <command> [options]"
echo
echo "commands:"
echo
column -t -s"|" ./task.md | tail -n +3
echo
}
case "$1" in
install-docker)
sudo apt-get install apt-transport-https ca-certificates curl gnupg-agent software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
| sudo apt-key add - \
&& sudo apt-key fingerprint 0EBFCD88
sudo add-apt-repository \
"deb [arch=amd64] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) \
stable"
sudo apt-get update && sudo apt-get install docker-ce docker-ce-cli containerd.io
sudo usermod -aG docker $USER
;;
install-tools)
cd ~
# Install node version manager
[ ! -d 'n' ] && curl -L https://git.io/n-install |
# Install python version manager
[ ! -d '.pyenv' ] && git clone https://github.com/pyenv/pyenv.git ~/.pyenv
# Install tmux plugins
[ ! -d '.tmux' ] && git clone https://github.com/tmux-plugins/tpm ~/.tmux/plugins/tpm
# Install binaries
sudo apt install -y zsh vim tmux jq pass htop xclip ripgrep
;;
*)
help task
exit 1
esac
And here is its help file.
/**/task.md
| command | option | description |
| -------------- | ------ | --------------- |
| install-docker | | Install docker. |
| install-tools | | Install tools. |
The autocompletion should list the available commands on task <TAB>
. This is done by adding an completion file:
~/.oh-my-zsh/completions/_task
#compdef task
_arguments '1: :->tasks' '*: :_files'
case "$state" in
tasks)
args=$(awk -F"|" '{print $2}' ./task.md | tail -n +3 | xargs)
args="$args help"
_arguments "1:profiles:($args)"
;;
esac
Whenever the tabulator is hit after entering task
the completion script will lookup command in the help file and output them as arguments.
➜ dotfiles git:(master) task <TAB>
install-docker install-tools
Easy, isn’t it? If the command is completed it will list files.
➜ dotfiles git:(master) ✗ task install-tools <TAB>
default.vim oh-my-zsh-completions/
Tags: zsh , bash , completion , dynamic
Edit this page
Show statistic for this page