I have a command with a very structured input like
cmd --help
cmd A -flagA1 X
cmd A -flagA2 Y
cmd B -flagB1 Z
Where X
,Y
,Z
are fixed values and depend on whether A
or B
is enabled.
Ideally, I'm trying to generate an autocomplete script for zsh to have the following behavior
cmd subA <tab> --> display X,Y
cmd subA -<tab> --> display flagA1, flagA2
My current script look like this
#compdef _cmd
_cmd () {
typeset -A opt_args
local state line curcontext="$curcontext" state_descr
_arguments -C \
': :->command' \
': :->subcmd' \
&& ret=0
case $state in
(command)
# local array variable
local -a subcommands
subcommands=(
'A:Do A'
'B:Do B'
)
_describe -t commands 'subcommands' subcommands && ret=0
;;
(subcmd)
case $line[1] in
(A)
_cmd_A_cmd
;;
(B)
;;
esac
;;
esac
}
_cmd_A_cmd () {
typeset -A opt_args
local state line curcontext="$curcontext" state_descr
_arguments -C \
':: :->options' \
': :->subcmd' \
&& ret=0
case $state in
(options)
_arguments
'-flagA1:the flag A1' \
'-flagA2:flag A2'
;;
(subcmd)
_values "A subcommand"\
'X[X option]' \
'Y[Y option]'
;;
esac
}
It works to get command A and B, and within A to get option X,Y, but I can't get the flags to work.
Any help appreciated.
I have a command with a very structured input like
cmd --help
cmd A -flagA1 X
cmd A -flagA2 Y
cmd B -flagB1 Z
Where X
,Y
,Z
are fixed values and depend on whether A
or B
is enabled.
Ideally, I'm trying to generate an autocomplete script for zsh to have the following behavior
cmd subA <tab> --> display X,Y
cmd subA -<tab> --> display flagA1, flagA2
My current script look like this
#compdef _cmd
_cmd () {
typeset -A opt_args
local state line curcontext="$curcontext" state_descr
_arguments -C \
': :->command' \
': :->subcmd' \
&& ret=0
case $state in
(command)
# local array variable
local -a subcommands
subcommands=(
'A:Do A'
'B:Do B'
)
_describe -t commands 'subcommands' subcommands && ret=0
;;
(subcmd)
case $line[1] in
(A)
_cmd_A_cmd
;;
(B)
;;
esac
;;
esac
}
_cmd_A_cmd () {
typeset -A opt_args
local state line curcontext="$curcontext" state_descr
_arguments -C \
':: :->options' \
': :->subcmd' \
&& ret=0
case $state in
(options)
_arguments
'-flagA1:the flag A1' \
'-flagA2:flag A2'
;;
(subcmd)
_values "A subcommand"\
'X[X option]' \
'Y[Y option]'
;;
esac
}
It works to get command A and B, and within A to get option X,Y, but I can't get the flags to work.
Any help appreciated.
Share Improve this question asked Mar 21 at 15:21 DavidbrczDavidbrcz 2,43920 silver badges28 bronze badges1 Answer
Reset to default 2To use _arguments
with below in mind could help especially in some completion codes with subcommands completion:
- describe options (for example
--help[show help]
--flag[some flag]
etc). - put subcommands definitions (
: :->command
). - more arguments (
*:: :->arg
) which means some more subcommands specified or no more arguments.
#compdef _cmd
_cmd () {
typeset -A opt_args
local state line curcontext="$curcontext" state_descr ret=1
_arguments -C : \
'--help[show help]' \
': :->command' \
'*:: :->arg' \
&& ret=0
case $state in
(command)
local -a commands
commands=(
'A:Do A'
'B:Do B')
_describe -t commands 'subcommands' commands && ret=0
;;
(arg)
_call_function ret _cmd-"$line[1]"
;;
esac
return ret
}
_cmd-A () {
typeset -A opt_args
local state line curcontext="$curcontext" state_descr ret=1
_arguments -C : \
'-flagA1[the flag A1]' \
'-flagA2[the flag A2]' \
': :->command' \
'*:: :->arg' \
&& ret=0
case $state in
(command)
_values "A subcommand"\
'X[X option]' \
'Y[Y option]' && ret=0
# local -a commands
# commands=(
# 'X:X option'
# 'Y:Y option')
# _describe -t commands 'A subcommands' commands && ret=0
;;
(arg)
_nothing
;;
esac
return ret
}
If *:: :->arg
specified, this is described in zsh manual (from _arguments
):
*::MESSAGE:ACTION
...
With two colons before the MESSAGE, the words special array and the CURRENT special parameter are modified to refer only to the normal arguments when the ACTION is executed or evaluated.
like this: (*) denotes the cursor's position,
$ cmd A --(*)<TAB>
;; words=(cmd A --), CURRENT=3
;; encounters `*:: ->arg` then,
;; words=(A --), CURRENT=2
;; eventually the function `_cmd-A` gets called
so the function _cmd-A
could be written like an A
command's completion.