Zsh completion arguments
From wikinotes
The _arguments
function is one method available for producing completions.
Cheat Sheet
'-o[output file]' # `foo -o` {-h,--help}'[show help]' # `foo -h` OR `foo --help` '-u[choose user]:::_users' # `foo -u $USER` (completes from os users) '1:foo:_normal' # positional arg $1 completes to anything (usually defaults to files) '2:bar:_users' # positional arg $2 completes to os users '3:baz:->my-state-name' # $state assigned val 'my-state-name' (use case to set completer) '*:foo:(one two three)' # completes 1x optional un-named param (rest arg) to 'one', 'two' or 'three' '*::foo:(one two three)' # unlimited optional un-named params (rest args) to 'one', 'two' or 'tree'
Syntax
Basics
arguments \ '( ${excludes} )${param}:[:]${message}:${action}'# ${excludes} is an array of param ${state_descr}s # arguments \ # '::one:_normal' \ # '::two:_normal' \ # '(one)::three:(foo bar baz)' # # don't complete 'three' if 'one' has been used# ${param} has different formats depending the param # (or the next param, depending on param type) # ex: '-h[show help]' # flag # ex: '1' # positional # ex: '*' # rest argument(s) # ex: '' # optional# ':' vs '::' # here ${param}:${message}:${action} is a required param # here ${param}::${message}:${action} is an optional param# ${message} is the name of the param # this is the name of the param, when referred to in other completer functions. # it gets bound to ${state_descr}.# ${action} is instructions on how to complete the next param # '1:one:' # ? valid ? # '1:one:(one two three)' # argument must be one, two, or three # '1:one:_user' # argument uses '_user' (function) to provide completionsFlag Arguments
_arguments \ {-h,--help}'[show help]' \ # param: -h/--help # desc: show help # action: (none) '-o[output file]:::_files' \ # param: -o # desc: output file # action: (complete any file)Positional Arguments
# ex: ${position}:${state_descr}:${action} _arguments \ '1:user:_users' \ # 1st positional arg (required) '2:priority:(low med high)' \ # 2nd positional arg (required) (complete to low/med/high) '3::group:_groups' \ # 3nd positional arg (optional)The argument-name is bound to
$state_descr
.Value for last defined Param
:${message}:${action} # reqd completion for prev command ::${message}:${action} # optional completion for prev command_arguments \ {-h,--help}'[show help]' \ '*::extra:(foo bar baz)' \ # any extra parameters, (complete to (foo bar baz)) ':value:(foo bar baz)' # after prev param (extra), always complete one of these wordsRest Arguments
Any arguments not consumed earlier use this completer.
*:${message}:${action} # *::${message}:${action} # *:::${message}:${action} #State Setting/Parsing
The
-C
argument enables state-setting.
This lets you determine the parser that gets used based on the state you set.local state # scope state locally _arguments -C \ '*:extra:->my-state' # sets `$state='my-state'` case $state in (my-state) _arguments '1:foo:(one two three four)' ;; esac
Strategies
TODO:
This section is unclear, requires experimentation and clarity
Subparsers
Sometimes, the use of a particular flag opens up a chain of possible sub-commands. (ex: git add, git commit, ...). This can be handled in ZSH as follows:
#compdef wtest _wtest() { # limit scope of variables used by zsh completer local context state line expl implementation # list of subparsers local -a subparsers subparsers=(archive display data) # Determine completer for subcommand # (based on 1st positional argument) _arguments -C \ {-h,--help}'[show help information]' \ '1:subcommand:compadd -a subparsers' \ '*:: :->subcmd' && return # parsers for each subparser subparser="$words[1]" curcontext="${curcontext%:*}-$subparser:" # <-- unecessary (?) case $subparser in (archive) _arguments -A "-*" \ '-a[append files to archive]' \ '-e[extract files to archive]' ;; (display) _arguments -A "-*" \ '-n[next file in archive]' \ '-p[previous file in archive]' ;; (data) _arguments -A "-*" \ '-s[shuffle order of wallpapers]' ;; (*) _message "unknown sub-command: $subparser" ;; esac } _wtest "$@"Dynamic Arguments
Some Background Info:
$words[]
is an array of all arguments used so far$state
is set in_arguments
. In the below example. If completion is used for '1', the value of $state will be 'country'hello COUNTRY CITY # (where completed city belongs to selected country)#compdef hello _hello() { # limit scope of zsh vars bound by completer local curcontext="$curcontext" state line typeset -A opt_args _arguments \ '1: :->country' \ '*: :->city' case $state in country) _arguments '1:Countries:(France Germany Italy)' ;; *) case $words[2] in France) compadd "$@" Paris Lyon Marseille ;; Germany) compadd "$@" Berlin Munich Dresden ;; Italy) compadd "$@" Rome Napoli Palermo ;; *) _files esac esac } _hello "$@"Params without Flags
I don't think zsh
_arguments
supports params without-
as a prefix.
This is a workaround, treating optional key/val params without-
as subparsers.foo ACTION [user USER] [group GROUP] [-h|--help] # completes foo ACTION [subparser1|subparser2] # redirects to subparser to complete#compdef foo _foo() { local context state state_descr line typeset -A opt_args _arguments -C \ '1:action:->action' \ '*:extra:->extra' \ {-h,--help}'[show help]' \ case $state in (extra) case $words[-1] in subparser1) # call completer for function for subparser1 ;; subparser2) # call completer for function for subparser2 ;; user|group) # last param was user or group. # complete their value. _arguments \ '*:: :_normal' ;; *) # anything else, suggest key/val params _arguments \ '*:: :(user group)' ;; esac ;; *) ;; esac } _foo