Writing completions with compsys

Zsh · Expert · 15 min

Completions for your own tools and scripts make them as pleasant to use as git or docker.

A completion is a function named after the command with a leading underscore, _deploy, stored in a file of the same name in a directory on fpath. The file's first line #compdef deploy tells compinit which commands it completes. compinit scans fpath when it builds ~/.zcompdump, so add your directory to fpath before calling compinit.

Most completions are built on _arguments, which takes one spec per option or argument:

  • '-v[verbose output]' an option with a description,
  • '(-v --verbose)'{-v,--verbose}'[...]' both spellings, excluding each other,
  • '--config=[config file]:file:_files' an option with a value and an action that completes it,
  • '1:environment:->env' the first positional argument, handled in a case $state block,
  • '*:service:(api web worker)' any further arguments from a fixed list.

_describe offers values with descriptions ('staging:test environment'), and helpers like _files, _hosts and _users complete common things. For a tool whose --help lists its options, compdef _gnu_generic mytool gives decent completion for free.

Styles use the context :completion:function:completer:command:argument:tag, for example zstyle ':completion:*:*:deploy:*' .... Press Ctrl-X then ? to run _complete_debug, which writes a trace of the completion to a file. After changing completion files, remove ~/.zcompdump and start a new shell.

Example

#compdef deploy
# file: ~/.zsh/completions/_deploy
local state
local -a envs=('staging:test environment' 'production:live site')
_arguments -s \
  '(-v --verbose)'{-v,--verbose}'[print more output]' \
  '(-t --tag)'{-t+,--tag=}'[image tag to deploy]:tag:' \
  '--config=[config file]:file:_files -g "*.(yml|yaml)"' \
  '1:environment:->env' \
  '*:service:(api web worker)'
case $state in
  env) _describe -t envs 'environment' envs ;;
esac
# In ~/.zshrc, BEFORE compinit:
#   fpath=(~/.zsh/completions $fpath)
#   autoload -Uz compinit && compinit
#   compdef _gnu_generic mytool    # free completion from mytool --help
# deploy <Tab>     ->  production -- live site / staging -- test environment
# deploy -<Tab>    ->  --config --tag --verbose -t -v

Remember

  • A _cmd file with #compdef cmd on fpath, loaded by compinit
  • _arguments specs describe options, values and positional arguments
  • ->state plus case $state for custom logic; _describe for described values

Watch out for

  • Adding the completions directory to fpath after compinit has already run.

Check yourself

  1. What does the first line `#compdef deploy` in a completion file do?
  2. In an _arguments spec, what does '*:file:_files' describe?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: zsh.sourceforge.io/Doc/Release/Completion-System.html

Builds on

Unlocks

Nothing builds on this yet.