Programmable completion using the `compctl' command is one of the most powerful, and also potentially confusing, features of zsh; here I give a short introduction. There is a set of example completions supplied with the source in Misc/compctl-examples; completion definitions for many of the most obvious commands can be found there.
`Completion' is where you hit a particular command key (TAB is the standard one) and the shell tries to guess the word you are typing and finish it for you --- a godsend for long file names, in particular, but in zsh there are many, many more possibilities than that.
There is also a related process, `expansion', where the shell sees
you have typed something which would be turned by the shell into
something else, such as a variable turning into its value ($PWD
becomes /home/users/mydir) or a history reference (!! becomes
everything on the last command line). In zsh, when you hit TAB it
will look to see if there is an expansion to be done; if there is,
it does that, otherwise it tries to perform completion. (You can
see if the word would be expanded --- not completed --- by TAB by
typing \C-x g
, which lists expansions.) Expansion is generally
fairly intuitive and not under user control; for the rest of the
chapter I will discuss completion only.
The simplest sort is filename completion, mentioned above. Unless you have made special arrangements, as described below, then after you type a command name, anything else you type is assumed by the completion system to be a filename. If you type part of a word and hit TAB, zsh will see if it matches the first part a file name and if it does it will automatically insert the rest.
The other simple type is command completion, which applies (naturally) to the first word on the line. In this case, zsh assumes the word is some command to be executed lying in your $PATH (or something else you can execute, like a builtin comman, a function or an alias) and tries to complete that.
Other forms of completion have to be set up by special arrangement. See the manual entry for compctl for a list of all the flags: you can make commands complete variable names, user names, job names, etc., etc.
For example, one common use is that you have an array variable, $hosts, which contains names of other machines you use frequently on the network:
telnet fr
and hit TAB, the rest of the name
will appear by itself.
An even more powerful option to compctl
(-g
) is to tell zsh that
only certain sorts of filename are allowed. The argument to -g
is
exactly like a glob pattern, with the usual wildcards *
, ?
, etc.
In the compctl statement it needs to be quoted to avoid it being
turned into filenames straight away. For example,
.ps
or .eps
should be considered
for completion.
Note that flags may be combined; if you have more than one, all the possible completions for all of them are put into the same list, all of them being possible completions. So
Often there will be more than one possible completion: two files
start with the same characters, for example. Zsh has a lot of
flexibility for what it does here via its options. The default is
for it to beep and completion to stop until you type another
character. You can type \C-D
to see all the possible completions.
(That's assuming your at the end of the line, otherwise \C-D
will
delete the next character and you have to use ESC-\C-D
.) This can be
changed by the following options, among others:
\C-D
Finally, the hairiest part of completion. It is possible to get zsh to consider different completions not only for different commands, but for different words of the same command, or even to look at other words on the command line (for example, if the last word was a particular flag) and decide then.
There are really two sorts of things to worry about. The simpler is alternative completion: that just means zsh will try one alternative, and only if there are no possible completions try the next. For example
.ps
files, so if
there are any, only those are used, but if there aren't any, any
old file is a possibility. You can also have a +
with no flags
after it, which tells zsh that it's to treat the command like any
other if nothing was found. That's only really useful if your
default completion is fancy, i.e. you have done something with
compctl -D
to tell zsh how commands which aren't specially handled
are to have their arguments completed.
The second sort is the hard one. Following a -x
, zsh expects that
the next thing will be some completion code, which is a single
letter followed by an argument in square brackets. For example
p[1]
: p
is for position, and the argument tells it to look at
position 1; that says that this completion only applies to the word
immediately after the command. You can also say p[1,3]
which says
the completion only applies to the word if it's between the first
and third words, inclusive, after the command, and so on. See the
list in the `compctl' manual entry for a list of these conditions:
some conditions take one argument in the square brackets, some two.
Usually, negative numeric arguments count backwards from the end
(for example, p[-1]
applies to the last word on the line).
The condition is then followed by the flags as usual (as in 4.2), and possibly other condition/flag sets following a single -; the whole lot ends with a double -- before the command name. In other words, each extended completion section looks like this:
Let's look at rcp again: this assumes you've set up $hosts
as above.
This uses the n[<n>,<string>]
flag, which tells zsh to look for
the <n>
'th occurrence of <string> in the word, ignoring anything up
to and including that. We'll use it for completing the bits of
rcp's user@host:file
combination. (Of course, the file name is on
the local machine, not host
, but let's ignore that; it may still
be useful.)
+
), if successful add a :
(-S
for suffix); (2) if that fails
move on to try the code after the +
: look and see if there is a
:
in a word (the n[1,:]
); if there is, complete filenames
(-f
) after the first of them; (3) otherwise look for an @
and
complete hostnames after the first of them (the n[1,@]
), adding a
:
if successful; (4) if all else fails use the -f
before the
-x
and try to complete files.
So the rules for order are (1) try anything before a +
before
anything after it (2) try the conditions after a -x
in order until
one succeeds (3) use the default flags before the -x
if none of the
conditions was true.
Different conditions can also be combined. There are three levels of this (in decreasing order of precedence):
s[foo][bar]
says apply the
completion if the word begins with foo
or bar
,
p[1] s[-]
says this completion only applies for the first word
after the command and only if it begins with a -
,
c[-1,-f], s[-f]
means either the previous word (-1 relative to
the current one) is -f
, or the current word begins with -f
---
useful to use the same completion whether or not the -f
has a
space after it.
Here's a useless example just to show a general -x
completion.
foobar
, look and see if (((the
word before the current one is -u
) or (the word before the current
one is -U
)) and (the current word is 2)) or (the current word begins
with -u
); if so, try to complete user names. If the word before
the current one is -j
, insert the prefix %
before the current word
if it's not there already and complete job names. Otherwise, just
complete file names.
...then your last resort is to write a shell function to do it for
you. By combining the -U
and -K func
flags you can get almost
unlimited power. The -U
tells zsh that whatever the completion
produces is to be used, even if it doesn't fit what's there already
(so that gets deleted when the completion is inserted). The -K
func
tells zsh a function name. The function is passed what's on
the line already, but it can return anything it likes via the
reply
array, and this becomes the set of possible completions.
The best way to understand this is to look at multicomp
and other
functions supplied with the zsh distribution.