about summary refs log tree commit diff
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