about summary refs log tree commit diff
path: root/Completion/Base
diff options
context:
space:
mode:
authorTanaka Akira <akr@users.sourceforge.net>1999-10-12 09:32:45 +0000
committerTanaka Akira <akr@users.sourceforge.net>1999-10-12 09:32:45 +0000
commit0f076fcde8a342c081b8eab0a2f135335d552d79 (patch)
tree13bf91d328057d7b41df879e7ad80128f70baeab /Completion/Base
parent0749034911b1e28d4d9abba5472201972a5e37ce (diff)
downloadzsh-0f076fcde8a342c081b8eab0a2f135335d552d79.tar.gz
zsh-0f076fcde8a342c081b8eab0a2f135335d552d79.tar.xz
zsh-0f076fcde8a342c081b8eab0a2f135335d552d79.zip
manual/8219
Diffstat (limited to 'Completion/Base')
-rw-r--r--Completion/Base/_arguments1022
-rw-r--r--Completion/Base/_describe104
-rw-r--r--Completion/Base/_values339
3 files changed, 261 insertions, 1204 deletions
diff --git a/Completion/Base/_arguments b/Completion/Base/_arguments
index 173a23a73..9875d979b 100644
--- a/Completion/Base/_arguments
+++ b/Completion/Base/_arguments
@@ -5,904 +5,294 @@
 
 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 i tmp1 tmp2 tmp3 suffix match
+local long cmd="$words[1]" descr
 
-# Associative arrays used to collect information about the options.
+long=$argv[(I)--]
+if (( long )); then
+  local name tmp tmpargv
 
-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,match,rest,args,sopts,soptseq,soptseq1}
-
-  # Default match spec.
-
-  _args_cache_match='r:|[_-]=* r:|=*'
-
-  # See if we are using single-letter options or have a match spec.
-
-  while [[ "$1" = -(s|M*) ]]; do
-    if [[ "$1" = -s ]]; then
-      shift
-      _args_cache_single=yes
-    elif [[ "$1" = -M?* ]]; then
-      _args_cache_match="${1[3,-1]}"
-      shift
-    else
-      _args_cache_match="$2"
-      shift 2
-    fi
-  done
-
-  # See if we support long options, too.
-
-  nth=$argv[(I)--]
-  if (( nth )); then
-    local tmpargv
+  if [[ long -eq 1 ]]; then
+    tmpargv=()
+  else
+    tmpargv=( "${(@)argv[1,long-1]}" )
+  fi
 
