Zsh completion arguments: Difference between revisions
From wikinotes
(→Syntax) |
|||
(18 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
The <code>_arguments</code> function is one method available for producing completions. | The <code>_arguments</code> function is one method available for producing completions. | ||
= Cheat Sheet = | |||
<blockquote> | |||
<syntaxhighlight lang="bash"> | |||
'-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' | |||
</syntaxhighlight> | |||
</blockquote><!-- Cheat Sheet --> | |||
= Syntax = | = Syntax = | ||
Line 25: | Line 39: | ||
# ex: '-h[show help]' # flag | # ex: '-h[show help]' # flag | ||
# ex: '1' # positional | # ex: '1' # positional | ||
# ex: '*' # rest argument(s) | |||
# ex: '' # optional | # ex: '' # optional | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Line 125: | Line 140: | ||
= Strategies = | = Strategies = | ||
<blockquote> | <blockquote> | ||
{{ TODO | | |||
This section is unclear, requires experimentation and clarity }} | |||
== Subparsers == | |||
<blockquote> | |||
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: | |||
<source lang="bash"> | |||
#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 "$@" | |||
</source> | |||
</blockquote><!-- Subparsers --> | |||
== Dynamic Arguments == | |||
<blockquote> | |||
Some Background Info: | |||
* <code>$words[]</code> is an array of all arguments used so far | |||
* <code>$state</code> is set in <code>_arguments</code>. In the below example. If completion is used for '1', the value of $state will be 'country' | |||
<syntaxhighlight lang="bash"> | |||
hello COUNTRY CITY # (where completed city belongs to selected country) | |||
</syntaxhighlight> | |||
<source lang="bash"> | |||
#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 "$@" | |||
</source> | |||
</blockquote><!-- Dynamic Arguments --> | |||
== Params without Flags == | |||
<blockquote> | |||
I don't think zsh <code>_arguments</code> supports params without <code>-</code> as a prefix.<br> | |||
This is a workaround, treating optional key/val params without <code>-</code> as subparsers. | |||
<syntaxhighlight lang="bash"> | |||
foo ACTION [user USER] [group GROUP] [-h|--help] # completes | |||
foo ACTION [subparser1|subparser2] # redirects to subparser to complete | |||
</syntaxhighlight> | |||
<syntaxhighlight lang="bash"> | |||
#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 | |||
</syntaxhighlight> | |||
</blockquote><!-- Params w/o Flags --> | |||
</blockquote><!-- Strategies --> | </blockquote><!-- Strategies --> |
Latest revision as of 03:57, 25 July 2021
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