A good way to get started is to look at some already defined completion functions.
On my linux installation these are found in /usr/share/zsh/functions/Completion/Unix
and /usr/share/zsh/functions/Completion/Linux and a few other subdirs.
You will notice that the _arguments function is used a lot in these files.
This is a utility function that makes it easy to write simple completion functions.
The _arguments function is a wrapper around the compadd builtin function.
The compadd builtin is the core function used to add completion words to the command line, and control its behaviour.
However, most of the time you will not need to use compadd, since there are many utility functions such as _arguments
and _describe which are easier to use.
For very basic completions the _describe function should be adequate
** Utility functions
Here is a list of some of the utility functions that may be of use.
The full list of utility functions, with full explanations, is available [[https://zsh.sourceforge.net/Doc/Release/Completion-System.html#Completion-Functions][here]].
Examples of how to use these functions are given in the next section.
*** main utility functions for overall completion
| _alternative | Can be used to generate completion candidates from other utility functions or shell code. |
| _arguments | Used to specify how to complete individual options & arguments for a command with unix style options. |
| _describe | Used for creating simple completions consisting of words with descriptions (but no actions). Easier to use than _arguments |
| _gnu_generic | Can be used to complete options for commands that understand the `--help' option. |
| _regex_arguments | Creates a function for matching commandline arguments with regular expressions, and then performing actions/completions. |
*** functions for performing complex completions of single words
| _values | Used for completing arbitrary keywords (values) and their arguments, or comma separated lists of such combinations. |
| _combination | Used to complete combinations of values, for example pairs of hostnames and usernames. |
| _multi_parts | Used for completing multiple parts of words separately where each part is separated by some char, e.g. for completing partial filepaths: /u/i/sy -> /usr/include/sys |
| _sep_parts | Like _multi_parts but allows different separators at different parts of the completion. |
| _sequence | Used as a wrapper around another completion function to complete a delimited list of matches generated by that other function.
*** functions for completing specific types of objects
| _path_files | Used to complete filepaths. Take several options to control behaviour. |
| _files | Calls _path_files with all options except -g and -/. These options depend on file-patterns style setting. |
| _net_interfaces | Used for completing network interface names |
| _users | Used for completing user names |
| _groups | Used for completing group names |
| _options | Used for completing the names of shell options. |
| _parameters | Used for completing the names of shell parameters/variables (can restrict to those matching a pattern). |
*** functions for handling cached completions
If you have a very large number of completions you can save them in a cache file so that the completions load quickly.
| _cache_invalid | indicates whether the completions cache corresponding to a given cache identifier needs rebuilding |
| _retrieve_cache | retrieves completion information from a cache file |
| _store_cache | store completions corresponding to a given cache identifier in a cache file |
*** other functions
| _message | Used for displaying help messages in places where no completions can be generated. |
| _regex_words | Can be used to generate arguments for the _regex_arguments command. This is easier than writing the arguments manually. |
| _guard | Can be used in the ACTION of specifications for _arguments and similar functions to check the word being completed. |
*** Actions
Many of the utility functions such as _arguments, _regex_arguments, _alternative and _values may include an action
at the end of an option/argument specification. This action indicates how to complete the corresponding argument.
The actions can take one of the following forms:
| ( ) | Argument is required but no matches are generated for it. |
| (ITEM1 ITEM2) | List of possible matches |
| ((ITEM1\:'DESC1' ITEM2\:'DESC2')) | List of possible matches, with descriptions. Make sure to use different quotes than those around the whole specification. |
| ->STRING | Set $state to STRING and continue ($state can be checked in a case statement after the utility function call) |
| FUNCTION | Name of a function to call for generating matches or performing some other action, e.g. _files or _message |
| {EVAL-STRING} | Evaluate string as shell code to generate matches. This can be used to call a utility function with arguments, e.g. _values or _describe |
| =ACTION | Inserts a dummy word into completion command line without changing the point at which completion takes place. |
Not all action types are available for all utility functions that use them. For example the ->STRING type is not available in the
_regex_arguments or _alternative functions.
** Writing simple completion functions using _describe
The _describe function can be used for simple completions where the order and position of the options/arguments is
not important. You just need to create an array parameter to hold the options & their descriptions, and then pass
the parameter name as an argument to _describe. The following example creates completion candidates c and d, with
the descriptions (note this should be put in a file called _cmd in some directory listed in $fpath).
#+BEGIN_SRC sh
#compdef cmd
local -a subcmds
subcmds=('c:description for c command' 'd:description for d command')
_describe 'command' subcmds
#+END_SRC
You can use several different lists separated by a double hyphen as follows but note that this mixes the matches under and single heading and is not intended to be used with different types of completion candidates:
#+BEGIN_SRC sh
local -a subcmds topics
subcmds=('c:description for c command' 'd:description for d command')
topics=('e:description for e help topic' 'f:description for f help topic')
_describe 'command' subcmds -- topics
#+END_SRC
If two candidates have the same description, _describe collects them together on the same row and ensures that descriptions are aligned in neatly in columns.
The _describe function can be used in an ACTION as part of a specification for _alternative, _arguments or _regex_arguments.
In this case you will have to put it in braces with its arguments, e.g. 'TAG:DESCRIPTION:{_describe 'values' options}'
** Writing completion functions using _alternative
Like _describe, this function performs simple completions where the order and position of options/arguments is not important.
However, unlike _describe, instead of fixed matches further functions may be called to generate the completion candidates. Furthermore, _alternative allows a mix of different types of completion candidates to be mixed.
As arguments it takes a list of specifications each in the form 'TAG:DESCRIPTION:ACTION' where TAG is a special tag that identifies the type of completion matches,
DESCRIPTION is used as a heading to describe the group of completion candidates collectively, and ACTION is one of the action types listed previously (apart from the ->STRING and =ACTION forms).
For example:
#+BEGIN_SRC sh
_alternative 'arguments:custom arg:(a b c)' 'files:filename:_files'
#+END_SRC
The first specification adds completion candidates a, b & c, and the second specification calls the _files function for completing filepaths.
We could split the specifications over several lines with \ and add descriptions to each of the custom args like this:
To use parameter expansion to create our list of completions we must use double quotes to quote the specifications,
e.g:
#+BEGIN_SRC sh
_alternative \
"dirs:user directory:($userdirs)" \
"pids:process ID:($(ps -A o pid=))"
#+END_SRC
In this case the first specification adds the words stored in the $userdirs variable, and the second specification
evaluates 'ps -A o pid=' to get a list of pids to use as completion candidates. In practice, we would make used of the existing _pids function for this.
We can use other utility functions such as _values in the ACTION to perform more complex completions, e.g:
#+BEGIN_SRC sh
_alternative \
"directories:user directory:($userdirs)" \
'options:comma-separated opt: _values -s , letter a b c'
#+END_SRC
this will complete the items in $userdirs, as well as a comma separated list containing a, b &/or c. Note the use of the initial space before _values. This is needed because _values doesn't understand standard compadd options for descriptions.
As with _describe, the _alternative function can itself be used in an ACTION as part of a specification for _arguments
or _regex_arguments.
** Writing completion functions using _arguments
With a single call to the _arguments function you can create fairly sophisticated completion functions. It is intended to handle typical commands that take a variety of options along with some normal arguments.
Like the _alternative function, _arguments takes a list of specification strings as arguments.
These specification strings specify options and any corresponding option arguments (e.g. -f filename),
or command arguments.
Basic option specifications take the form '-OPT[DESCRIPTION]', e.g. like this:
In this case paths to music files are completed stepwise descending down directories using the _multi_parts function,
and the flags are completed as a comma separated list using the _values function.
I have just given you the basics of _arguments specifications here, you can also specify mutually exclusive options,
repeated options & arguments, options beginning with + instead of -, etc. For more details see the [[https://zsh.sourceforge.net/Doc/Release/Completion-System.html#Completion-System][official documentation]].
Also have a look at the tutorials mentioned at the end of this document, and the completion functions in the [[https://github.com/vapniks/zsh-completions/tree/master/src][src directory]].
** Writing completion functions using _regex_arguments and _regex_words
If you have a complex command line specification with several different possible argument sequences then
the _regex_arguments function may be what you need. It typically works well where you have a series of keywords followed by a variable number of arguments.
_regex_arguments creates a completion function whose name is given by the first argument.
Hence you need to first call _regex_arguments to create the completion function, and then call that function,
e.g. like this:
#+BEGIN_SRC sh
_regex_arguments _cmd OTHER_ARGS..
_cmd "$@"
#+END_SRC
The OTHER_ARGS should be sequences of specifications for matching & completing words on the command line.
These sequences can be separated by '|' to represent alternative sequences of words.
You can use bracketing to arbitrary depth to specify alternate subsequences, but the brackets must be backslashed like this \( \)
This specifies a command line matching either SEQ1, or SEQ2 followed by SEQ2a or SEQ2b. You are describing the form arguments to the command take in the form of a regular expression grammar.
Each specification in a sequence must contain a / PATTERN/ part at the start followed by an optional ':TAG:DESCRIPTION:ACTION'
part.
Each PATTERN is a regular expression to match a word on the command line. These patterns are processed sequentially
until we reach a pattern that doesn't match at which point any corresponding ACTION is performed to obtain completions
for that word. Note that there needs to be a pattern to match the initial command itself.
See below for further explanation about PATTERNs.
The ':TAG:DESCRIPTION:ACTION' part is interpreted in the same way as for the _alternative function specifications,
except that it has an extra : at the start, and now all of the possible ACTION formats listed previously are allowed.
For more fine grained control you can use the builtin compadd function to add completion words directly.
This function has many different options for controlling how completions are displayed and how text on the command line
can be altered when words are completed. Read the [[https://zsh.sourceforge.net/Doc/Release/Completion-System.html#Completion-System][official documentation]] for full details.
Here I just give a few simple examples.
Add some words to the list of possible completions:
#+BEGIN_SRC sh
compadd foo bar blah
#+END_SRC
As above but also display an explanation:
#+BEGIN_SRC sh
compadd -X 'Some completions' foo bar blah
#+END_SRC
As above but automatically insert a prefix of "what_" before the completed word:
#+BEGIN_SRC sh
compadd -P what_ foo bar blah
#+END_SRC
As above but automatically insert a suffix of "_todo" after the completed word:
#+BEGIN_SRC sh
compadd -S _todo foo bar blah
#+END_SRC
As above but automatically remove the "_todo" suffix if a blank char is typed after the suffix:
#+BEGIN_SRC sh
compadd -P _todo -q foo bar blah
#+END_SRC
Add words in array $wordsarray to the list of possible completions
#+BEGIN_SRC sh
compadd -a wordsarray
#+END_SRC
* Testing & debugging
To reload a completion function:
#+BEGIN_SRC sh
> unfunction _func
> autoload -U _func
#+END_SRC
The following functions can be called to obtain useful information.
If the default keybindings don't work you can try pressing Alt+x and then enter the command name.
| _complete_help | Ctrl+x h | displays information about context names, tags, and completion functions used when completing at the current cursor position |
| _complete_help | Alt+2 Ctrl+x h | as above but displays even more information |
| _complete_debug | Ctrl+x ? | performs ordinary completion, but captures in a temporary file a trace of the shell commands executed by the completion system |
* Gotchas (things to watch out for)
Remember to include a #compdef line at the beginning of the file containing the completion function.
Take care to use the correct type of quoting for specifications to _arguments or _regex_arguments:
use double quotes if there is a parameter that needs to be expanded in the specification, single quotes otherwise,
and make sure to use different quotes around item descriptions.
Check that you have the correct number of :'s in the correct places for specifications for _arguments,
_alternative, _regex_arguments, etc.
Remember to include an initial pattern to match the command word when using _regex_arguments (it does not need a matching action).
Remember to put a null char $'\0' at the end of any PATTERN argument for _regex_arguments
* Tips
Sometimes you have a situation where there is just one option that can come after a subcommand, and zsh will complete this
automatically when tab is pressed after the subcommand. If instead you want it listed with its description before completing
you can add another empty option (i.e. \:) to the ACTION like this ':TAG:DESCRIPTION:((opt1\:"description for opt1" \:))'
Note this only applies to utility functions that use ACTIONs in their specification arguments (_arguments, _regex_arguments, etc.)
* Other resources
[[https://wikimatze.de/writing-zsh-completion-for-padrino/][Here]] is a nicely formatted short tutorial showing basic usage of the _arguments function,
and [[https://web.archive.org/web/20190411104837/http://www.linux-mag.com/id/1106/][here]] is a slightly more advanced tutorial using the _arguments function.
[[https://zsh.sourceforge.net/Doc/Release/Completion-System.html#Completion-System][Here]] is the zshcompsys man page.