-    if [[ nth -eq 1 ]]; then
-      tmpargv=()
-    else
-      tmpargv=( "${(@)argv[1,nth-1]}" )
-    fi
+  name=${~words[1]}
+  if [[ "$name" != /* ]]; then
+    tmp="$PWD/$name"
+  fi
+  name="_args_cache_${name}"
+  name="${name//[^a-zA-Z0-9_]/_}"
 
-    tmp=${~words[1]}
-    if [[ "$tmp" != /* ]]; then
-      tmp="$PWD/$tmp"
-    fi
+  if (( ! ${(P)+name} )); then
+    local iopts sopts pattern tmpo cur opt cache
+    typeset -U lopts
 
-    if [[ "$tmp" != "$_args_cache_longcmd" ]]; then
-      local iopts pattern tmpo
-      typeset -U lopts
+    cache=()
 
-      _args_cache_longcmd="$tmp"
+    # We have to build a new long-option cache, get the `-i' and
+    # `-s' options.
 
-      # We have to build the long-option cache anew, get the `-i' and
-      # `-s' options.
+    set -- "${(@)argv[long+1,-1]}"
 
-      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
 
-      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 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
+    # Now remove all ignored options ...
 
-      # ... 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.
+    while (( $#iopts )); do
+      lopts=( ${lopts:#$~iopts[1]} )
+      shift iopts
+    done
 
-      set -- "$@" '*=FILE*:file:_files' \
-             '*=(DIR|PATH)*:directory:_files -/' '*: :'
+    # ... and add "same" options
 
-      while (( $# )); do
+    while (( $#sopts )); do
+      lopts=( $lopts ${lopts/$sopts[1]/$sopts[2]} )
+      shift 2 sopts
+    done
 
-        # First, we get the pattern and the action to use and take them
-        # from the positional parameters.
+    # Then we walk through the descriptions plus a few builtin ones.
 
-        pattern="${${${(M)1#*[^\\]:}[1,-2]}//\\\\:/:}"
-        descr="${1#${pattern}}"
-        shift
+    set -- "$@" '*=FILE*:file:_files' \
+           '*=(DIR|PATH)*:directory:_files -/' '*: :'
 
-        # 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 (( $# )); do
 
-        tmp=("${(@M)lopts:##$~pattern}")
-        lopts=("${(@)lopts:##$~pattern}")
+      # First, we get the pattern and the action to use and take them
+      # from the positional parameters.
 
-        (( $#tmp )) || continue
+      pattern="${${${(M)1#*[^\\]:}[1,-2]}//\\\\:/:}"
+      descr="${1#${pattern}}"
+      shift
 
-        opt=''
+      # 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.
 
-        # If there are option strings with a `[=', we take these get an
-        # optional argument.
+      tmp=("${(@M)lopts:##$~pattern}")
+      lopts=("${(@)lopts:##$~pattern}")
 
-        tmpo=("${(@M)tmp:#*\[\=*}")
-        if (( $#tmpo )); then
-          tmp=("${(@)tmp:#*\[\=*}")
-          tmpo=("${(@)${(@)tmpo%%\=*}//[^a-z0-9-]}")
+      (( $#tmp )) || continue
 
-	  if [[ "$descr" = ::* ]]; then
-	    _args_cache_long=( "$_args_cache_long[@]"
-	                       "${(@)^tmpo}=${descr}" )
-          else
-	    _args_cache_long=( "$_args_cache_long[@]"
-	                       "${(@)^tmpo}=:${descr}" )
-          fi
-        fi
+      opt=''
 
-	# Descriptions with `=': mandatory argument.
+      # 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-]}")
+      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
+        if [[ "$descr" = ::* ]]; then
+	  cache=( "$cache[@]" "${(@)^tmpo}=${descr}" )
+        else
+	  cache=( "$cache[@]" "${(@)^tmpo}=:${descr}" )
         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\]}"
-    elif [[ -n "$compconfig[autodescribe_options]" &&
-            "$1" = [-+][^:]##:[^:]#[^\\]:[^:]# ]]; then
-      descr="${${${${(M)${1#*:}#*[^\\]:}[1,-2]}## #}%% #}"
-      [[ -n "$descr" ]] && descr="${compconfig[autodescribe_options]//\\%d/$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
+      # Descriptions with `=': mandatory argument.
 
-      _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
+      tmpo=("${(@M)tmp:#*\=*}")
+      if (( $#tmpo )); then
+        tmp=("${(@)tmp:#*\=*}")
+        tmpo=("${(@)${(@)tmpo%%\=*}//[^a-z0-9-]}")
 
-      # 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]=''
+        if [[ "$descr" = ::* ]]; then
+	  cache=( "$cache[@]" "${(@)^tmpo}=${descr[2,-1]}" )
+        else
+	  cache=( "$cache[@]" "${(@)^tmpo}=${descr}" )
+        fi
       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.
+      # Everything else is just added as a option without arguments.
 
-      if [[ "$1" = \*:::* ]]; then
-        _args_cache_rest="*${1[3,-1]}"
-      else
-        _args_cache_rest="$1"
+      if (( $#tmp )); then
+        tmp=("${(@)tmp//[^a-zA-Z0-9-]}")
+	cache=( "$cache[@]" "$tmp[@]" )
       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=''
+    done
+    eval "${name}=( \"\${(@)cache:# #}\" )"
   fi
+  set -- "$tmpargv[@]" "${(@P)name}"
 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"
-match="$_args_cache_match"
-
-# 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
+if comparguments -i "$compconfig[autodescribe_options]" "$@"; then
+  local nm="$compstate[nmatches]" action noargs aret expl local
+  local next direct odirect equal single match matched ws tmp1 tmp2
 
-  # `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"
+  if ! comparguments -D descr action; then
+    if comparguments -a; then
+      noargs='no more arguments'
     else
-      def=''
-      curopt=''
+      noargs='no arguments'
     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
+  while true; do
 
-    # `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 [[ -z "$noargs" || -n "$matched" ]]; then
+      _description expl "$descr"
 
-    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"
-	  for i in ${(s::)ws[1][2,-1]}; do
-            _options[${ws[1][1]}$i]=''
-	  done
-	  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::)${(M@)${(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
+      if [[ "$action" = -\>* ]]; then
+        comparguments -W line options
+        state="${${action[3,-1]##[ 	]#}%%[ 	]#}"
+        compstate[restore]=''
+        aret=yes
+      else
+        if [[ -z "$local" ]]; then
+          local line
+          typeset -A options
+          local=yes
         fi
-	(( nth++ ))
-      fi
-    fi
-  fi
 
-  shift 1 ws
-  (( cur-- ))
-  (( beg++ ))
-done
+        comparguments -W line options
 
-[[ -n "$inopt" ]] && nargbeg=$(( beg - 1 ))
+        if [[ "$action" = \ # ]]; then
 
-# Now generate the matches.
+          # An empty action means that we should just display a message.
 
-nm="$compstate[nmatches]"
+          [[ -n "$matched" ]] && compadd -n -Q -S '' -s "$SUFFIX" - "$PREFIX"
+          _message "$descr"
+          break
 
-if [[ -z "$def" || "$def" = :* ]]; then
-  local pre="$PREFIX"
+        elif [[ "$action" = \(\(*\)\) ]]; then
 
-  uns=''
+          # ((...)) contains literal strings with descriptions.
 
-  # We either don't have a description for an argument of an option
-  # or we have a description for a optional argument.
+          eval ws\=\( "${action[3,-3]}" \)
 
-  opt=yes
+          _describe -c "$cmd" "$descr" ws -M "$match"
 
-  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
-      if [[ -z "$args$rest" ]]; then
-        noargs='no arguments'
-      else
-        noargs='no more arguments'
-      fi
-    fi
-  fi
+        elif [[ "$action" = \(*\) ]]; then
 
-  # 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]}"
-	for i in ${(s::)prefix[2,-1]%%${tmp[1][2]}*} ${tmp[1][2]}; do
-	  _options[${prefix[1]}$i]=''
-	done
-	noargs=''
-	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=''
-	noargs=''
-	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]}"
-	for i in ${(s::)prefix[2,-1]%%${tmp[1][2]}*} ${tmp[1][2]}; do
-	  _options[${prefix[1]}$i]=''
-	done
-	noargs=''
-	break
-      elif compset -P "$tmp[1]"; then
-	def="$odopts[$tmp[1]]"
-	opt=''
-	noargs=''
-	break
-      fi
-      shift 1 tmp
-    done
-  fi
-
-  [[ -n "$sopts" && -n "$opt" && "$PREFIX" = [-+]${~soptseq}[$sopts] ]] &&
-      uns="${PREFIX[2,-1]}"
-
-  if [[ -n "$uns" ]]; then
-    uns="${(@j::)${(M@)${(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
+          # Anything inside `(...)' is added directly.
 
-# Now add the matches from the description, if any.
+          compadd "$expl[@]" - ${=action[2,-2]}
+        elif [[ "$action" = \{*\} ]]; then
 
-while true; do
+          # A string in braces is evaluated.
 
-  if [[ -n "$def" ]]; then
+          eval "$action[2,-2]"
 
-    # Ignore the leading colon or `*...' describing optional arguments.
+        elif [[ "$action" = \ * ]]; then
 
-    if [[ "$def" = :* ]]; then
-      def="$def[2,-1]"
-    elif [[ "$def" = \** ]]; then
-      tmp="${${(M)def#*[^\\]:}[2,-2]}"
-      def="${def#*[^\\]:}"
+          # If the action starts with a space, we just call it.
 
-      if [[ "$def" = :* ]]; then
-        if [[ "$def" = ::* ]]; then
-          def="$def[3,-1]"
-	  beg=$argbeg
+          ${(e)=~action}
         else
-	  def="$def[2,-1]"
-	  beg=$optbeg
-        fi
-
-        [[ beg -ge $#words ]] && beg=$(( $#words - 1 ))
 
-        shift beg words
-        (( CURRENT -= beg ))
+          # Otherwise we call it with the description-arguments built above.
 
-        if [[ -n "$tmp" ]]; then
-          tmp="$words[(ib:CURRENT:)${~tmp}]"
-	  [[ tmp -le $#words ]] && words=( "${(@)words[1,tmp-1]}" )
+          action=( $=action )
+          ${(e)action[1]} "$expl[@]" ${(e)~action[2,-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]}" \)
-
-        _describe -c "$cmd" "$descr" ws -M "$match"
-
-      elif [[ "$action" = \(*\) ]]; then
-
-        # Anything inside `(...)' is added directly.
-
-        compadd "$expl[@]" - ${=action[2,-2]}
-      elif [[ "$action" = \{*\} ]]; then
+    if [[ -z "$matched" ]] &&
+       comparguments -O next direct odirect equal &&
+       [[ ( ( nm -eq compstate[nmatches] || -n "$noargs" ) && -z "$aret" ) ||
+          -z "$compconfig[option_prefix]" || 
+          "$compconfig[option_prefix]" = *\!${cmd}* ||
+          "$PREFIX" = [-+]* ]]; then
 
-        # A string in braces is evaluated.
+      comparguments -M match
 
-        eval "$action[2,-2]"
+      if comparguments -s single; then
 
-      elif [[ "$action" = \ * ]]; then
+        _description expl option
 
-        # If the action starts with a space, we just call it.
+        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[@]" )
+	  tmp2=( "${PREFIX}${(@)^tmp1%%:*}" )
 
-        ${(e)=~action}
+          _describe -o -c "$cmd" option tmp1 tmp2 -Q -S ''
+        fi
+        single=yes
       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
-        tmp1=( "${(@Mo)odescr:#[-+]?:*}" )
-        tmp2=(
-               "${PREFIX}${(@k)^opts[(I)${PREFIX[1]}?]#?}" \
-	       "${PREFIX}${(@k)^dopts[(I)${PREFIX[1]}?]#?}" \
-	       "${PREFIX}${(@)^${(@k)odopts[(I)${PREFIX[1]}?(|=)]#?}%=}"
-        )
-        tmp2=( "${(@o)tmp2}" )
-
+        next=( "$next[@]" "$odirect[@]" )
         _describe -o -c "$cmd" option \
-          tmp1 tmp2  -Q -M 'r:|[_-]=* r:|=*'
-      else
-        # The last option takes an argument in the next word.
-
-        compadd "$expl[@]" -Q -M "$match" - "${PREFIX}" && ret=0
+          next -Q -M "$match" -- \
+          direct -QS '' -M "$match" -- \
+          equal -QqS= -M "$match"
       fi
-    else
-      tmp1=( "${(@k)opts}" "${(@k)odopts[(I)*[^=]]}" )
-      tmp1=( "${(@M)odescr:#(${(j:|:)~tmp1}):*}" )
-      tmp2=( "${(@M)odescr:#(${(kj:|:)~dopts}):*}" )
-      tmp3=( "${(@M)odescr:#(${(kj:|:)~odopts[(I)*=]%=}):*}" )
-      _describe -o -c "$cmd" option \
-        tmp1 -Q -M "$match" -- \
-        tmp2 -QS '' -M "$match" -- \
-        tmp3 -QqS= -M "$match"
-    fi
-  fi
 
-  if [[ nm -eq compstate[nmatches] && 
-        ( ( -z "$single" && "$PREFIX" = [-+]*\=* ) ||
-          ( $#_args_cache_long -ne 0 && "$PREFIX" = --*\=* ) ) ]]; then
-    tmp=( "${(@Mk)odopts:#[^:]#\=}" )
-    prefix="${PREFIX#*\=}"
-    suffix="$SUFFIX"
-    PREFIX="${PREFIX%%\=*}"
-    SUFFIX=''
-    compadd -M "$match" -D tmp - "${(@)tmp%\=}"
-
-    if [[ $#tmp -eq 1 ]]; then
-      def="$odopts[$tmp[1]]"
-      PREFIX="$prefix"
-      SUFFIX="$suffix"
-      IPREFIX="$tmp[1]"
-      matched=yes
-      continue
+      if [[ nm -eq compstate[nmatches] && -z "$aret" &&
+            ( ( -z "$single" && "$PREFIX" = [-+]*\=* ) ||
+              "$PREFIX" = --* ) ]]; then
+
+        local prefix suffix
+
+	prefix="${PREFIX#*\=}"
+	suffix="$SUFFIX"
+	PREFIX="${PREFIX%%\=*}"
+	SUFFIX=''
+	compadd -M "$match" -D equal - "${(@)equal%%:*}"
+
+        if [[ $#equal -eq 1 ]]; then
+	  PREFIX="$prefix"
+	  SUFFIX="$suffix"
+	  IPREFIX="${IPREFIX}${equal[1]%%:*}="
+	  matched=yes
+	  comparguments -L "$equal[1]" descr action
+	  continue
+	fi
+      fi
     fi
-  fi
+    break
+  done
 
-  break
-done
+  [[ -n "$aret" ]] && return 300
 
-[[ -n "$aret" ]] && return 300
+  [[ -n "$noargs" ]] && _message "$noargs"
 
-[[ -n "$noargs" ]] && _message "$noargs"
+  # Set the return value.
 
-# Set the return value.
+  [[ nm -ne "$compstate[nmatches]" ]]
 
-[[ nm -ne "$compstate[nmatches]" ]]
+else
+  return 1
+fi
diff --git a/Completion/Base/_describe b/Completion/Base/_describe
index c95674121..c0b3d7174 100644
--- a/Completion/Base/_describe
+++ b/Completion/Base/_describe
@@ -4,8 +4,7 @@
 
 setopt localoptions extendedglob
 
-local gdescr isopt cmd opt nsets tmp descr match descrs matches adescr i
-local disps disp expl tmps tmpd tmpmd tmpms name ret=1 showd _nm
+local isopt cmd opt expl tmps tmpd tmpmd tmpms ret=1 showd _nm hide
 
 cmd="$words[1]"
 
@@ -45,101 +44,22 @@ else
      "$compconfig[describe_values]" != *\!${cmd}* ]] && showd=yes
 fi
 
-gdescr="$1"
+_description expl "$1"
 shift
 
-# Now interpret the arguments.
-
-nsets=0
-adescr=()
-descrs=()
-matches=()
-while (( $# )); do
-  (( nsets++ ))
-  descr="$1"
-  [[ -n "$showd" ]] && adescr=( "$adescr[@]" "${(@PM)^descr:#*:?*},$nsets" )
-  if [[ $# = 1 || "$2" = -* ]]; then
-    match=''
-    shift
-  else
-    match="$2"
-    shift 2
-  fi
-  tmp=$argv[(i)--]
-  if [[ tmp -eq 1 ]]; then
-    opt=()
-  else
-    opt=( "${(@)argv[1,tmp-1]}" )
-  fi
-  if [[ tmp -gt $# ]]; then
-    argv=()
-  else
-    shift tmp
-  fi
-
-  # `descr' and `matches' collect the names of the arrays containing the
-  # possible matches with descriptions and the matches to add.
-  # The options to give to `compadd' are stored in local arrays.
+if [[ -n "$showd" ]]; then
+  compdescribe -I ' -- ' "$@"
+else
+  compdescribe -i ' -- ' "$@"
+fi
 
-  descrs[nsets]="$descr"
-  matches[nsets]="$match"
-  typeset -a _descr_opts_$nsets
-  eval "_descr_opts_${nsets}=( \"\$opt[@]\" )"
-done
+[[ -n "$isopt" && "$compconfig[option_prefix]" = hide* ]] && hide=yes
 
-(( nsets )) || return 1
-
-# Build the display strings if needed.
-
-[[ -n "$showd" ]] && _display disps "$adescr[@]"
-_description expl "$gdescr"
-
-# Loop through the array/option sets we have.
-
-i=0
-while [[ ++i -le nsets ]]; do
-  name=_descr_opts_$i
-  [[ -n "$showd" ]] && disp=( "${(@)${(@M)disps:#*,${i}}%,*}" )
-  descr=( "${(@P)descrs[i]}" )
-
-  # We collect the strings to display in `tmpd' (one string per line)
-  # and `tmps' (in columns) and the matches to add in `tmpmd' and `tmpms'.
-
-  tmpd=()
-  tmps=()
-  tmpmd=()
-  tmpms=()
-  if [[ -n "$matches[i]" ]]; then
-    match=( "${(@P)matches[i]}" )
-    while (( $#match )); do
-      if [[ -n "$showd" && "$descr[1]" = *:?* ]]; then
-	tmpd=( "$tmpd[@]" "$disp[1]" )
-        tmpmd=( "$tmpmd[@]" "$match[1]" )
-        shift 1 disp
-      else
-        tmps=( "$tmps[@]" "${descr[1]%%:*}" )
-        tmpms=( "$tmpms[@]" "$match[1]" )
-      fi
-      shift 1 match
-      shift 1 descr
-    done
-  else
-    while (( $#descr )); do
-      if [[ -n "$showd" && "$descr[1]" = *:?* ]]; then
-	tmpd=( "$tmpd[@]" "$disp[1]" )
-        tmpmd=( "$tmpmd[@]" "${descr[1]%%:*}" )
-        shift 1 disp
-      else
-        tmps=( "$tmps[@]" "${descr[1]%%:*}" )
-        tmpms=( "$tmpms[@]" "${descr[1]%%:*}" )
-      fi
-      shift 1 descr
-    done
-  fi
+while compdescribe -g args tmpd tmpmd tmps tmpms; do
 
   # See if we should remove the option prefix characters.
 
-  if [[ -n "$isopt" && "$compconfig[option_prefix]" = hide* ]]; then
+  if [[ -n "$hide" ]]; then
     if [[ "$PREFIX" = --* ]]; then
       tmpd=( "${(@)tmpd#--}" )
       tmps=( "${(@)tmps#--}" )
@@ -148,8 +68,8 @@ while [[ ++i -le nsets ]]; do
       tmps=( "${(@)tmps#[-+]}" )
     fi
   fi
-  compadd "${(@P)name}" "$expl[@]" -ld tmpd - "$tmpmd[@]" && ret=0
-  compadd "${(@P)name}" "$expl[@]" -d tmps - "$tmpms[@]" && ret=0
+  compadd "$args[@]" "$expl[@]" -ld tmpd - "$tmpmd[@]" && ret=0
+  compadd "$args[@]" "$expl[@]" -d tmps - "$tmpms[@]" && ret=0
 done
 
 return ret
diff --git a/Completion/Base/_values b/Completion/Base/_values
index 5b413313b..aff2f92d8 100644
--- a/Completion/Base/_values
+++ b/Completion/Base/_values
@@ -2,328 +2,71 @@
 
 setopt localoptions extendedglob
 
-local name arg def descr xor str tmp ret=1 expl nm="$compstate[nmatches]"
-local snames odescr gdescr sep esep spat tmp1 tmp2 tmp3 opts
-typeset -A names onames xors _values
+if compvalues -i "$@"; then
 
-# Probably fill our cache.
+  local noargs args opts descr action expl sep
 
-if [[ "$*" != "$_vals_cache_args" ]]; then
-  _vals_cache_args="$*"
+  if ! compvalues -D descr action; then
+    compvalues -V noargs args opts
 
-  unset _vals_cache_{sep,esep,descr,names,onames,snames,xors,odescr}
-
-  typeset -gA _vals_cache_{names,onames,xors}
-  _vals_cache_snames=()
-  _vals_cache_odescr=()
-
-  # Get the separator, if any.
-
-  if [[ "$1" = -s ]]; then
-    _vals_cache_sep="$2"
-    [[ -z "$2" ]] && _vals_cache_esep=yes
-    shift 2
-  fi
-
-  # This is the description string for the values.
-
-  _vals_cache_descr="$1"
-  shift
-
-  # Now parse the descriptions.
-
-  while (( $# )); do
-
-    # Get the `name', anything before an unquoted colon.
-
-    if [[ "$1" = *[^\\]:* ]]; then
-      name="${${${(M)1#*[^\\]:}[1,-2]}//\\\\:/:}"
-    else
-      name="$1"
-    fi
-
-    descr=''
-    xor=''
-
-    # Get a description, if any.
-
-    if [[ "$name" = *\[*\] ]]; then
-      descr="${${name#*\[}[1,-2]}"
-      name="${name%%\[*}"
-    fi
-
-    # Get the names of other values that are mutually exclusive with
-    # this one.
-
-    if [[ "$name" = \(*\)* ]]; then
-      xor="${${name[2,-1]}%%\)*}"
-      name="${name#*\)}"
-    fi
-
-    # Finally see if this value may appear more than once.
-
-    if [[ "$name" = \** ]]; then
-      name="$name[2,-1]"
-    else
-      xor="$xor $name"
-    fi
-
-    # Store the information in the cache.
-
-    _vals_cache_odescr=( "$_vals_cache_odescr[@]" "${name}:$descr" )
-    [[ -n "$xor" ]] && _vals_cache_xors[$name]="${${xor##[ 	]#}%%[ 	]#}"
-
-    # Get the description and store that.
-
-    if [[ "$1" = *[^\\]:* ]]; then
-      descr=":${1#*[^\\]:}"
-    else
-      descr=''
-    fi
-
-    if [[ "$descr" = ::* ]]; then
-
-       # Optional argument.
-
-      _vals_cache_onames[$name]="$descr[3,-1]"
-    elif [[ "$descr" = :* ]]; then
-
-      # Mandatory argument.
-
-      _vals_cache_names[$name]="$descr[2,-1]"
-    else
-
-      # No argument.
-
-      _vals_cache_snames=( "$_vals_cache_snames[@]" "$name" )
-    fi
-    shift
-  done
-fi
-
-snames=( "$_vals_cache_snames[@]" )
-names=( "${(@kv)_vals_cache_names}" )
-onames=( "${(@kv)_vals_cache_onames}" )
-xors=( "${(@kv)_vals_cache_xors}" )
-odescr=( "$_vals_cache_odescr[@]" )
-gdescr="$_vals_cache_descr"
-sep="$_vals_cache_sep"
-esep="$_vals_cache_esep"
-
-if [[ -n "$sep$esep" ]]; then
-
-  # We have a separator character. We parse the PREFIX and SUFFIX to
-  # see if any of the values that must not appear more than once are
-  # already on the line.
-
-  if [[ -n "$esep" ]]; then
-    spat='?*'
-  else
-    spat="*${sep}*"
-  fi
-
-  while [[ "$PREFIX" = $~spat ]]; do
-
-    # Get one part, remove it from PREFIX and put it into IPREFIX.
-
-    if [[ -n "$esep" ]]; then
-      tmp="$PREFIX[1]"
-      IPREFIX="${IPREFIX}${tmp}"
-      PREFIX="${PREFIX[2,-1]}"
-    else
-      tmp="${PREFIX%%${sep}*}"
-      PREFIX="${PREFIX#*${sep}}"
-      IPREFIX="${IPREFIX}${tmp}${sep}"
-    fi
-
-    # Get the value `name'.
-
-    name="${tmp%%\=*}"
-
-    if [[ "$tmp" = *\=* ]]; then
-      _values[$name]="${tmp#*\=}"
-    else
-      _values[$name]=''
-    fi
-
-    # And remove the descriptions for the values this one makes
-    # superfluous.
-
-    if [[ -n "$xors[$name]" ]]; then
-      snames=( "${(@)snames:#(${(j:|:)~${=xors[$name]}})}" )
-      odescr=( "${(@)odescr:#(${(j:|:)~${=xors[$name]}}):*}" )
-      unset {names,onames,xors}\[$name\]
-    fi
-  done
-  if [[ "$SUFFIX" = $~spat ]]; then
-
-    # The same for the suffix.
-
-    if [[ -n "$esep" ]]; then
-      str=''
-    else
-      str="${SUFFIX%%${sep}*}"
-      SUFFIX="${SUFFIX#*${sep}}"
-    fi
+    if [[ "$PREFIX" = *\=* ]]; then
+      local name
 
-    while [[ -n "$SUFFIX" ]]; do
-      if [[ -n "$esep" ]]; then
-        tmp="$SUFFIX[-1]"
-        ISUFFIX="${SUFFIX[-1]}$ISUFFIX"
-	SUFFIX="$SUFFIX[1,-2]"
+      name="${PREFIX%%\=*}"
+      if compvalues -L "$name" descr action; then
+        IPREFIX="${IPREFIX}${name}="
+        PREFIX="${PREFIX#*\=}"
       else
-        tmp="${SUFFIX##*${sep}}"
-        if [[ "$SUFFIX" = *${sep}* ]]; then
-          SUFFIX="${SUFFIX%${sep}*}"
-        else
-          SUFFIX=''
-        fi
-	ISUFFIX="${sep}${tmp}${ISUFFIX}"
-      fi
+        local prefix suffix
 
-      name="${tmp%%\=*}"
+	prefix="${PREFIX#*\=}"
+	suffix="$SUFFIX"
+	PREFIX="$name"
+	SUFFIX=''
+	args=( "$args[@]" "$opts[@]" )
+	compadd -M 'r:|[_-]=* r:|=*' -D args - "${(@)args[@]%%:*}"
 
-      if [[ "$tmp" = *\=* ]]; then
-        _values[$name]="${tmp#*\=}"
-      else
-        _values[$name]=''
-      fi
+	[[ $#args -ne 1 ]] && return 1
 
-      if [[ -n "$xors[$name]" ]]; then
-        snames=( "${(@)snames:#(${(j:|:)~${=xors[$name]}})}" )
-        odescr=( "${(@)odescr:#(${(j:|:)~${=xors[$name]}}):*}" )
-        unset {names,onames,xors}\[$name\]
+        PREFIX="$prefix"
+	SUFFIX="$suffix"
+        IPREFIX="${IPREFIX}${args[1]%%:*}="
+	compvalues -L "${args[1]%%:*}" descr action
       fi
-    done
-    SUFFIX="$str"
-  fi
-fi
-
-descr=''
-str="$PREFIX$SUFFIX"
-
-if [[ "$str" = *\=* ]]; then
-
-  # The string from the line contains a `=', so we get the stuff before
-  # it and after it and see what we can do here...
-
-  name="${str%%\=*}"
-  arg="${str#*\=}"
-
-  if (( $snames[(I)${name}] )); then
-
-    # According to our information, the value doesn't get an argument,
-    # so give up.
-
-    _message "\`${name}' gets no value"
-    return 1
-  elif (( $+names[$name] )); then
-
-    # It has to get an argument, we skip over the name and complete
-    # the argument (below).
-
-    def="$names[$name]"
-    if ! compset -P '*\='; then
-      IPREFIX="${IPREFIX}${name}="
-      PREFIX="$arg"
-      SUFFIX=''
-    fi
-  elif (( $+onames[$name] )); then
-
-    # Gets an optional argument, same as previous case.
-
-    def="$onames[$name]"
-    if ! compset -P '*\='; then
-      IPREFIX="${IPREFIX}${name}="
-      PREFIX="$arg"
-      SUFFIX=''
-    fi
-  else
-    local pre="$PREFIX" suf="$SUFFIX"
-
-    # The part before the `=' isn't a known value name, so we see if
-    # it matches only one of the known names.
-
-    if [[ "$PREFIX" = *\=* ]]; then
-      PREFIX="${PREFIX%%\=*}"
-      pre="${pre#*\=}"
-      SUFFIX=''
     else
-      SUFFIX="${SUFFIX%%\=*}"
-      pre="${suf#*\=}"
-      suf=''
-    fi
-
-    tmp=( "${(@k)names}" "${(@k)onames}" )
-    compadd -M 'r:|[-_]=* r:|=*' -D tmp - "$tmp[@]"
-
-    if [[ $#tmp -eq 1 ]]; then
-
-      # It does, so we use that name and immediatly start completing
-      # the argument for it.
+      compvalues -d descr
+      if [[ ${#noargs}+${#args}+${#opts} -ne 1 ]] && compvalues -s sep; then
+        sep=( "-qQS$sep" )
+      else
+        sep=()
+      fi
 
-      IPREFIX="${IPREFIX}${tmp[1]}="
-      PREFIX="$pre"
-      SUFFIX="$suf"
+      _describe "$descr" \
+        noargs "$sep[@]" -M 'r:|[_-]=* r:|=*' -- \
+        args -S= -M 'r:|[_-]=* r:|=*' -- \
+        opts -qS= -M 'r:|[_-]=* r:|=*'
 
-      def="$names[$tmp[1]]"
-      [[ -z "$def" ]] && def="$onames[$tmp[1]]"
-    elif (( $#tmp )); then
-      _message "ambiguous option \`${PREFIX}${SUFFIX}'"
-      return 1
-    else
-      _message "unknown option \`${PREFIX}${SUFFIX}'"
-      return 1
+      return
     fi
   fi
-else
-
-  # No `=', just complete value names.
-
-  if [[ -n "$sep" && ${#snames}+${#names}+${#onames} -ne 1 ]]; then
-    opts=( "-qS$sep" )
-  else
-    opts=()
-  fi
-
-  tmp1=( "${(@M)odescr:#(${(j:|:)~snames}):*}" )
-  tmp2=( "${(@M)odescr:#(${(kj:|:)~names}):*}" )
-  tmp3=( "${(@M)odescr:#(${(kj:|:)~onames}):*}" )
-
-  _describe "$gdescr" \
-  tmp1 "$opts[@]" -M 'r:|[_-]=* r:|=*' -- \
-  tmp2 -S= "$opts[@]" -M 'r:|[_-]=* r:|=*' -- \
-  tmp3 -qS= "$opts[@]" -M 'r:|[_-]=* r:|=*'
-
-  return ret
-fi
-
-if [[ -z "$def" ]]; then
-  _message 'no value'
-  return 1
-else
-  local action
-
-  descr="${${${(M)def#*[^\\]:}[1,-2]}//\\\\:/:}"
-  action="${${def#*[^\\]:}//\\\\:/:}"
 
   _description expl "$descr"
 
   # We add the separator character as a autoremovable suffix unless
   # we have only one possible value left.
 
-  [[ -n "$sep" && ${#snames}+${#names}+${#onames} -ne 1 ]] &&
+  [[ ${#snames}+${#names}+${#onames} -ne 1 ]] && compvalues -s sep &&
       expl=( "-qS$sep" "$expl[@]" )
 
   if [[ "$action" = -\>* ]]; then
-    values=( "${(@kv)_values}" )
+    compvalues -v values
     state="${${action[3,-1]##[ 	]#}%%[ 	]#}"
     compstate[restore]=''
     return 1
   else
     typeset -A values
 
-    values=( "${(@kv)_values}" )
+    compvalues -v values
 
     if [[ "$action" = \ # ]]; then
 
@@ -341,7 +84,7 @@ else
 
       if [[ -n "$compconfig[describe_values]" &&
             "$compconfig[describe_values]" != *\!${cmd}* ]] &&
-         _display tmp "$ws[@]"; then
+         compdisplay tmp ' -- ' "$ws[@]"; then
 	compadd "$expl[@]" -M 'r:|[_-]=* r:|=*' -ld tmp - "${(@)ws%%:*}"
       else
 	compadd "$expl[@]" - "${(@)ws%%:*}"
@@ -370,6 +113,10 @@ else
       ${(e)action[1]} "$expl[@]" ${(e)~action[2,-1]}
     fi
   fi
-fi
 
-[[ nm -ne "$compstate[nmatches]" ]]
+  [[ nm -ne "$compstate[nmatches]" ]]
+  return
+
+else
+  return 1;
+fi