1
0
Fork 0
mirror of git://git.code.sf.net/p/zsh/code synced 2025-09-29 19:00:57 +02:00
zsh/Completion/Base/_arguments
1999-09-13 14:00:34 +00:00

913 lines
25 KiB
Text

#autoload
# Complete the arguments of the current command according to the
# descriptions given as arguments to this function.
setopt localoptions extendedglob
local args rest ws cur nth def nm expl descr action opt arg tmp xor
local single uns ret=1 aret soptseq soptseq1 sopts prefix _line odescr
local beg optbeg argbeg nargbeg inopt inrest fromrest cmd="$words[1]"
local matched curopt noargs
# Associative arrays used to collect information about the options.
typeset -A opts dopts odopts xors _options
# Fill the cache if we were called with different arguments.
if [[ "$*" != "$_args_cache_descr" ]]; then
_args_cache_descr="$*"
unset _args_cache_{opts,dopts,odopts,odescr,xors}
typeset -gA _args_cache_{opts,dopts,odopts,xors}
unset _args_cache_{long,longcmd,single,rest,args,sopts,soptseq,soptseq1}
# See if we are using single-letter options.
if [[ "$1" = -s ]]; then
shift
_args_cache_single=yes
fi
# See if we support long options, too.
nth=$argv[(I)--]
if (( nth )); then
local tmpargv
if [[ nth -eq 1 ]]; then
tmpargv=()
else
tmpargv=( "${(@)argv[1,nth-1]}" )
fi
tmp=${~words[1]}
if [[ "$tmp" != /* ]]; then
tmp="$PWD/$tmp"
fi
if [[ "$tmp" != "$_args_cache_longcmd" ]]; then
local iopts pattern tmpo
typeset -U lopts
_args_cache_longcmd="$tmp"
# We have to build the long-option cache anew, get the `-i' and
# `-s' options.
set -- "${(@)argv[nth+1,-1]}"
iopts=()
sopts=()
while [[ "$1" = -[is]* ]]; do
if [[ "$1" = -??* ]]; then
tmp="${1[3,-1]}"
cur=1
else
tmp="$2"
cur=2
fi
if [[ "$tmp[1]" = '(' ]]; then
tmp=( ${=tmp[2,-2]} )
else
tmp=( "${(@P)tmp}" )
fi
if [[ "$1" = -i* ]]; then
iopts=( "$iopts[@]" "$tmp[@]" )
else
sopts=( "$sopts[@]" "$tmp[@]" )
fi
shift cur
done
# Now get the long option names by calling the command with `--help'.
# The parameter expansion trickery first gets the lines as separate
# array elements. Then we select all lines whose first non-blank
# character is a hyphen. Since some commands document more than one
# option per line, separated by commas, we convert commas int
# newlines and then split the result again at newlines after joining
# the old array elements with newlines between them. Then we select
# those elements that start with two hyphens, remove anything up to
# those hyphens and anything from the space or comma after the
# option up to the end.
lopts=("--${(@)^${(@)${(@)${(@M)${(@ps:\n:j:\n:)${(@)${(@M)${(@f)$(${~words[1]} --help 2>&1)//\[--/
--}:#[ ]#-*}//,/
}}:#[ ]#--*}#*--}%%[, ]*}:#}")
# Now remove all ignored options ...
while (( $#iopts )); do
lopts=( ${lopts:#$~iopts[1]} )
shift iopts
done
# ... and add "same" options
while (( $#sopts )); do
lopts=( $lopts ${lopts/$sopts[1]/$sopts[2]} )
shift 2 sopts
done
# Then we walk through the descriptions plus a few builtin ones.
set -- "$@" '*=FILE*:file:_files' \
'*=(DIR|PATH)*:directory:_files -/' '*:unknown:'
while (( $# )); do
# First, we get the pattern and the action to use and take them
# from the positional parameters.
pattern="${${${(M)1#*[^\\]:}[1,-2]}//\\\\:/:}"
descr="${1#${pattern}}"
shift
# We get all options matching the pattern and take them from the
# list we have built. If no option matches the pattern, we
# continue with the next.
tmp=("${(@M)lopts:##$~pattern}")
lopts=("${(@)lopts:##$~pattern}")
(( $#tmp )) || continue
opt=''
# If there are option strings with a `[=', we take these get an
# optional argument.
tmpo=("${(@M)tmp:#*\[\=*}")
if (( $#tmpo )); then
tmp=("${(@)tmp:#*\[\=*}")
tmpo=("${(@)${(@)tmpo%%\=*}//[^a-z0-9-]}")
if [[ "$descr" = ::* ]]; then
_args_cache_long=( "$_args_cache_long[@]"
"${(@)^tmpo}=${descr}" )
else
_args_cache_long=( "$_args_cache_long[@]"
"${(@)^tmpo}=:${descr}" )
fi
fi
# Descriptions with `=': mandatory argument.
tmpo=("${(@M)tmp:#*\=*}")
if (( $#tmpo )); then
tmp=("${(@)tmp:#*\=*}")
tmpo=("${(@)${(@)tmpo%%\=*}//[^a-z0-9-]}")
if [[ "$descr" = ::* ]]; then
_args_cache_long=( "$_args_cache_long[@]"
"${(@)^tmpo}=${descr[2,-1]}" )
else
_args_cache_long=( "$_args_cache_long[@]"
"${(@)^tmpo}=${descr}" )
fi
fi
# Everything else is just added as a option without arguments.
if (( $#tmp )); then
tmp=("${(@)tmp//[^a-zA-Z0-9-]}")
_args_cache_long=( "$_args_cache_long[@]" "$tmp[@]" )
fi
done
fi
_args_cache_long=( "${(@)_args_cache_long:# #}" )
set -- "$tmpargv[@]" "$_args_cache_long[@]"
fi
# Now parse the arguments...
odescr=()
args=()
nth=1
while (( $# )); do
descr=''
xor=''
# Get the names of other values that are mutually exclusive with
# this one.
if [[ "$1" = \(*\)* ]]; then
xor="${${1[2,-1]}%%\)*}"
1="${1#*\)}"
fi
# Get a description, if any.
if [[ "$1" = *\[*\](|:*) ]]; then
descr="${${1#*\[}%%\]*}"
1="${1/\[$descr\]}"
fi
# Description for both the `-foo' and `+foo' form?
if [[ "$1" = (\*|)(-+|+-)[^:]* ]]; then
# With a `*' at the beginning, the option may appear more than
# once.
if [[ "$1" = \** ]]; then
tmp="${1[4,-1]%%:*}"
[[ "$tmp" = *[-+] ]] && tmp="$tmp[1,-2]"
else
tmp="${1[3,-1]%%:*}"
[[ "$tmp" = *[-+] ]] && tmp="$tmp[1,-2]"
xor="$xor -$tmp +$tmp"
fi
# If the option name ends in a `-', the first argument comes
# directly after the option, if it ends in a `+', the first
# argument *may* come directly after the option, otherwise it
# is in the next word.
if [[ "$1" = [^:]##-:* ]]; then
_args_cache_dopts[-$tmp]="${1#*:}"
_args_cache_dopts[+$tmp]="${1#*:}"
elif [[ "$1" = [^:]##[+=]:* ]]; then
_args_cache_odopts[-$tmp]="${1#*:}"
_args_cache_odopts[+$tmp]="${1#*:}"
elif [[ "$1" = *:* ]]; then
_args_cache_opts[-$tmp]="${1#*:}"
_args_cache_opts[+$tmp]="${1#*:}"
else
_args_cache_opts[-$tmp]=''
_args_cache_opts[+$tmp]=''
fi
_args_cache_odescr=( "$_args_cache_odescr[@]" {-,+}"${tmp}:$descr" )
if [[ -n "$xor" ]]; then
_args_cache_xors[-$tmp]="${${xor##[ ]#}%%[ ]#}"
_args_cache_xors[+$tmp]="${${xor##[ ]#}%%[ ]#}"
fi
elif [[ "$1" = (\*|)[-+]* ]]; then
# With a `*' at the beginning, the option may appear more than
# once.
if [[ "$1" = \** ]]; then
tmp="${1[2,-1]%%:*}"
[[ "$tmp" = *[-+] ]] && tmp="$tmp[1,-2]"
else
tmp="${1%%:*}"
[[ "$tmp" = [-+]?*[-+] ]] && tmp="$tmp[1,-2]"
xor="$xor ${tmp%\=}"
fi
# If the option name ends in a `-', the first argument comes
# directly after the option, if it ends in a `+', the first
# argument *may* come directly after the option, otherwise it
# is in the next word.
if [[ "$1" = [^:]##-:* ]]; then
_args_cache_dopts[$tmp]="${1#*:}"
elif [[ "$1" = [^:]##[+=]:* ]]; then
_args_cache_odopts[$tmp]="${1#*:}"
elif [[ "$1" = *:* ]]; then
_args_cache_opts[$tmp]="${1#*:}"
else
_args_cache_opts[$tmp]=''
fi
_args_cache_odescr=( "$_args_cache_odescr[@]" "${tmp%\=}:$descr" )
[[ -n "$xor" ]] &&
_args_cache_xors[${tmp%\=}]="${${xor##[ ]#}%%[ ]#}"
elif [[ "$1" = \*::* ]]; then
# This is `*:...', describing `all other arguments', with argument
# range restriction.
if [[ "$1" = \*:::* ]]; then
_args_cache_rest="*${1[3,-1]}"
else
_args_cache_rest="$1"
fi
elif [[ "$1" = \*:* ]]; then
# This is `*:...', describing `all other arguments'.
_args_cache_rest="${1[3,-1]}"
elif [[ "$1" = :* ]]; then
# This is `:...', describing `the next argument'.
_args_cache_args[nth++]="${1#*:}"
else
# And this is `n:...', describing the `n'th argument.
_args_cache_args[${1%%:*}]="${1#*:}"
nth=$(( ${1%%:*} + 1 ))
fi
shift
done
if [[ -n "$_args_cache_single" ]]; then
_args_cache_soptseq="${(@j::)${(@M)${(@k)_args_cache_opts[(R)]}:#[-+]?}#[-+]}"
if [[ -n "$_args_cache_soptseq" ]]; then
_args_cache_soptseq="[$_args_cache_soptseq]#"
_args_cache_soptseq1="$_args_cache_soptseq#"
else
_args_cache_soptseq=''
_args_cache_soptseq1=''
fi
_args_cache_sopts="${(@j::)${(@)${(@M)${=:-${(k)_args_cache_opts} ${(k)_args_cache_dopts} ${(k)_args_cache_odopts}}:#[-+]?(|=)}#?}%\=}"
else
_args_cache_soptseq=''
_args_cache_soptseq1=''
_args_cache_sopts=''
fi
fi
soptseq="$_args_cache_soptseq"
soptseq1="$_args_cache_soptseq1"
sopts="$_args_cache_sopts"
args=( "$_args_cache_args[@]" )
rest="$_args_cache_rest"
opts=( "${(@kv)_args_cache_opts}" )
dopts=( "${(@kv)_args_cache_dopts}" )
odopts=( "${(@kv)_args_cache_odopts}" )
odescr=( "$_args_cache_odescr[@]" )
xors=( "${(@kv)_args_cache_xors}" )
single="$_args_cache_single"
# Parse the command line...
ws=( "${(@)words[2,-1]}" )
cur=$(( CURRENT-2 ))
nth=1
_line=( "$words[1]" )
beg=2
argbeg=1
optbeg=1
nargbeg=1
# ...until the current word is reached.
while [[ cur -gt 0 ]]; do
if [[ -n "$def" && -n "$curopt" ]]; then
if [[ -n "$_options[$curopt]" ]]; then
_options[$curopt]="$_options[$curopt]:${ws[1]//:/\\:}"
else
_options[$curopt]="${ws[1]//:/\\:}"
fi
fi
# `def' holds the description for the option we are currently after.
# Check if the next argument for the option is optional.
if [[ "$def" = :* ]]; then
opt=yes
else
opt=''
fi
arg=''
# See if we are after an option getting n arguments ended by something
# that matches the current word.
if [[ "$def" = \**[^\\]:* && "$ws[1]" = ${~${(M)def#*[^\\]:}[2,-2]} ]]; then
def=''
curopt=''
shift 1 ws
(( cur-- ))
(( beg++ ))
continue
fi
# Remove one description/action pair from `def' if that isn't empty.
if [[ -n "$def" && "$def" != \** ]]; then
if [[ "$def" = ?*[^\\]:*[^\\]:* ]]; then
def="${def#?*[^\\]:*[^\\]:}"
argbeg="$beg"
else
def=''
curopt=''
fi
elif [[ -z "$def" ]]; then
# Make sure we test for options below and handle normal arguments.
opt=yes
arg=yes
curopt=''
fi
if [[ -n "$opt" ]]; then
# `opt' was set above if we have to test if the word is an option.
# We first test for the simple options -- those without arguments or
# those whose arguments have to be given as separate words.
if (( $+opts[$ws[1]] )); then
# Options that may only be given once are removed from the
# associative array so that we don't offer them again.
def="$opts[$ws[1]]"
curopt="$ws[1]"
_options[$curopt]=''
optbeg="$beg"
argbeg="$beg"
inopt=yes
if [[ -n "$xors[$ws[1]]" ]]; then
if [[ "$xors[$ws[1]]" = (*\ |):(\ *|) ]]; then
args=()
rest=''
fi
odescr=( "${(@)odescr:#(${(j:|:)~${=xors[$ws[1]]}}):*}" )
unset {{,d,od}opts,xors}\[${^=xors[$ws[1]]}\]
fi
else
uns=''
if [[ -n "$sopts" && "$ws[1]" = [-+]${~soptseq}[$sopts] ]]; then
tmp="${ws[1][1]}${ws[1][-1]}"
if (( $+opts[$tmp] )); then
def="$opts[$tmp]"
curopt="$tmp"
_options[$curopt]=''
optbeg="$beg"
argbeg="$beg"
inopt=yes
uns="${ws[1][2,-1]}"
opt=''
fi
fi
# If the word is none of the simple options, test for those
# whose first argument has to or may come directly after the
# option. This is done in two loops looking very much alike.
if [[ -n "$opt" && $#dopts -ne 0 ]]; then
# First we get the option names.
tmp=( "${(@k)dopts}" )
# Then we loop over them and see if the current word begins
# with one of the option names.
while (( $#tmp )); do
if [[ -n "$sopts" && $tmp[1] = [-+]? ]]; then
if [[ "$ws[1]" = ${tmp[1][1]}${~soptseq}${tmp[1][2]}* ]]; then
uns="${ws[1][2,-1]%%${tmp[1][2]}*}${tmp[1][2]}"
break;
fi
elif [[ "$ws[1]" = ${tmp[1]}* ]]; then
break
fi
shift 1 tmp
done
if (( $#tmp )); then
# It does. So use the description for it, but only from
# the second argument on, because we are searching the
# description for the next command line argument.
opt=''
def="$dopts[$tmp[1]]"
curopt="$tmp[1]"
_options[$curopt]="${ws[1]#${tmp[1]}}"
optbeg="$beg"
argbeg="$beg"
inopt=yes
if [[ -n "$xors[$tmp[1]]" ]]; then
if [[ "$xors[$ws[1]]" = (*\ |):(\ *|) ]]; then
args=()
rest=''
fi
odescr=( "${(@)odescr:#(${(j:|:)~${=xors[$tmp[1]]}}):*}" )
unset {{,d,od}opts,xors}\[${^=xors[$tmp[1]]}\]
fi
if [[ "$def" = [^*]*[^\\]:*[^\\]:* ]]; then
def="${def#?*[^\\]:*[^\\]:}"
elif [[ "$def" != \** ]]; then
def=''
fi
fi
fi
if [[ -n "$opt" && $#odopts -ne 0 ]]; then
tmp=( "${(@k)odopts%\=}" )
while (( $#tmp )); do
if [[ -n "$sopts" && $tmp[1] = [-+]? ]]; then
if [[ "$ws[1]" = ${tmp[1][1]}${~soptseq}${tmp[1][2]}* ]]; then
uns="${ws[1][2,-1]%%${tmp[1][2]}*}${tmp[1][2]}"
break;
fi
elif [[ "$ws[1]" = ${tmp[1]}* ]]; then
break
fi
shift 1 tmp
done
if (( $#tmp )); then
opt=''
def="$odopts[$tmp[1]]"
curopt="$tmp[1]"
if [[ -z "$def" ]]; then
def="$odopts[$tmp[1]=]"
if [[ "$ws[1]" = ${tmp[1]}?* ]]; then
_options[$curopt]="${ws[1]#${tmp[1]}=}"
else
_options[$curopt]=''
fi
else
if [[ "$ws[1]" = ${tmp[1]}?* ]]; then
_options[$curopt]="${ws[1]#${tmp[1]}}"
else
_options[$curopt]=''
fi
fi
optbeg="$beg"
argbeg="$beg"
inopt=yes
if [[ -n "$xors[$tmp[1]]" ]]; then
if [[ "$xors[$ws[1]]" = (*\ |):(\ *|) ]]; then
args=()
rest=''
fi
odescr=( "${(@)odescr:#(${(j:|:)~${=xors[$tmp[1]]}}):*}" )
unset {{,d,od}opts,xors}\[${^=xors[$tmp[1]]}\]
fi
# For options whose first argument *may* come after the
# option, we skip over the first description only if there
# is something after the option name on the line.
if [[ ( -z "$sopts" && ( "$def" = :* || "$ws[1]" != "$tmp[1]" ) ) ||
( -n "$sopts" && ( ( $tmp[1] = [-+]? && ( "$def" = :* || "$ws[1]" != "${tmp[1][1]}"${~soptseq}"${tmp[1][2]}" ) ) ||
( $tmp[1] != [-+]? && ( "$def" = :* || "$ws[1]" != "$tmp[1]" ) ) ) ) ]]; then
if [[ "$def" = [^*]*[^\\]:*[^\\]:* ]]; then
def="${def#?*[^\\]:*[^\\]:}"
optbeg="$beg"
argbeg="$beg"
elif [[ "$def" != \** ]]; then
def=''
fi
fi
fi
fi
[[ -n "$sopts" && -n "$opt" && "$ws[1]" = [-+]${~soptseq} ]] && \
uns="${ws[1][2,-1]}"
if [[ -n "$uns" ]]; then
uns="${(@j::)${(v)=xors[(I)${ws[1][1]}[$uns]]}#[-+]}"
if [[ -n "$uns" ]]; then
tmp=(
"opts[${(@)^opts[(I)${ws[1][1]}[$uns]]}]"
"dopts[${(@)^dopts[(I)${ws[1][1]}[$uns]]}]"
"odopts[${(@)^odopts[(I)${ws[1][1]}[$uns]]}]"
"xors[${(@)^xors[(I)${ws[1][1]}[$uns]]}]"
)
odescr=( "${(@)odescr:#${ws[1][1]}[$uns]:*}" )
(( $#tmp )) && unset "$tmp[@]"
fi
fi
# If we didn't find a matching option description and we were
# told to use normal argument descriptions, just increase
# our counter `nth'.
if [[ -n "$opt" && -n "$arg" ]]; then
def=''
_line=( "$_line[@]" "$ws[1]" )
[[ -n "$inopt" ]] && nargbeg=$(( beg - 1 ))
inopt=''
if [[ -z "$args[nth]" && "$rest" = \*::* ]]; then
inrest=yes
break
fi
(( nth++ ))
fi
fi
fi
shift 1 ws
(( cur-- ))
(( beg++ ))
done
[[ -n "$inopt" ]] && nargbeg=$(( beg - 1 ))
# Now generate the matches.
nm="$compstate[nmatches]"
if [[ -z "$def" || "$def" = :* ]]; then
local pre="$PREFIX"
uns=''
# We either don't have a description for an argument of an option
# or we have a description for a optional argument.
opt=yes
if [[ -z "$def" ]]; then
# If we have none at all, use the one for this argument position.
def="$args[nth]"
if [[ -z "$def" ]]; then
def="$rest"
optbeg="$nargbeg"
argbeg="$nargbeg"
fromrest=yes
[[ -n "$inrest" ]] && opt=''
fi
if [[ -z "$def" ]]; then
_message 'no more arguments'
noargs=yes
fi
fi
# In any case, we have to complete option names here, but we may
# be in a string that starts with an option name and continues with
# the first argument, test that (again, two loops).
if [[ -n "$opt" && $#dopts -ne 0 ]]; then
# Get the option names.
tmp=( "${(@k)dopts}" )
prefix="$PREFIX"
while (( $#tmp )); do
if [[ -n "$sopts" && $tmp[1] = [-+]? ]] && compset -P "${tmp[1][1]}${~soptseq}${tmp[1][2]}"; then
def="$dopts[$tmp[1]]"
opt=''
uns="${prefix[2,-1]%%${tmp[1][2]}*}${tmp[1][2]}"
break
elif compset -P "$tmp[1]"; then
# The current string starts with the option name, so ignore
# that and complete the rest of the string.
def="$dopts[$tmp[1]]"
opt=''
break
fi
shift 1 tmp
done
fi
if [[ -n "$opt" && $#odopts -ne 0 ]]; then
tmp=( "${(@k)odopts}" )
prefix="$PREFIX"
while (( $#tmp )); do
if [[ -n "$sopts" && $tmp[1] = [-+]?(|=) ]] && compset -P "${tmp[1][1]}${~soptseq}${tmp[1][2]}${tmp[1][3]}"; then
def="$odopts[$tmp[1]]"
opt=''
uns="${prefix[2,-1]%%${tmp[1][2]}*}${tmp[1][2]}"
break
elif compset -P "$tmp[1]"; then
def="$odopts[$tmp[1]]"
opt=''
break
fi
shift 1 tmp
done
fi
[[ -n "$sopts" && -n "$opt" && "$PREFIX" = [-+]${~soptseq}[$sopts] ]] && \
uns="${PREFIX[2,-1]}"
if [[ -n "$uns" ]]; then
uns="${(@j::)${(v)=xors[(I)${ws[1][1]}[$uns]]}#[-+]}"
if [[ -n "$uns" ]]; then
tmp=(
"opts[${(@)^opts[(I)${pre[1]}[$uns]]}]"
"dopts[${(@)^dopts[(I)${pre[1]}[$uns]]}]"
"odopts[${(@)^odopts[(I)${pre[1]}[$uns](|=)]}]"
"xors[${(@)^xors[(I)${pre[1]}[$uns]]}]"
)
odescr=( "${(@)odescr:#${pre[1]}[$uns]:*}" )
(( $#tmp )) && unset "$tmp[@]"
fi
fi
# If we aren't in an argument directly after a option name, all option
# names are possible matches.
[[ -z "$opt" || ( "$def" = \** &&
( -z "$fromrest" || CURRENT -ne argbeg+1 ) ) ]] && opt=''
else
opt=''
fi
# Now add the matches from the description, if any.
while true; do
if [[ -n "$def" ]]; then
# Ignore the leading colon or `*...' describing optional arguments.
if [[ "$def" = :* ]]; then
def="$def[2,-1]"
elif [[ "$def" = \** ]]; then
tmp="${${(M)def#*[^\\]:}[2,-2]}"
def="${def#*[^\\]:}"
if [[ "$def" = :* ]]; then
if [[ "$def" = ::* ]]; then
def="$def[3,-1]"
beg=$argbeg
else
def="$def[2,-1]"
beg=$optbeg
fi
[[ beg -ge $#words ]] && beg=$(( $#words - 1 ))
shift beg words
(( CURRENT -= beg ))
if [[ -n "$tmp" ]]; then
tmp="$words[(ib:CURRENT:)${~tmp}]"
[[ tmp -le $#words ]] && words=( "${(@)words[1,tmp-1]}" )
fi
fi
fi
# Get the description and the action.
descr="${${${(M)def#*[^\\]:}[1,-2]}//\\\\:/:}"
if [[ "$def" = *[^\\]:*[^\\]:* ]]; then
action="${${${(M)${def#*[^\\]:}#*[^\\]:}[1,-2]}//\\\\:/:}"
else
action="${${def#*[^\\]:}//\\\\:/:}"
fi
_description expl "$descr"
if [[ "$action" = -\>* ]]; then
line=( "$_line[@]" )
options=( "${(@kv)_options}" )
state="${${action[3,-1]##[ ]#}%%[ ]#}"
compstate[restore]=''
aret=yes
else
if [[ "${(t)line}" != *local* ]]; then
local line
typeset -A options
fi
line=( "$_line[@]" )
options=( "${(@kv)_options}" )
if [[ "$action" = \ # ]]; then
# An empty action means that we should just display a message.
[[ -n "$matched" ]] && compadd -n -Q -S '' -s "$SUFFIX" - "$PREFIX"
_message "$descr"
break
elif [[ "$action" = \(\(*\)\) ]]; then
# ((...)) contains literal strings with descriptions.
eval ws\=\( "${action[3,-3]}" \)
if [[ -n "$compconfig[describe_values]" &&
"$compconfig[describe_values]" != *\!${cmd}* ]]; then
if _display tmp ws -M 'r:|[_-]=* r:|=*'; then
compadd "$expl[@]" -y tmp - "${(@)ws%%:*}"
else
[[ -n "$matched" ]] && compadd -Q -S -s "$SUFFIX" - "$PREFIX"
_message "$descr"
fi
else
compadd "$expl[@]" - "${(@)ws%%:*}"
fi
elif [[ "$action" = \(*\) ]]; then
# Anything inside `(...)' is added directly.
compadd "$expl[@]" - ${=action[2,-2]}
elif [[ "$action" = \{*\} ]]; then
# A string in braces is evaluated.
eval "$action[2,-2]"
elif [[ "$action" = \ * ]]; then
# If the action starts with a space, we just call it.
${(e)=~action}
else
# Otherwise we call it with the description-arguments built above.
action=( $=action )
${(e)action[1]} "$expl[@]" ${(e)~action[2,-1]}
fi
fi
fi
# Probably add the option names.
if [[ -n "$opt" &&
( ( ( nm -eq compstate[nmatches] || -n "$noargs" ) && -z "$aret" ) ||
-z "$compconfig[option_prefix]" ||
"$compconfig[option_prefix]" = *\!${cmd}* ||
"$PREFIX" = [-+]* ) ]]; then
_description expl option
if [[ -n "$sopts" && -n "$PREFIX" &&
"$PREFIX" = [-+]${~soptseq}[$sopts] ]]; then
if [[ "$PREFIX" = [-+]${~soptseq1} ]]; then
local dpre="$PREFIX" dsuf="$SUFFIX"
PREFIX=''
SUFFIX=''
if [[ -z "$compconfig[describe_options]" ||
"$compconfig[describe_options]" = *\!${cmd}* ]] ||
! _display tmp odescr; then
tmp=( "${dpre[1]}${(@o)^${(@)${(@M)${=:-${(k)opts} ${(k)dopts} ${(k)odopts}}:#[-+]?(|=)}#?}%=}" )
fi
PREFIX="$dpre"
SUFFIX="$dsuf"
compadd "$expl[@]" -Q -M 'r:|[_-]=* r:|=*' -y tmp - \
"${PREFIX}${(@k)^opts[(I)${PREFIX[1]}?]#?}" \
"${PREFIX}${(@k)^dopts[(I)${PREFIX[1]}?]#?}" \
"${PREFIX}${(@)^${(@k)odopts[(I)${PREFIX[1]}?(|=)]#?}%=}" &&
ret=0
else
# The last option takes an argument in the next word.
compadd "$expl[@]" -Q -M 'r:|[_-]=* r:|=*' - "${PREFIX}" && ret=0
fi
else
tmp=''
if [[ -n "$compconfig[describe_options]" &&
"$compconfig[describe_options]" != *\!${cmd}* ]]; then
if _display tmp odescr; then
if (( $#dopts )); then
compadd -n "$expl[@]" -QS '' -M 'r:|[_-]=* r:|=*' -y tmp - \
"${(@k)dopts}" && ret=0
compadd -n -J option -Q -M 'r:|[_-]=* r:|=*' - \
"${(@k)opts}" "${(@k)odopts[(I)*[^=]]}" && ret=0
compadd -n -J option -QqS= -M 'r:|[_-]=* r:|=*' - \
"${(@k)odopts[(I)*=]%=}" && ret=0
elif (( ${(@k)#odopts[(I)*=]} )); then
compadd -n "$expl[@]" -QqS= -M 'r:|[_-]=* r:|=*' -y tmp - \
"${(@k)odopts[(I)*=]%=}" && ret=0
compadd -n -J option -Q -M 'r:|[_-]=* r:|=*' - \
"${(@k)opts}" "${(@k)odopts[(I)*[^=]]}" && ret=0
else
compadd -n "$expl[@]" -Q -M 'r:|[_-]=* r:|=*' -y tmp - \
"${(@k)opts}" "${(@k)odopts[(I)*[^=]]}" && ret=0
fi
fi
fi
if [[ -z "$tmp" ]]; then
compadd "$expl[@]" -Q -M 'r:|[_-]=* r:|=*' - \
"${(@k)opts}" "${(@k)odopts[(I)*[^=]]}" && ret=0
compadd "$expl[@]" -QqS= -M 'r:|[_-]=* r:|=*' - \
"${(@k)odopts[(I)*=]%=}" && ret=0
compadd "$expl[@]" -QS '' -M 'r:|[_-]=* r:|=*' - \
"${(@k)dopts}" && ret=0
fi
fi
fi
if [[ nm -eq compstate[nmatches] &&
( -z "$single" ||
( $#_args_cache_long -ne 0 && "$PREFIX" = --*=* ) ) ]]; then
local suffix
tmp=( "${(@Mk)odopts:#[^:]#\=}" )
prefix="${PREFIX#*\=}"
suffix="$SUFFIX"
PREFIX="${PREFIX%%\=*}"
SUFFIX=''
compadd -M 'r:|[_-]=* r:|=*' -D tmp - "${(@)tmp%\=}"
if [[ $#tmp -eq 1 ]]; then
def="$odopts[$tmp[1]]"
PREFIX="$prefix"
SUFFIX="$suffix"
IPREFIX="$tmp[1]"
matched=yes
continue
fi
fi
break
done
[[ -n "$aret" ]] && return 300
# Set the return value.
[[ nm -ne "$compstate[nmatches]" ]]