summaryrefslogtreecommitdiff
path: root/Completion/Base/_arguments
diff options
context:
space:
mode:
Diffstat (limited to 'Completion/Base/_arguments')
-rw-r--r--Completion/Base/_arguments571
1 files changed, 265 insertions, 306 deletions
diff --git a/Completion/Base/_arguments b/Completion/Base/_arguments
index 5170acb84..bf263d6e9 100644
--- a/Completion/Base/_arguments
+++ b/Completion/Base/_arguments
@@ -3,386 +3,345 @@
# Complete the arguments of the current command according to the
# descriptions given as arguments to this function.
-local long args rest ws cur nth def nm expl descr action opt arg tmp
+local long cmd="$words[1]" descr mesg subopts opt usecc autod
+local oldcontext="$curcontext" hasopts
-# Associative arrays used to collect information about the options.
+long=$argv[(I)--]
+if (( long )); then
+ local name tmp tmpargv
-typeset -A opts mopts dopts dmopts odopts odmopts
-
-# See if we support long options, too.
+ if [[ long -eq 1 ]]; then
+ tmpargv=()
+ else
+ tmpargv=( "${(@)argv[1,long-1]}" )
+ fi
-nth=$argv[(I)--]
-if (( nth )); then
- long=( "${(@)argv[nth+1,-1]}" )
- argv=("${(@)argv[1,nth-1]}")
-else
- long=()
-fi
+ name=${~words[1]}
+ [[ "$name" != /* ]] && tmp="$PWD/$name"
-# Now parse the arguments...
+ name="_args_cache_${name}"
+ name="${name//[^a-zA-Z0-9_]/_}"
-args=()
-nth=1
-while (( $# )); do
+ if (( ! ${(P)+name} )); then
+ local iopts sopts pattern tmpo cur cache
+ typeset -U lopts
- # This describes a one-shot option.
+ cache=()
- if [[ "$1" = [-+]* ]]; then
- if [[ "$1" = *:* ]]; then
+ # We have to build a new long-option cache, get the `-i' and
+ # `-s' options.
- # 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.
+ set -- "${(@)argv[long+1,-1]}"
- if [[ "$1" = [^:]##-:* ]]; then
- dopts[${${1%%:*}[1,-2]}]="${1#*:}"
- elif [[ "$1" = [^:]##+:* ]]; then
- odopts[${${1%%:*}[1,-2]}]="${1#*:}"
+ iopts=()
+ sopts=()
+ while [[ "$1" = -[is]* ]]; do
+ if [[ "$1" = -??* ]]; then
+ tmp="${1[3,-1]}"
+ cur=1
else
- opts[${1%%:*}]="${1#*:}"
+ tmp="$2"
+ cur=2
fi
- else
- opts[$1]=''
- fi
- elif [[ "$1" = \*[-+]* ]]; then
-
- # The same for options that may appear more than once.
-
- if [[ "$1" = *:* ]]; then
- if [[ "$1" = [^:]##-:* ]]; then
- dmopts[${${1[2,-1]%%:*}[1,-2]}]="${1#*:}"
- elif [[ "$1" = [^:]##+:* ]]; then
- odmopts[${${1[2,-1]%%:*}[1,-2]}]="${1#*:}"
+ if [[ "$tmp[1]" = '(' ]]; then
+ tmp=( ${=tmp[2,-2]} )
else
- mopts[${1[2,-1]%%:*}]="${1#*:}"
+ tmp=( "${(@P)tmp}" )
fi
- else
- mopts[${1[2,-1]}]=''
- fi
- elif [[ "$1" = \*:* ]]; then
+ if [[ "$1" = -i* ]]; then
+ iopts=( "$iopts[@]" "$tmp[@]" )
+ else
+ sopts=( "$sopts[@]" "$tmp[@]" )
+ fi
+ shift cur
+ done
- # This is `*:...', describing `all other arguments'.
+ # 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.
- rest="${1[3,-1]}"
- elif [[ "$1" = :* ]]; then
+ lopts=("--${(@)^${(@)${(@)${(@M)${(@ps:\n:j:\n:)${(@)${(@M)${(@f)$(_call options ${~words[1]} --help 2>&1)//\[--/
+--}:#[ ]#-*}//,/
+}}:#[ ]#--*}#*--}%%[], ]*}:#}")
+ lopts=( "${(@)lopts:#--}" )
- # This is `:...', describing `the next argument'.
+ # Now remove all ignored options ...
- args[nth++]="${1#*:}"
- else
+ while (( $#iopts )); do
+ lopts=( ${lopts:#$~iopts[1]} )
+ shift iopts
+ done
- # And this is `n:...', describing the `n'th argument.
+ # ... and add "same" options
- args[${1%%:*}]="${1#*:}"
- nth=$(( ${1%%:*} + 1 ))
- fi
- shift
-done
+ while (( $#sopts )); do
+ lopts=( $lopts ${lopts/$sopts[1]/$sopts[2]} )
+ shift 2 sopts
+ done
-if [[ $#long -ne 0 && "$PREFIX" = --* ]]; then
+ # Then we walk through the descriptions plus a few builtin ones.
- # If the current words starts with `--' and we should use long
- # options, just call...
+ set -- "$@" '*=FILE*:file:_files' \
+ '*=(DIR|PATH)*:directory:_files -/' '*: :'
- _long_options "$long[@]"
-else
+ while (( $# )); do
- # Otherwise parse the command line...
+ # First, we get the pattern and the action to use and take them
+ # from the positional parameters.
- ws=( "${(@)words[2,-1]}" )
- cur=$(( CURRENT-2 ))
- nth=1
+ pattern="${${${(M)1#*[^\\]:}[1,-2]}//\\\\:/:}"
+ descr="${1#${pattern}}"
+ shift
- # ...until the current word is reached.
+ # 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.
- while [[ cur -gt 0 ]]; do
+ tmp=("${(@M)lopts:##$~pattern}")
+ lopts=("${(@)lopts:##$~pattern}")
- # `def' holds the description for the option we are currently after.
- # Check if the next argument for the option is optional.
+ (( $#tmp )) || continue
- if [[ "$def" = :* ]]; then
- opt=yes
- else
opt=''
- fi
- arg=''
-
- # Remove one description/action pair from `def' if that isn't empty.
- if [[ -n "$def" ]]; then
- if [[ "$def" = ?*:*:* ]]; then
- def="${def#?*:*:}"
- else
- def=''
- fi
- else
+ # If there are option strings with a `[=', we take these get an
+ # optional argument.
- # If it is empty, and the word starts with `--' and we should
- # complete long options, just ignore this word, otherwise make sure
- # we test for options below and handle normal arguments.
+ tmpo=("${(@M)tmp:#*\[\=*}")
+ if (( $#tmpo )); then
+ tmp=("${(@)tmp:#*\[\=*}")
+ tmpo=("${(@)${(@)tmpo%%\=*}//[^a-z0-9-]}")
- if [[ $#long -eq 0 || "$ws[1]" != --* ]]; then
- opt=yes
- arg=yes
- else
- def=''
+ if [[ "$descr" = ::* ]]; then
+ cache=( "$cache[@]" "${(@)^tmpo}=${descr}" )
+ else
+ cache=( "$cache[@]" "${(@)^tmpo}=:${descr}" )
+ fi
fi
- 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 are not offered them again.
- def="$opts[$ws[1]]"
- unset "opts[$ws[1]]"
- elif (( $+mopts[$ws[1]] )); then
- def="$mopts[$ws[1]]"
- else
+ # Descriptions with `=': mandatory argument.
- # 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 four loops looking very much alike.
+ tmpo=("${(@M)tmp:#*\=*}")
+ if (( $#tmpo )); then
+ tmp=("${(@)tmp:#*\=*}")
+ tmpo=("${(@)${(@)tmpo%%\=*}//[^a-z0-9-]}")
- if (( $#dopts )); then
+ cache=( "$cache[@]" "${(@)^tmpo}=${descr}" )
+ fi
- # First we get the option names.
+ # Everything else is just added as a option without arguments.
- tmp=( "${(@k)dopts}" )
+ if (( $#tmp )); then
+ tmp=("${(@)tmp//[^a-zA-Z0-9-]}")
+ cache=( "$cache[@]" "$tmp[@]" )
+ fi
+ done
+ eval "${name}=( \"\${(@)cache:# #}\" )"
+ fi
+ set -- "$tmpargv[@]" "${(@P)name}"
+fi
- # Then we loop over them and see if the current word begins
- # with one of the option names.
+subopts=()
+while [[ "$1" = -(O*|C) ]]; do
+ case "$1" in
+ -C) usecc=yes; shift ;;
+ -O) subopts=( "${(@P)2}" ); shift 2 ;;
+ *) subopts=( "${(@P)1[3,-1]}" ); shift ;;
+ esac
+done
- while (( $#tmp )); do
- [[ "$ws[1]" = ${tmp[1]}* ]] && break
- shift 1 tmp
- done
+zstyle -s ":completion:${curcontext}:options" auto-description autod
- if (( $#tmp )); then
+if (( $# )) && comparguments -i "$autod" "$@"; then
+ local nm="$compstate[nmatches]" action noargs aret expl local
+ local next direct odirect equal single match matched ws tmp1 tmp2 tmp3
+ local opts subc prefix suffix
+ local origpre="$PREFIX" origipre="$IPREFIX"
- # 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.
+ if comparguments -D descr action; then
+ comparguments -C subc
+ curcontext="${oldcontext%:*}:$subc"
- opt=''
- def="$dopts[$tmp[1]]"
- unset "dopts[$tmp[1]]"
- if [[ "$def" = ?*:*:* ]]; then
- def="${def#?*:*:}"
- else
- def=''
- fi
- fi
- fi
- if [[ -n "$opt" && $#dmopts -ne 0 ]]; then
- tmp=( "${(@k)dmopts}" )
- while (( $#tmp )); do
- [[ "$ws[1]" = ${tmp[1]}* ]] && break
- shift 1 tmp
- done
-
- if (( $#tmp )); then
- opt=''
- def="$dmopts[$tmp[1]]"
- if [[ "$def" = ?*:*:* ]]; then
- def="${def#?*:*:}"
- else
- def=''
- fi
- fi
- fi
- if [[ -n "$opt" && $#odopts -ne 0 ]]; then
- tmp=( "${(@k)odopts}" )
- while (( $#tmp )); do
- [[ "$ws[1]" = ${tmp[1]}* ]] && break
- shift 1 tmp
- done
-
- if (( $#tmp )); then
- opt=''
- def="$odopts[$tmp[1]]"
- unset "odopts[$tmp[1]]"
-
- # 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 [[ "$ws[1]" != "$tmp[1]" ]]; then
- if [[ "$def" = ?*:*:* ]]; then
- def="${def#?*:*:}"
- else
- def=''
- fi
- fi
- fi
- fi
- if [[ -n "$opt" && $#odmopts -ne 0 ]]; then
- tmp=( "${(@k)odmopts}" )
- while (( $#tmp )); do
- [[ "$ws[1]" = ${tmp[1]}* ]] && break
- shift 1 tmp
- done
-
- if (( $#tmp )); then
- opt=''
- def="$odmopts[$tmp[1]]"
- if [[ "$ws[1]" != "$tmp[1]" ]]; then
- if [[ "$def" = ?*:*:* ]]; then
- def="${def#?*:*:}"
- else
- def=''
- fi
- fi
- 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=''
- (( nth++ ))
- fi
- fi
+ if comparguments -O next direct odirect equal; then
+ opts=yes
+ _tags arguments options
+ else
+ _tags arguments
+ fi
+ else
+ if comparguments -a; then
+ noargs='no more arguments'
+ else
+ noargs='no arguments'
fi
+ comparguments -O next direct odirect equal || return 1
- shift 1 ws
- (( cur-- ))
- done
+ opts=yes
+ _tags options
+ fi
- # Now generate the matches.
+ while true; do
+ while _tags; do
+ if [[ -n "$matched" ]] || _requested arguments; then
+ _description arguments expl "$descr"
+
+ if [[ "$action" = -\>* ]]; then
+ comparguments -W line opt_args
+ state="${${action[3,-1]##[ ]#}%%[ ]#}"
+ if [[ -n "$usecc" ]]; then
+ curcontext="${oldcontext%:*}:$subc"
+ else
+ context="$subc"
+ fi
+ compstate[restore]=''
+ aret=yes
+ else
+ if [[ -z "$local" ]]; then
+ local line
+ typeset -A opt_args
+ local=yes
+ fi
- nm="$compstate[nmatches]"
+ comparguments -W line opt_args
- if [[ -z "$def" || "$def" = :* ]]; then
+ if [[ "$action" = \ # ]]; then
- # We either don't have a description for an argument of an option
- # or we have a description for a optional argument.
+ # An empty action means that we should just display a message.
- if [[ -z "$def" ]]; then
+ [[ -n "$matched" ]] && compadd -n -Q -S '' -s "$SUFFIX" - "$PREFIX"
+ mesg="$descr"
- # If we have none at all, use the one for this argument position.
+ elif [[ "$action" = \(\(*\)\) ]]; then
- def="$args[nth]"
- [[ -z "$def" ]] && def="$rest"
- fi
+ # ((...)) contains literal strings with descriptions.
- # In any case, we have to complete option names here, but we may
- # be in a string that starts with an option names and continues with
- # the first argument, test that (again, four loops).
+ eval ws\=\( "${action[3,-3]}" \)
- opt=yes
- if (( $#dopts )); then
+ _describe "$descr" ws -M "$match" "$subopts[@]"
- # Get the option names.
+ elif [[ "$action" = \(*\) ]]; then
- tmp=( "${(@k)dopts}" )
- while (( $#tmp )); do
- if compset -P "$tmp[1]"; then
+ # Anything inside `(...)' is added directly.
- # The current string starts with the option name, so ignore
- # that and complete the rest of the string.
+ _all_labels arguments expl "$descr" \
+ compadd "$subopts[@]" - ${=action[2,-2]}
+ elif [[ "$action" = \{*\} ]]; then
- def="$dopts[$tmp[1]]"
- opt=''
- break
- fi
- shift 1 tmp
- done
- fi
- if [[ -n "$opt" && $#dmopts -ne 0 ]]; then
- tmp=( "${(@k)dmopts}" )
- while (( $#tmp )); do
- if compset -P "$tmp[1]"; then
- def="$dmopts[$tmp[1]]"
- opt=''
- break
- fi
- shift 1 tmp
- done
- fi
- if [[ -n "$opt" && $#odopts -ne 0 ]]; then
- tmp=( "${(@k)odopts}" )
- while (( $#tmp )); do
- if compset -P "$tmp[1]"; then
- def="$odopts[$tmp[1]]"
- opt=''
- break
- fi
- shift 1 tmp
- done
- fi
- if [[ -n "$opt" && $#odmopts -ne 0 ]]; then
- tmp=( "${(@k)odmopts}" )
- while (( $#tmp )); do
- if compset -P "$tmp[1]"; then
- def="$odmopts[$tmp[1]]"
- opt=''
- break
- fi
- shift 1 tmp
- done
- fi
- if [[ -n "$opt" ]]; then
-
- # We aren't in an argument directly after a option name, so
- # all option names are possible matches.
-
- _description expl option
- compadd "$expl[@]" - "${(@k)opts}" "${(@k)mopts}" \
- "${(@k)dopts}" "${(@k)dmopts}" \
- "${(@k)odopts}" "${(@k)odmopts}"
- fi
- fi
+ # A string in braces is evaluated.
- # Now add the matches from the description, if any.
+ while _next_label arguments expl "$descr"; do
+ eval "$action[2,-2]"
+ done
+ elif [[ "$action" = \ * ]]; then
- if [[ -n "$def" ]]; then
+ # If the action starts with a space, we just call it.
- # Ignore the leading colon describing optional arguments.
+ eval "action=( $action )"
+ while _next_label arguments expl "$descr"; do
+ "$action[@]"
+ done
+ else
- [[ "$def" = :* ]] && def="$def[2,-1]"
+ # Otherwise we call it with the description-arguments.
- # Get the description and the action.
+ eval "action=( $action )"
+ _all_labels arguments expl "$descr" \
+ "$action[1]" "$subopts[@]" "${(@)action[2,-1]}"
+ fi
+ fi
+ fi
- descr="${def%%:*}"
- action="${${def#*:}%%:*}"
+ if [[ -z "$matched$hasopts" ]] && _requested options &&
+ { ! zstyle -T ":completion:${curcontext}:options" prefix-needed ||
+ [[ "$origpre" = [-+]* ||
+ ( -z "$aret$mesg" && nm -eq compstate[nmatches] ) ]] } ; then
+ local prevpre="$PREFIX" previpre="$IPREFIX"
+
+ hasopts=yes
+
+ PREFIX="$origpre"
+ IPREFIX="$origipre"
+
+ comparguments -M match
+
+ if comparguments -s single; then
+
+ _description options expl option
+
+ if [[ "$single" = direct ]]; then
+ compadd "$expl[@]" -QS '' - "${PREFIX}${SUFFIX}"
+ elif [[ "$single" = next ]]; then
+ compadd "$expl[@]" -Q - "${PREFIX}${SUFFIX}"
+ elif [[ "$single" = equal ]]; then
+ compadd "$expl[@]" -QqS= - "${PREFIX}${SUFFIX}"
+ else
+ tmp1=( "$next[@]" "$direct[@]" "$odirect[@]" "$equal[@]" )
+ tmp3=( "${(M@)tmp1:#[-+]?[^:]*}" )
+ tmp1=( "${(M@)tmp1:#[-+]?(|:*)}" )
+ tmp2=( "${PREFIX}${(@M)^${(@)${(@)tmp1%%:*}#[-+]}:#?}" )
+
+ _describe -o option \
+ tmp1 tmp2 -Q -S '' -- \
+ tmp3 -Q
+ fi
+ single=yes
+ else
+ next=( "$next[@]" "$odirect[@]" )
+ _describe -o option \
+ next -Q -M "$match" -- \
+ direct -QS '' -M "$match" -- \
+ equal -QqS= -M "$match"
+ fi
+ PREFIX="$prevpre"
+ IPREFIX="$previpre"
+ fi
+ done
+ if [[ -n "$opts" && -z "$aret$matched$mesg" &&
+ nm -eq compstate[nmatches] ]]; then
- _description expl "$descr"
+ PREFIX="$origpre"
+ IPREFIX="$origipre"
- if [[ -z "$action" ]]; then
+ prefix="${PREFIX#*\=}"
+ suffix="$SUFFIX"
+ PREFIX="${PREFIX%%\=*}"
+ SUFFIX=''
+ compadd -M "$match" -D equal - "${(@)equal%%:*}"
- # An empty action means that we should just display a message.
- _message "$descr"
- return 1
- elif [[ "$action[1]" = \( ]]; then
+ if [[ $#equal -eq 1 ]]; then
+ PREFIX="$prefix"
+ SUFFIX="$suffix"
+ IPREFIX="${IPREFIX}${equal[1]%%:*}="
+ matched=yes
- # Anything inside `(...)' is added directly.
+ comparguments -L "${equal[1]%%:*}" descr action subc
+ curcontext="${oldcontext%:*}:$subc"
- compadd "$expl[@]" - ${=action[2,-2]}
- elif [[ "$action" = \ * ]]; then
+ _tags arguments
- # If the action starts with a space, we just call it.
+ continue
+ fi
+ fi
+ break
+ done
- $=action
- else
+ [[ -z "$aret" || -z "$usecc" ]] && curcontext="$oldcontext"
- # Otherwise we call it with the description-arguments built above.
+ [[ -n "$aret" ]] && return 300
- action=( $=action )
- "$action[1]" "$expl[@]" "${(@)action[2,-1]}"
- fi
- fi
+ [[ -n "$mesg" ]] && _message "$mesg"
+ [[ -n "$noargs" ]] && _message "$noargs"
# Set the return value.
- [[ nm -ne "$compstate[nmatches]" ]]
+ [[ nm -ne "$compstate[nmatches]" ]]
+else
+ return 1
fi