about summary refs log tree commit diff
path: root/Completion
diff options
context:
space:
mode:
authorPeter Stephenson <pws@users.sourceforge.net>2000-04-01 20:43:43 +0000
committerPeter Stephenson <pws@users.sourceforge.net>2000-04-01 20:43:43 +0000
commite025336f2f6d9f107ee1e03b9900f04af0544ba9 (patch)
tree37b0ce74587d42d4bcb024991526d2361fcdf04a /Completion
parent20c5fbe688f24010c578c48d4b4d228f0e1a56c3 (diff)
downloadzsh-e025336f2f6d9f107ee1e03b9900f04af0544ba9.tar.gz
zsh-e025336f2f6d9f107ee1e03b9900f04af0544ba9.tar.xz
zsh-e025336f2f6d9f107ee1e03b9900f04af0544ba9.zip
Updated from list as far as 10376
Diffstat (limited to 'Completion')
-rw-r--r--Completion/Base/_arguments571
-rw-r--r--Completion/Base/_default30
-rw-r--r--Completion/Base/_describe164
-rw-r--r--Completion/Base/_jobs80
-rw-r--r--Completion/Base/_subscript58
-rw-r--r--Completion/Base/_tilde55
-rw-r--r--Completion/Base/_values383
-rw-r--r--Completion/Builtins/_autoload11
-rw-r--r--Completion/Builtins/_cd48
-rw-r--r--Completion/Builtins/_compdef54
-rw-r--r--Completion/Builtins/_disable12
-rw-r--r--Completion/Builtins/_emulate6
-rw-r--r--Completion/Builtins/_enable12
-rw-r--r--Completion/Builtins/_fc30
-rw-r--r--Completion/Builtins/_nothing2
-rw-r--r--Completion/Builtins/_pids26
-rw-r--r--Completion/Builtins/_popd55
-rw-r--r--Completion/Builtins/_sched24
-rw-r--r--Completion/Builtins/_signals12
-rw-r--r--Completion/Builtins/_stat20
-rw-r--r--Completion/Builtins/_zcompile22
-rw-r--r--Completion/Builtins/_zftp100
-rw-r--r--Completion/Builtins/_zpty10
-rw-r--r--Completion/Builtins/_zstyle145
-rw-r--r--Completion/Commands/_complete_help73
-rw-r--r--Completion/Commands/_history_complete_word107
-rw-r--r--Completion/Commands/_next_tags86
-rw-r--r--Completion/Core/_all_labels44
-rw-r--r--Completion/Core/_alternative45
-rw-r--r--Completion/Core/_approximate192
-rw-r--r--Completion/Core/_call2
-rw-r--r--Completion/Core/_complete58
-rw-r--r--Completion/Core/_correct4
-rw-r--r--Completion/Core/_description54
-rw-r--r--Completion/Core/_expand152
-rw-r--r--Completion/Core/_files59
-rw-r--r--Completion/Core/_ignored3
-rw-r--r--Completion/Core/_list43
-rw-r--r--Completion/Core/_main_complete221
-rw-r--r--Completion/Core/_match44
-rw-r--r--Completion/Core/_menu4
-rw-r--r--Completion/Core/_next_label24
-rw-r--r--Completion/Core/_oldlist53
-rw-r--r--Completion/Core/_path_files661
-rw-r--r--Completion/Core/_prefix4
-rw-r--r--Completion/Core/_requested21
-rw-r--r--Completion/Core/_setup68
-rw-r--r--Completion/Core/_tags144
-rw-r--r--Completion/Core/_wanted22
-rw-r--r--Completion/Core/compdump62
-rw-r--r--Completion/Core/compinit427
-rw-r--r--Completion/Core/compinstall431
-rw-r--r--Completion/Linux/_rpm101
-rw-r--r--Completion/User/_gdb52
-rw-r--r--Completion/User/_getconf37
-rw-r--r--Completion/User/_groups19
-rw-r--r--Completion/User/_lp76
-rw-r--r--Completion/User/_make33
-rw-r--r--Completion/User/_mh67
-rw-r--r--Completion/User/_nedit9
-rw-r--r--Completion/User/_netscape70
-rw-r--r--Completion/User/_tiff37
-rw-r--r--Completion/User/_urls180
-rw-r--r--Completion/User/_users12
-rw-r--r--Completion/User/_users_on8
-rw-r--r--Completion/X/_x_colormapid5
-rw-r--r--Completion/X/_x_extension10
-rw-r--r--Completion/X/_x_font15
-rw-r--r--Completion/X/_x_keysym6
-rw-r--r--Completion/X/_x_window13
-rw-r--r--Completion/X/_xmodmap20
-rw-r--r--Completion/X/_xutils42
-rw-r--r--Completion/X/_xwit8
73 files changed, 3647 insertions, 2211 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
diff --git a/Completion/Base/_default b/Completion/Base/_default
index 8bcf14f6a..fd5869e2e 100644
--- a/Completion/Base/_default
+++ b/Completion/Base/_default
@@ -1,13 +1,23 @@
-#defcomp -default-
+#compdef -default-
 
-# We first try the `compctl's. This is without first (-T) and default (-D)
-# completion. If you want them add `-T' and/or `-D' to this command.
-# If there is a `compctl' for the command we are working on, we return
-# immediatly. If you want to use new style completion anyway, remove the
-# `|| return'. Also, you may want to use new style completion if the 
-# `compctl' didn't produce any matches. In that case remove the `|| return'
-# and at the line `[[ -nmatches 0 ]] || return' after `compcall'.
+local ctl
 
-compcall || return
+if { zstyle -s ":completion:${curcontext}:" use-compctl ctl ||
+     zmodload -e zsh/compctl } && [[ "$ctl" != (no|false|0|off) ]]; then
+  local opt
 
-_files
+  opt=()
+  [[ "$ctl" = *first* ]] && opt=(-T)
+  [[ "$ctl" = *default* ]] && opt=("$opt[@]" -D)
+  compcall "$opt[@]" || return 0
+fi
+
+_wanted files || return 1
+
+_files && return 0
+
+# magicequalsubst allows arguments like <any-old-stuff>=~/foo to do
+# file name expansion after the =.  In that case, it's natural to
+# allow completion to handle file names after any equals sign.
+
+[[ -o magicequalsubst ]] && compset -P 1 '*=' && _files
diff --git a/Completion/Base/_describe b/Completion/Base/_describe
index e01c77509..6e6f4f4a9 100644
--- a/Completion/Base/_describe
+++ b/Completion/Base/_describe
@@ -2,154 +2,52 @@
 
 # This can be used to add options or values with descriptions as matches.
 
-setopt localoptions extendedglob
+local _opt _expl _tmps _tmpd _tmpmd _tmpms _ret=1 _showd _nm _hide _args
+local _type=values _descr
 
-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
+# Get the option.
 
-cmd="$words[1]"
-
-# Get the options.
-
-while getopts 'oc:' opt; do
-  if [[ "$opt" = o ]]; then
-    isopt=yes
-  else
-    cmd="$OPTARG"
-  fi
-done
-shift OPTIND-1
+if [[ "$1" = -o ]]; then
+  _type=options
+  shift
+fi
 
 # Do the tests. `showd' is set if the descriptions should be shown.
 
-if [[ -n "$isopt" ]]; then
-
-  # We take the value to test the number of patches from a non-local
-  # parameter `nm' if that exists and contains only digits. It's a hack.
-
-  if [[ "$nm" = [0-9]## ]]; then
-    _nm="$nm"
-  else
-    _nm=0
-  fi
-  [[ -n "$compconfig[option_prefix]" &&
-     "$compconfig[option_prefix]" != *\!${cmd}* &&
-     "$PREFIX" != [-+]* &&
-     ( "$compconfig[option_prefix]" = *nodefault* ||
-       _nm -ne compstate[nmatches] ) ]] && return 1
+_wanted "$_type" || return 1
 
-  [[ -n "$compconfig[describe_options]" &&
-     "$compconfig[describe_options]" != *\!${cmd}* ]] && showd=yes
-else
-  [[ -n "$compconfig[describe_values]" &&
-     "$compconfig[describe_values]" != *\!${cmd}* ]] && showd=yes
-fi
+zstyle -T ":completion:${curcontext}:$_type" verbose && _showd=yes
 
-gdescr="$1"
+_descr="$1"
 shift
 
-# Now interpret the arguments.
+[[ "$_type" = options ]] &&
+    zstyle -t ":completion:${curcontext}:options" prefix-hidden && _hide=yes
 
-nsets=0
-adescr=()
-descrs=()
-matches=()
-while (( $# )); do
-  (( nsets++ ))
-  descr="$1"
-  [[ -n "$showd" ]] && adescr=( "$adescr[@]" "${(@PM)^descr:#*:?*},$nsets" )
-  if [[ "$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=()
+while _next_label "$_type" _expl "$_descr"; do
+
+  if [[ -n "$_showd" ]]; then
+    compdescribe -I ' -- ' "$@"
   else
-    shift tmp
+    compdescribe -i "$@"
   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.
+  while compdescribe -g _args _tmpd _tmpmd _tmps _tmpms; do
 
-  descrs[nsets]="$descr"
-  matches[nsets]="$match"
-  typeset -a _descr_opts_$nsets
-  eval "_descr_opts_${nsets}=( \"\$opt[@]\" )"
-done
-
-(( nsets )) || return 1
-
-# Build the display strings if needed.
-
-[[ -n "$showd" ]] && _display disps "$adescr[@]"
-_description expl "$gdescr"
+    # See if we should remove the option prefix characters.
 
-# 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]" )
+    if [[ -n "$_hide" ]]; then
+      if [[ "$PREFIX" = --* ]]; then
+        _tmpd=( "${(@)_tmpd#--}" )
+        _tmps=( "${(@)_tmps#--}" )
+      elif [[ "$PREFIX" = [-+]* ]]; then
+        _tmpd=( "${(@)_tmpd#[-+]}" )
+        _tmps=( "${(@)_tmps#[-+]}" )
       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
-
-  # See if we should remove the option prefix characters.
-
-  if [[ -n "$isopt" && "$compconfig[option_prefix]" = hide* ]]; then
-    if [[ "$PREFIX" = --* ]]; then
-      tmpd=( "${(@)tmpd#--}" )
-      tmps=( "${(@)tmps#--}" )
-    elif [[ "$PREFIX" = [-+]* ]]; then
-      tmpd=( "${(@)tmpd#[-+]}" )
-      tmps=( "${(@)tmps#[-+]}" )
     fi
-  fi
-  compadd "${(@P)name}" "$expl[@]" -ld tmpd - "$tmpmd[@]" && ret=0
-  compadd "${(@P)name}" "$expl[@]" -d tmps - "$tmpms[@]" && ret=0
-done
 
-return ret
+    compadd "$_args[@]" "$_expl[@]" -ld _tmpd - "$_tmpmd[@]" && _ret=0
+    compadd "$_args[@]" "$_expl[@]" -d _tmps  - "$_tmpms[@]" && _ret=0
+  done
+done
+return _ret
diff --git a/Completion/Base/_jobs b/Completion/Base/_jobs
index 869aeeb8a..45983ad16 100644
--- a/Completion/Base/_jobs
+++ b/Completion/Base/_jobs
@@ -1,27 +1,85 @@
 #autoload
 
-local expl disp jobs job jids
+local expl disp jobs job jids pfx='%' desc how expls
+
+_wanted jobs || return 1
+
+if [[ "$1" = -t ]]; then
+  zstyle -T ":completion:${curcontext}:jobs" prefix-needed &&
+      [[ "$PREFIX" != %* && compstate[nmatches] -ne 0 ]] && return 1
+  shift
+fi
+zstyle -t ":completion:${curcontext}:jobs" prefix-hidden && pfx=''
+zstyle -T ":completion:${curcontext}:jobs" verbose       && desc=yes
 
 if [[ "$1" = -r ]]; then
   jids=( "${(@k)jobstates[(R)running*]}" )
   shift
-  _description expl 'running job'
+  expls='running job'
 elif [[ "$1" = -s ]]; then
   jids=( "${(@k)jobstates[(R)running*]}" )
   shift
-  _description expl 'suspended job'
+  expls='suspended job'
 else
   [[ "$1" = - ]] && shift
   jids=( "${(@k)jobtexts}" )
-  _description expl job
+  expls=job
 fi
 
-disp=()
-jobs=()
-for job in "$jids[@]"; do
-  disp=( "$disp[@]" "${(l:3:: ::%:)job} -- ${jobtexts[$job]}" )
-  jobs=( "$jobs[@]" "$job" )
-done
+if [[ -n "$desc" ]]; then
+  disp=()
+  for job in "$jids[@]"; do
+    [[ -n "$desc" ]] &&
+        disp=( "$disp[@]" "${pfx}${(r:2:: :)job} -- ${(r:COLUMNS-8:: :)jobtexts[$job]}" )
+  done
+fi
+
+zstyle -s ":completion:${curcontext}:jobs" numbers how
+
+if [[ "$how" = (yes|true|on|1) ]]; then
+  jobs=( "$jids[@]" )
+else
+  local texts i text str tmp num max=0
 
-compadd "$@" "$expl[@]" -ld disp - "%$^jobs[@]"
+  # Find shortest unambiguous strings.
 
+  texts=( "$jobtexts[@]" )
+  jobs=()
+  for i in "$jids[@]"; do
+    text="$jobtexts[$i]"
+    str="${text%% *}"
+    if [[ "$text" = *\ * ]]; then
+      text="${text#* }"
+    else
+      text=""
+    fi
+    tmp=( "${(@M)texts:#${str}*}" )
+    num=1
+    while [[ -n "$text" && $#tmp -ge 2 ]]; do
+      str="${str} ${text%% *}"
+      if [[ "$text" = *\ * ]]; then
+        text="${text#* }"
+      else
+        text=""
+      fi
+      tmp=( "${(@M)texts:#${str}*}" )
+      (( num++ ))
+    done
+
+    [[ num -gt max ]] && max="$num"
+
+    jobs=( "$jobs[@]" "$str" )
+  done
+
+  if [[ "$how" = [0-9]## && max -gt how ]]; then
+    jobs=( "$jids[@]" )
+  else
+    [[ -z "$pfx" && -n "$desc" ]] && disp=( "${(@)disp#%}" )
+  fi
+fi
+
+if [[ -n "$desc" ]]; then
+  _all_labels jobs expl "$expls" compadd "$@" -ld disp - "%$^jobs[@]"
+else
+  _all_labels jobs expl "$expls" compadd "$@" - "%$^jobs[@]"
+fi
diff --git a/Completion/Base/_subscript b/Completion/Base/_subscript
index 2b827a117..60d45370b 100644
--- a/Completion/Base/_subscript
+++ b/Completion/Base/_subscript
@@ -1,4 +1,56 @@
-#defcomp -subscript-
+#compdef -subscript-
 
-_compalso -math- "$@"
-[[ ${(Pt)${COMMAND}} = assoc* ]] && complist -k "( ${(kP)${COMMAND}} )"
+local expl
+
+if [[ "$PREFIX" = :* ]]; then
+  _wanted characters expl 'character class' \
+      compadd -p: -S ':]' alnum alpha blank cntrl digit graph \
+                          lower print punct space upper xdigit
+elif [[ ${(Pt)${compstate[parameter]}} = assoc* ]]; then
+  local suf
+
+  [[ "$RBUFFER" != \]* ]] && suf=']'
+
+  _wanted association-keys expl 'association key' \
+      compadd -S "$suf" - "${(@kP)${compstate[parameter]}}"
+elif [[ ${(Pt)${compstate[parameter]}} = array* ]]; then
+  local list i j ret=1 disp
+
+  _tags indexes parameters
+
+  while _tags; do
+    if _requested indexes; then
+      ind=( {1..${#${(P)${compstate[parameter]}}}} )
+      if zstyle -T ":completion:${curcontext}:indexes" verbose; then
+        list=()
+        for i in "$ind[@]"; do
+          if [[ "$i" = ${PREFIX}*${SUFFIX} ]]; then
+              list=( "$list[@]" 
+	             "${i}:$(print -D ${(P)${compstate[parameter]}[$i]})" )
+	  else
+	      list=( "$list[@]" '' )
+	  fi
+        done
+        zformat -a list ' -- ' "$list[@]"
+	disp=( -d list)
+      else
+        disp=()
+      fi
+
+      if [[ "$RBUFFER" = \]* ]]; then
+        _all_labels -V indexes expl 'array index' \
+            compadd -S '' "$disp[@]" - "$ind[@]" && ret=0
+      else
+        _all_labels -V indexes expl 'array index' \
+            compadd -S ']' "$disp[@]" - "$ind[@]" && ret=0
+      fi
+    fi
+    _requested parameters && _parameters && ret=0
+
+    (( ret )) || return 0
+  done
+
+  return 1
+else
+  _compalso -math-
+fi
diff --git a/Completion/Base/_tilde b/Completion/Base/_tilde
index aef575e19..7ab058e01 100644
--- a/Completion/Base/_tilde
+++ b/Completion/Base/_tilde
@@ -1,10 +1,53 @@
-#defcomp -tilde-
+#compdef -tilde-
 
 # We use all named directories and user names here. If this is too slow
 # for you or if there are too many of them, you may want to use
-# `compgen -k friends -qS/' or something like that. To get all user names
-# if there are no matches in the `friends' array, add
-#   `(( compstate[nmatches] )) || compgen -nu -qS/'
-# below that.
+# `compadd -qS/ - "$friends[@]"' or something like that.
 
-compgen -nu -qS/
+local expl suf dirs list lines revlines i ret disp nm="$compstate[nmatches]"
+
+if [[ "$SUFFIX" = */* ]]; then
+  ISUFFIX="/${SUFFIX#*/}$ISUFFIX"
+  SUFFIX="${SUFFIX%%/*}"
+  suf=(-S '')
+else
+  suf=(-qS/)
+fi
+
+_tags users named-directories directory-stack
+
+while _tags; do
+  _requested users && _users "$suf[@]" "$@" && ret=0
+  _requested named-directories expl 'named directory' \
+      compadd "$suf[@]" "$@" - "${(@k)nameddirs}"
+
+  if _requested directory-stack &&
+     { ! zstyle -T ":completion:${curcontext}:directory-stack" prefix-needed ||
+       [[ "$PREFIX" = [-+]* || nm -eq compstate[nmatches] ]] }; then
+    if zstyle -T ":completion:${curcontext}:directory-stack" verbose; then
+      integer i
+
+      lines=("${PWD}" "${dirstack[@]}")
+
+      if [[ ( -prefix - && ! -o pushdminus ) ||
+	    ( -prefix + && -o pushdminus ) ]]; then
+        revlines=( $lines )
+        for (( i = 1; i <= $#lines; i++ )); do
+          lines[$i]="$((i-1)) -- ${revlines[-$i]}"
+        done
+      else
+        for (( i = 1; i <= $#lines; i++ )); do
+          lines[$i]="$((i-1)) -- ${lines[$i]}"
+        done
+      fi
+      list=( ${PREFIX[1]}${^lines%% *} )
+      disp=( -ld lines )
+    else
+      list=( ${PREFIX[1]}{0..${#dirstack}} )
+      disp=()
+    fi
+    _all_labels -V directory-stack expl 'directory stack' \
+        compadd "$suf[@]" "$disp[@]" -Q - "$list[@]" && ret=0
+  fi
+  (( ret )) || return 0
+done
diff --git a/Completion/Base/_values b/Completion/Base/_values
index 4be3e8203..62cf0e409 100644
--- a/Completion/Base/_values
+++ b/Completion/Base/_values
@@ -1,322 +1,103 @@
 #autoload
 
-setopt localoptions extendedglob
+local subopts opt usecc
 
-local name arg def descr xor str tmp ret=1 expl nm="$compstate[nmatches]"
-local snames odescr gdescr sep
-typeset -A names onames xors _values
+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
 
-# Probably fill our cache.
+if compvalues -i "$@"; then
 
-if [[ "$*" != "$_vals_cache_args" ]]; then
-  _vals_cache_args="$*"
+  local noargs args opts descr action expl sep subc
+  local oldcontext="$curcontext"
 
-  unset _vals_cache_{sep,descr,names,onames,snames,xors,odescr}
+  if ! compvalues -D descr action; then
 
-  typeset -gA _vals_cache_{names,onames,xors}
-  _vals_cache_snames=()
-  _vals_cache_odescr=()
+    _wanted values || return 1
 
-  # Get the separator, if any.
+    curcontext="${oldcontext%:*}:values"
 
-  if [[ "$1" = -s ]]; then
-    _vals_cache_sep="$2"
-    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
+    compvalues -V noargs args opts
 
-       # 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"
-
-if [[ -n "$sep" ]]; 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.
-
-  while [[ "$PREFIX" = *${sep}* ]]; do
-
-    # Get one part, remove it from PREFIX and put it into IPREFIX.
-
-    tmp="${PREFIX%%${sep}*}"
-    PREFIX="${PREFIX#*${sep}}"
-    IPREFIX="${IPREFIX}${tmp}${sep}"
-
-    # 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}\[${^=tmp}\]
-    fi
-  done
-  if [[ "$SUFFIX" =  *${sep}* ]]; then
-
-    # The same for the suffix.
+    if [[ "$PREFIX" = *\=* ]]; then
+      local name
 
-    str="${SUFFIX%%${sep}*}"
-    SUFFIX="${SUFFIX#*${sep}}"
-    while [[ -n "$SUFFIX" ]]; do
-      tmp="${PREFIX%%${sep}*}"
-      if [[ "$SUFFIX" = *${sep}* ]]; then
-        SUFFIX="${SUFFIX#*${sep}}"
+      name="${PREFIX%%\=*}"
+      if compvalues -L "$name" descr action; then
+        IPREFIX="${IPREFIX}${name}="
+        PREFIX="${PREFIX#*\=}"
       else
-        SUFFIX=''
+        local prefix suffix
+
+	prefix="${PREFIX#*\=}"
+	suffix="$SUFFIX"
+	PREFIX="$name"
+	SUFFIX=''
+	args=( "$args[@]" "$opts[@]" )
+	compadd -M 'r:|[_-]=* r:|=*' -D args - "${(@)args[@]%%:*}"
+
+	[[ $#args -ne 1 ]] && return 1
+
+        PREFIX="$prefix"
+	SUFFIX="$suffix"
+        IPREFIX="${IPREFIX}${args[1]%%:*}="
+	compvalues -L "${args[1]%%:*}" descr action subc
+	curcontext="${oldcontext%:*}:$subc"
       fi
-      PREFIX="${PREFIX#*${sep}}"
-      IPREFIX="${IPREFIX}${tmp}${sep}"
-
-      name="${tmp%%\=*}"
-
-      if [[ "$tmp" = *\=* ]]; then
-        _values[$name]="${tmp#*\=}"
+    else
+      compvalues -d descr
+      if [[ ${#noargs}+${#args}+${#opts} -ne 1 ]] && compvalues -s sep; then
+        sep=( "-qQS" "$sep" )
       else
-        _values[$name]=''
+        sep=()
       fi
 
-      if [[ -n "$xors[$name]" ]]; then
-        snames=( "${(@)snames:#(${(j:|:)~${=xors[$name]}})}" )
-        odescr=( "${(@)odescr:#(${(j:|:)~${=xors[$name]}}):*}" )
-        unset {names,onames,xors}\[${^=tmp}\]
-      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
+      _describe "$descr" \
+        noargs "$sep[@]" -M 'r:|[_-]=* r:|=*' -- \
+        args -S= -M 'r:|[_-]=* r:|=*' -- \
+        opts -qS= -M 'r:|[_-]=* r:|=*'
 
-    # Gets an optional argument, same as previous case.
+      curcontext="$oldcontext"
 
-    def="$onames[$name]"
-    if ! compset -P '*\='; then
-      IPREFIX="${IPREFIX}${name}="
-      PREFIX="$arg"
-      SUFFIX=''
+      return
     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.
-
-      IPREFIX="${IPREFIX}${tmp[1]}="
-      PREFIX="$pre"
-      SUFFIX="$suf"
-
-      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
-    fi
+    compvalues -C subc
+    curcontext="${oldcontext%:*}:$subc"
   fi
-else
-
-  # No `=', just complete value names.
-
-  _description expl "$gdescr"
 
-  [[ -n "$sep" && ${#snames}+${#names}+${#onames} -ne 1 ]] &&
-      expl=( "-qS$sep" "$expl[@]" )
-
-  tmp=''
-  if [[ -n "$compconfig[describe_values]" &&
-        "$compconfig[describe_values]" != *\!${words[1]}* ]]; then
-    if _display tmp odescr -M 'r:|[_-]=* r:|=*'; then
-      if (( $#snames )); then
-        compadd "$expl[@]" -y tmp -M 'r:|[_-]=* r:|=*' - \
-                "$snames[@]" && ret=0
-        compadd -n -S= -J "_$gdescr" -M 'r:|[_-]=* r:|=*' - \
-                "${(@k)names}" && ret=0
-        compadd -n -qS= -J "_$gdescr" -M 'r:|[_-]=* r:|=*' - \
-                "${(@k)onames}" && ret=0
-      elif (( $#names )); then
-        compadd -n -S= "$expl[@]" -y tmp -M 'r:|[_-]=* r:|=*' - \
-                "${(@k)names}" && ret=0
-        compadd -n -qS= -J "_$gdescr" -M 'r:|[_-]=* r:|=*' - \
-                "${(@k)onames}" && ret=0
-      else
-        compadd -n -qS= "$expl[@]" -y tmp -M 'r:|[_-]=* r:|=*' - \
-                "${(@k)onames}" && ret=0
-      fi
-    fi
-  fi
-  if [[ -z "$tmp" ]]; then
-    compadd "$expl[@]" -M 'r:|[_-]=* r:|=*' - "$snames[@]" && ret=0
-    compadd -S= "$expl[@]" -M 'r:|[_-]=* r:|=*' - "${(@k)names}" && ret=0
-    compadd -qS= "$expl[@]" -M 'r:|[_-]=* r:|=*' - "${(@k)onames}" && ret=0
+  if ! _tags arguments; then
+    curcontext="$oldcontext"
+    return 1
   fi
-  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"
+  _description arguments 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 val_args
     state="${${action[3,-1]##[ 	]#}%%[ 	]#}"
+    if [[ -n "$usecc" ]]; then
+      curcontext="${oldcontext%:*}:$subc"
+    else
+      context="$subc"
+    fi
     compstate[restore]=''
     return 1
   else
-    typeset -A values
+    typeset -A val_args
 
-    values=( "${(@kv)_values}" )
+    compvalues -v val_args
 
     if [[ "$action" = \ # ]]; then
 
@@ -332,36 +113,44 @@ else
 
       eval ws\=\( "${action[3,-3]}" \)
 
-      if _display tmp ws; then
-        compadd "$expl[@]" -y tmp - "${(@)ws%%:*}"
-      else
-        _message "$descr"
-        return 1
-      fi
+      _describe "$descr" ws -M 'r:|[_-]=* r:|=*' "$subopts[@]"
+
     elif [[ "$action" = \(*\) ]]; then
 
       # Anything inside `(...)' is added directly.
 
-      compadd "$expl[@]" - ${=action[2,-2]}
+      _all_labels arguments expl "$descr" \
+          compadd "$subopts[@]" - ${=action[2,-2]}
     elif [[ "$action" = \{*\} ]]; then
 
       # A string in braces is evaluated.
 
-      eval "$action[2,-2]"
-
+      while _next_label arguments expl "$descr"; do
+        eval "$action[2,-2]"
+      done
     elif [[ "$action" = \ * ]]; then
 
       # If the action starts with a space, we just call it.
 
-      ${(e)=~action}
+      eval "action=( $action )"
+      while _next_label arguments expl "$descr"; do
+        "$action[@]"
+      done
     else
 
       # Otherwise we call it with the description-arguments built above.
 
-      action=( $=action )
-      ${(e)action[1]} "$expl[@]" ${(e)~action[2,-1]}
+      eval "action=( $action )"
+      _all_labels arguments expl "$descr" \
+          "$action[1]" "$subopts[@]" "${(@)action[2,-1]}"
     fi
   fi
-fi
 
-[[ nm -ne "$compstate[nmatches]" ]]
+  curcontext="$oldcontext"
+
+  [[ nm -ne "$compstate[nmatches]" ]]
+else
+  curcontext="$oldcontext"
+
+  return 1;
+fi
diff --git a/Completion/Builtins/_autoload b/Completion/Builtins/_autoload
index 4f506baeb..238b79e95 100644
--- a/Completion/Builtins/_autoload
+++ b/Completion/Builtins/_autoload
@@ -1,3 +1,10 @@
-#defcomp autoload
+#compdef autoload
 
-complist -s '${^fpath}/*(N:t)'
+local expl
+
+if (( $words[(I)[-+]*w*] )); then
+  _description files expl 'zwc file'
+  _files "$expl[@]" -g '*.zwc'
+else
+  _wanted functions expl 'shell function' compadd - ${^fpath}/*(N:t)
+fi
diff --git a/Completion/Builtins/_cd b/Completion/Builtins/_cd
index f3ce67ec7..803bcbda5 100644
--- a/Completion/Builtins/_cd
+++ b/Completion/Builtins/_cd
@@ -1,3 +1,47 @@
-#defcomp cd
+#compdef cd chdir pushd
 
-_files -W cdpath -g '*(-/)'
+# Handling of cd.
+#  - Normally just completes directories.  Uses cdpath if that's set
+#    and the string doesn't begin with ~, /, ./ or ../.
+#  - In the second argument to cd for the form `cd old new', completes
+#    possible `new' strings by examining `old' and $PWD.
+#  - After - or +, completes numbers, but the listing
+#    gives you the list of directories to complete.  This turns on
+#    menu-completion and lists the possibilities automatically, otherwise
+#    it's not a lot of use.  If you don't type the + or - it will
+#    complete directories as normal.
+
+setopt localoptions nonomatch
+
+local expl
+
+if [[ CURRENT -eq 3 ]]; then
+  # cd old new: look for old in $PWD and see what can replace it
+  local rep
+  # Get possible completions using word in position 2
+  rep=(${~PWD/$words[2]/*}~$PWD(-/N))
+  # Now remove all the common parts of $PWD and the completions from this
+  rep=(${${rep#${PWD%%$words[2]*}}%${PWD#*$words[2]}})
+  (( $#rep )) && _wanted -C replacement strings expl replacement compadd $rep
+elif _popd || [[ $PREFIX != (\~|/|./|../)* && $#cdpath -ne 0 ]]; then
+  local tdir tdir2
+
+  # With cdablevars, we can convert foo/bar/... to ~foo/bar/... if
+  # there is no directory foo.  In that case we could also complete
+  # variable names, but it hardly seems worth it.
+  # Note we need a tilde because cdablevars also allows user home
+  # directories, hence we also need nonomatch to suppress error messages.
+  if [[ -o cdablevars && -n "$PREFIX" && ! -d ${tdir::=${PREFIX%%/*}} &&
+        -d ${~tdir2::="~$tdir"} ]]; then
+      PREFIX="~$PREFIX"
+      _wanted directories expl directory _path_files -/
+  else
+    local tmpcdpath
+    tmpcdpath=(${${(@)cdpath:#.}:#$PWD})
+    _alternative \
+        'local-directories:local directories:_path_files -/' \
+	"path-directories:directories in cdpath:_path_files -W tmpcdpath -/"
+  fi
+else
+  _wanted directories expl directory _path_files -/
+fi
diff --git a/Completion/Builtins/_compdef b/Completion/Builtins/_compdef
index 1df5758b3..d47a560c9 100644
--- a/Completion/Builtins/_compdef
+++ b/Completion/Builtins/_compdef
@@ -1,22 +1,40 @@
 #compdef compdef
 
-local func base=2
+local state line expl list disp
 
-while [[ $words[base] = -* ]]; do
-  case $words[base] in
-    -d) delete=yes ;;
-    -p) type=pattern ;;
-    -k) type=key ;;
-  esac  
-  (( base++ ))
-done
+_arguments -C -s \
+  '(-d)-a[make function autoloadable]' \
+  '(-d -p -P)-n[leave existing definitions intact]' \
+  '(-a -n -p -P -k -K)-d[delete]:*:completed command:->ccom' \
+  '(-n -d -P -k -K)-p[completion for command matching pattern]:completion function:->cfun:pattern' \
+  '(-n -d -p -k -K)-P[as -p for commands without own completion]:completion function:->cfun:pattern' \
+  '(-d -p -P -K)-k[define widget and key binding]:completion function:->cfun:widget name::style:->style:*:key' \
+  '(-d -p -P -k)-K[define multiple widgets based on function]:completion function:->cfun:widget name::style:->style:*:key' \
+  '1:completion function:->cfun' \
+  '2:commands:_command_names'
+  
 
-if [ "$delete" ]; then
-  compadd ${(k)_comps}
-else
-  if [[ CURRENT -eq base  ]]; then
-    for func in ${^~fpath:/.}/_(|*[^~])(N:t); compadd -P_ - ${func#_}
-  else
-    compgen -c
-  fi
-fi
+case $state in
+  ccom)
+    _wanted commands expl 'completed command' compadd - ${(k)_comps}
+  ;;
+  cfun)
+    if _wanted functions; then
+      list=( ${^fpath:/.}/_(|*[^~])(N:t) )
+      if zstyle -T ":completion:${curcontext}:functions" prefix-hidden; then
+        disp=( ${list[@]#_} )
+        _all_labels functions expl 'completion function' \
+            compadd -d disp - "$list[@]"
+      else
+        _all_labels functions expl 'completion function' compadd - "$list[@]"
+      fi
+    fi
+  ;;
+  style)
+    _wanted widgetstyle expl 'widget style' \
+        compadd -M 'r:|-=* r:|=*' \
+            complete-word delete-char-or-list expand-or-complete \
+            expand-or-complete-prefix list-choices menu-complete \
+            menu-expand-or-complete reverse-menu-complete
+  ;;
+esac
diff --git a/Completion/Builtins/_disable b/Completion/Builtins/_disable
index 063b65a7d..b3c2632ed 100644
--- a/Completion/Builtins/_disable
+++ b/Completion/Builtins/_disable
@@ -1,6 +1,8 @@
-#defcomp disable
+#compdef disable
 
-[[ -mcurrent -1 -*a* ]] && complist -ea
-[[ -mcurrent -1 -*f* ]] && complist -eF
-[[ -mcurrent -1 -*r* ]] && complist -ew
-[[ ! -mcurrent -1 -* ]] && complist -eB
+_arguments -C -s \
+  "(-f -r)-a[act on aliases]:*:aliases:(${(k)aliases} ${(k)galiases})" \
+  "(-a -r)-f[act on functions]:*:functions:(${(k)functions})" \
+  "(-a -f)-r[act on reserved words]:*:reserved-words:(${(k)reswords})" \
+  '-m[treat arguments as patterns]' \
+  "*:builtin command:(${(k)builtins})"
diff --git a/Completion/Builtins/_emulate b/Completion/Builtins/_emulate
new file mode 100644
index 000000000..82096a77e
--- /dev/null
+++ b/Completion/Builtins/_emulate
@@ -0,0 +1,6 @@
+#compdef emulate
+
+_arguments -C -s \
+  '-L[set local_options and local_traps as well]' \
+  '-R[reset all options instead of only those needed for script portability]' \
+  '1::shell to emulate:(zsh sh ksh csh)'
diff --git a/Completion/Builtins/_enable b/Completion/Builtins/_enable
index 22ff53ee7..991286276 100644
--- a/Completion/Builtins/_enable
+++ b/Completion/Builtins/_enable
@@ -1,6 +1,8 @@
-#defcomp enable
+#compdef enable
 
-[[ -mcurrent -1 -*a* ]] && complist -da
-[[ -mcurrent -1 -*f* ]] && complist -dF
-[[ -mcurrent -1 -*r* ]] && complist -dw
-[[ ! -mcurrent -1 -* ]] && complist -dB
+_arguments -C -s \
+  "(-f -r)-a[act on aliases]:*:aliases:(${(k)dis_aliases})" \
+  "(-a -r)-f[act on functions]:*:functions:(${(k)dis_functions})" \
+  "(-a -f)-r[act on reserved words]:*:reserved-words:(${(k)dis_reswords})" \
+  '-m[treat arguments as patterns]' \
+  "*:builtin command:(${(@k)dis_builtins})"
diff --git a/Completion/Builtins/_fc b/Completion/Builtins/_fc
index f0d2c03fd..e97492604 100644
--- a/Completion/Builtins/_fc
+++ b/Completion/Builtins/_fc
@@ -1,7 +1,27 @@
-#defcomp fc
+#compdef fc history
 
-if [[ -mcurrent -1 -*e ]]; then
-  complist -c
-elif [[ -mcurrent -1 -[ARWI]## ]]; then
-  _files
+local fc_common
+
+fc_common=( \
+  '(-A -R -W -I)-m[treat first argument as a pattern]' \
+  '(-A -R -W -I)-r[reverse order of the commands]' \
+  '(-A -R -W -I -e)-n[suppress line numbers]' \
+  '(-A -R -W -I -e -f -E -i)-d[print time-stamps]' \
+  '(-A -R -W -I -e -d -E -i)-f[mm/dd/yyyy format time-stamps]' \
+  '(-A -R -W -I -e -d -f -i)-E[dd.mm.yyyy format time-stamps]' \
+  '(-A -R -W -I -e -d -f -E)-i[yyyy-mm-dd format time-stamps]' \
+  '(-A -R -W -I -e)-D[print elapsed times]' \
+  '(-A -R -W -I)*::commands:_command_names -e' )
+
+if [[ $words[1] = *history ]]; then
+  _arguments -C -s "$fc_common[@]"
+else
+  _arguments -C -s \
+    '(-A -R -W -I -e)-l[list resulting commands on stdout]' \
+    '(-A -R -W -I -l -n -d -f -E -i -D)-e[specify editor to invoke]:editor to invoke:_command_names -e' \
+    '(-l -m -e -r -n -d -f -E -i -D -A -W *)-R[read history from file]:history file:_files' \
+    '(-l -m -e -r -n -d -f -E -i -D -R -W *)-A[append history to file]:history file:_files' \
+    '(-l -m -e -r -n -d -f -E -i -D -R -A *)-W[write history to file]:history file:_files' \
+    '(-l -m -e -r -n -d -f -E -i -D -A -W *)-I[read/write new events only]:history file:_files' \
+    "$fc_common[@]"
 fi
diff --git a/Completion/Builtins/_nothing b/Completion/Builtins/_nothing
index 35a2558cc..38f6bee77 100644
--- a/Completion/Builtins/_nothing
+++ b/Completion/Builtins/_nothing
@@ -1,3 +1,3 @@
-#compdef true false
+#compdef true false log times whoami
 
 _message 'no argument or option'
diff --git a/Completion/Builtins/_pids b/Completion/Builtins/_pids
index 0ffda900b..7dec90e7d 100644
--- a/Completion/Builtins/_pids
+++ b/Completion/Builtins/_pids
@@ -3,16 +3,32 @@
 # If given the `-m <pattern>' option, this tries to complete only pids
 # of processes whose command line match the `<pattern>'.
 
-local list expl match
+local out list expl match desc listargs args
+
+_wanted processes || return 1
 
 if [[ "$1" = -m ]]; then
   match="${2}*"
   shift 2
 fi
 
-_description expl 'process ID'
+zstyle -s ":completion:${curcontext}:pids" command args
+
+out="$(_call pids ps 2>/dev/null)"
 
-list=("${(@Mr:COLUMNS-1:)${(f@)$(ps ${=compconfig[ps_listargs]:-$=compconfig[ps_args]} 2>/dev/null)}[2,-1]:#[ 	]#${PREFIX}[0-9]#${SUFFIX}[ 	]*${~match}}")
+if zstyle -T ":completion:${curcontext}:processes" verbose; then
+  zstyle -s ":completion:${curcontext}:pids-list" command listargs
+  (( $#listargs )) || listargs=( "$args[@]" )
+  if [[ "$listargs" = "$args" ]]; then
+    list=("${(@Mr:COLUMNS-1:)${(f@)out}[2,-1]:#[ 	]#${PREFIX}[0-9]#${SUFFIX}[ 	]*${~match}}")
+  else
+    list=("${(@Mr:COLUMNS-1:)${(f@)$(_call pids-list ps 2>/dev/null)}[2,-1]:#[ 	]#${PREFIX}[0-9]#${SUFFIX}[ 	]*${~match}}")
+  fi
+  desc=(-ld list)
+else
+  desc=()
+fi
 
-compadd "$expl[@]" "$@" -ld list - \
-  ${${${(M)${(f)"$(ps $=compconfig[ps_args] 2>/dev/null)"}[2,-1]:#*${~match}}## #}%% *}
+_all_labels processes expl 'process ID' \
+    compadd "$@" "$desc[@]" - \
+        ${${${(M)${(f)"${out}"}[2,-1]:#[ 	]#${PREFIX}[0-9]#${SUFFIX}[ 	]#*${~match}}## #}%% *}
diff --git a/Completion/Builtins/_popd b/Completion/Builtins/_popd
index 9054befb7..2a3413253 100644
--- a/Completion/Builtins/_popd
+++ b/Completion/Builtins/_popd
@@ -5,36 +5,39 @@
 # way round if pushdminus is set). Note that this function is also called
 # from _cd for cd and pushd.
 
-emulate -L zsh
 setopt extendedglob nonomatch
 
-[[ $PREFIX = [-+]* ]] || return 1
+local expl list lines revlines disp
 
-local expl list lines revlines ret=1 i
+! zstyle -T ":completion:${curcontext}:directory-stack" prefix-needed ||
+    [[ $PREFIX = [-+]* ]] || return 1
 
-IPREFIX=$PREFIX[1]
-PREFIX=$PREFIX[2,-1]
+_wanted directory-stack || return 1
 
-# get the list of directories with their canonical number
-# and turn the lines into an array, removing the current directory
-lines=( ${${(f)"$(dirs -v)"}##0*} )
-if [[ ( $IPREFIX = - && ! -o pushdminus ) ||
-      ( $IPREFIX = + && -o pushdminus ) ]]; then
-  integer i
-  revlines=( $lines )
-  for (( i = 1; i <= $#lines; i++ )); do
-    lines[$i]="$((i-1)) -- ${revlines[-$i]##[0-9]#[	 ]#}"
-  done
+if zstyle -T ":completion:${curcontext}:directory-stack" verbose; then
+  # get the list of directories with their canonical number
+  # and turn the lines into an array, removing the current directory
+  lines=("${dirstack[@]}")
+
+  if [[ ( $PREFIX[1] = - && ! -o pushdminus ) ||
+        ( $PREFIX[1] = + && -o pushdminus ) ]]; then
+    integer i
+    revlines=( $lines )
+    for (( i = 1; i <= $#lines; i++ )); do
+      lines[$i]="$((i-1)) -- ${revlines[-$i]##[0-9]#[	 ]#}"
+    done
+  else
+    for (( i = 1; i <= $#lines; i++ )); do
+      lines[$i]="$i -- ${lines[$i]##[0-9]#[	 ]#}"
+    done
+  fi
+  # get the array of numbers only
+  list=( ${PREFIX[1]}${^lines%% *} )
+  disp=( -ld lines )
 else
-  for (( i = 1; i <= $#lines; i++ )); do
-    lines[$i]="$i -- ${lines[$i]##[0-9]#[	 ]#}"
-  done
+  list=( ${PREFIX[1]}{0..${#dirstack}} )
+  disp=()
 fi
-# get the array of numbers only
-list=(${lines%% *})
-_description expl 'directory stack index'
-compadd "$expl[@]" -ld lines -V dirs -Q - "$list[@]" && ret=0
-[[ -z $compstate[list] ]] && compstate[list]=list && ret=0
-[[ -n $compstate[insert] ]] && compstate[insert]=menu && ret=0
-
-return ret
+
+_all_labels -V directory-stack expl 'directory stack' \
+    compadd "$@" "$disp[@]" -Q - "$list[@]"
diff --git a/Completion/Builtins/_sched b/Completion/Builtins/_sched
index 1e8ae3445..98ecb3642 100644
--- a/Completion/Builtins/_sched
+++ b/Completion/Builtins/_sched
@@ -1,3 +1,23 @@
-#defcomp sched
+#compdef sched
 
-[[ -position 2 -1 ]] && _normal "$@"
+local expl lines disp
+
+if [[ CURRENT -eq 2 ]]; then
+  if compset -P -; then
+    _wanted -C - jobs || return 1
+
+    lines=(${(f)"$(sched)"})
+    if zstyle -T ":completion:${curcontext}:jobs" verbose; then
+      disp=( -ld lines )
+    else
+      disp=()
+    fi
+    [[ -z $lines ]] || _all_labels jobs expl 'scheduled jobs' \
+                           compadd "$disp[@]" - {1..$#lines}
+    return
+  else
+    _message 'time specification'
+    return 1
+  fi
+fi
+compset -n 3 && _normal
diff --git a/Completion/Builtins/_signals b/Completion/Builtins/_signals
index c79350044..aa95a8499 100644
--- a/Completion/Builtins/_signals
+++ b/Completion/Builtins/_signals
@@ -20,17 +20,19 @@ done
 
 [[ "$1" = -(|-) ]] && shift
 
-if _wanted signals expl signal &&
-       { [[ -z "$minus" ]] || ! _style signals prefix-needed ||
+if _wanted signals &&
+       { [[ -z "$minus" ]] ||
+         ! zstyle -T ":completion:${curcontext}:signals" prefix-needed ||
          [[ "$PREFIX" = -* ]] } ; then
   local disp tmp
 
-  if _style signals prefix-hidden; then
+  if zstyle -t ":completion:${curcontext}:signals" prefix-hidden; then
     tmp=( "${(@)signals[1,last]}" )
     disp=(-d tmp)
   else
     disp=()
   fi
-  compadd "$@" "$expl[@]" "$disp[@]" -M 'm:{a-z}=${A-Z}' - \
-          "${minus}${(@)^signals[1,last]}"
+  _all_labels signals expl signal \
+      compadd "$@" "$disp[@]" -M 'm:{a-z}={A-Z}' - \
+              "${minus}${(@)^signals[1,last]}"
 fi
diff --git a/Completion/Builtins/_stat b/Completion/Builtins/_stat
index 3cdbb2618..5ba06388b 100644
--- a/Completion/Builtins/_stat
+++ b/Completion/Builtins/_stat
@@ -1,10 +1,20 @@
 #compdef stat
 
+local expl ret=1
+
 if [[ "$words[CURRENT-1]" = -[AH] ]]; then
-  compgen -A
+  _arrays
 else
-  [[ "$PREFIX[1]" = + ]] &&
-      compadd - +device +inode +mode +nlink +uid +gid +rdev +size \
-                +atime +mtime +ctime +blksize +block +link
-  _files
+  _tags files options || return 1
+
+  while _tags; do
+    _requested files && _files && ret=0
+    _requested options &&
+        { ! zstyle -T ":completion:${curcontext}:options" prefix-needed ||
+          [[ "$PREFIX[1]" = + || ret -eq 1 ]] } &&
+        _all_labels options expl 'inode element' \
+            compadd - +device +inode +mode +nlink +uid +gid +rdev \
+                      +size +atime +mtime +ctime +blksize +block +link
+    (( ret )) || return 0
+  done
 fi
diff --git a/Completion/Builtins/_zcompile b/Completion/Builtins/_zcompile
new file mode 100644
index 000000000..5ec6f96ce
--- /dev/null
+++ b/Completion/Builtins/_zcompile
@@ -0,0 +1,22 @@
+#compdef zcompile
+
+local context state line expl
+typeset -A opt_args
+
+_arguments -s \
+    '(-c -m -a)-U[don'\''t expand aliases]' \
+    '(-M)-R[mark as read]' \
+    '(-R)-M[mark as mapped]' \
+    '(-c -z -m -a)-k[ksh-style autoloading]' \
+    '(-c -k -m -a)-z[zsh-style autoloading]' \
+    '(-U -z -k)-c[currently defined functions]' \
+    '(-U -z -k)-m[use names as patterns]' \
+    '(-U -z -k)-a[write autoload functions]' \
+    ':zwc file:_files' \
+    '*:function:->function' && return 0
+
+if (( $+opt_args[-c] )); then
+  _wanted functions expl 'function to write' compadd - ${(k)functions}
+else
+  _wanted file expl 'zsh source file' _files
+fi
diff --git a/Completion/Builtins/_zftp b/Completion/Builtins/_zftp
index 9be9c94db..0d6530dfc 100644
--- a/Completion/Builtins/_zftp
+++ b/Completion/Builtins/_zftp
@@ -1,50 +1,92 @@
-#defpatcomp zf*
-
-# Don't try any more completion after this.
-_compskip=1
+#compdef -p zf*
 
 # Completion for zftp builtin and zf* functions.  The functions
-# zfcd_match and zfget_match (used for old-style completion)
+# zfcd_match and zfget_match (also used for old-style completion)
 # need to be installed for remote file and directory completion to work.
 
-local subcom
+# emulate -L zsh
+
+# Don't try any more completion after this.
+_compskip=all
+
+local subcom expl curcontext="${curcontext}"
 
-if [[ $COMMAND = zftp ]]; then
-  if [[ $CURRENT -eq 1 ]]; then
-    compadd -m open params user login type ascii binary mode put \
-      putat get getat append appendat ls dir local remote mkdir rmdir
+if [[ $words[1] = zftp ]]; then
+  if [[ $CURRENT -eq 2 ]]; then
+    _wanted commands expl sub-command \
+        compadd open params user login type ascii binary mode put \
+          putat get getat append appendat ls dir local remote mkdir rmdir \
+          session rmsession
     return
   fi
-  subcom=$1
+  subcom=$words[2]
+  curcontext="${curcontext/:zftp:/:zftp-${words[2]}:}"
 else
-  subcom=$COMMAND
+  subcom=$words[1]
 fi
 
 case $subcom in
   *(cd|ls|dir))
-   # complete remote directories; we could be smarter about hiding prefixes
-   zfcd_match $PREFIX $SUFFIX
-   (( $#reply )) && compadd -m -S/ -q $reply
-   ;;
+    # complete remote directories
+    _wanted directories && zfcd_match $PREFIX $SUFFIX
+    ;;
 
   *(get(|at)|gcp|delete|remote))
-   # complete remote files
-   zfget_match $PREFIX $SUFFIX
-   (( $#reply )) && compadd -F fignore -m $reply
-   ;;
+    # complete remote files
+    _wanted files && zfget_match $PREFIX $SUFFIX
+    ;;
 
   *(put(|at)|pcp))
-   # complete local files
-   _files
-   ;;
+    # complete local files
+    _wanted files && _files
+    ;;
 
   *(open|anon|params))
-  # complete hosts:  should do cleverer stuff with user names
-  complist -k hosts
-  ;;
+    # complete hosts:  should do cleverer stuff with user names
+    _wanted hosts && _hosts
+    ;;
+
+  *(goto|mark))
+    # complete bookmarks.  First decide if ncftp mode is go.
+    _wanted bookmarks || return 1
+    if [[ $words[2] = -*n* ]]; then
+      if [[ -f ~/.ncftp/bookmarks ]]; then
+        _all_labels bookmarks expl bookmark \
+            compadd - $(awk -F, 'NR > 2 { print $1 }' ~/.ncftp/bookmarks)
+      fi
+    else
+      if [[ -f ${ZFTP_BMFILE:=${ZDOTDIR:-$HOME}/.zfbkmarks} ]]; then
+        _all_labels bookmarks expl bookmark \
+            compadd - $(awk '{print $1}' $ZFTP_BMFILE)
+      fi
+    fi
+    ;;
+
+  *session)
+    # complete sessions, excluding the current one.
+    _wanted sessions expl 'another FTP session' \
+        compadd - ${$(zftp session):#$ZFTP_SESSION}
+    ;;
+
+  *transfer)
+    # complete arguments like sess1:file1 sess2:file2
+    if [[ $PREFIX = *:* ]]; then
+      # complete file in the given session
+      _wanted files || return 1
+      local sess=${PREFIX%%:*} oldsess=$ZFTP_SESSION
+      compset -p $(( $#sess + 1 ))
+      [[ -n $sess ]] && zftp session $sess
+      zfget_match $PREFIX $SUFFIX
+      [[ -n $sess && -n $oldsess ]] && zftp session $oldsess
+    else
+      # note here we can complete the current session
+      _wanted sessions expl 'FTP session' compadd -S : - $(zftp session)
+    fi
+    ;;
 
   *)
-  # dunno... try ordinary completion after all.
-  unset _compskip   
-  ;;
+    # dunno... try ordinary completion after all.
+    _compskip=''
+    return 1
+    ;;
 esac
diff --git a/Completion/Builtins/_zpty b/Completion/Builtins/_zpty
index b197b4128..d8c77ff2e 100644
--- a/Completion/Builtins/_zpty
+++ b/Completion/Builtins/_zpty
@@ -7,17 +7,17 @@ _arguments -C -s \
   '(-d -w -r -L)-b[io to pseudo-terminal blocking]' \
   '(-e -b -w -r -L)-d[delete command]:*:name:->name' \
   '(-e -b -d -r -L)-w[send string to command]:name:->name:*:strings to write' \
-  '(-e -b -d -w -L)-r[read string from command]:name:->name:param:_parameters:*:nothing:_nothing' \
+  '(-e -b -d -w -L *)-r[read string from command]:name:->name:param:_parameters' \
   '(-e -b -d -w -r)-L[list defined commands as calls]' \
-  '*::args:_normal'
+  '(-r)*::args:_normal'
 
-if [[ $state = name ]] && _wanted zptynames expl 'zpty command names'; then
+if [[ $state = name ]] && _wanted names; then
   list=( ${${(f)"$(zpty)"}#*\) } )
   names=( ${list%%:*} )
   if zstyle -T ":completion:${curcontext}" verbose; then
     zformat -a list ' --' ${${(f)"$(zpty)"}#*\) }
-    compadd "$expl[@]" -d list - "$names[@]"
+    _all_labels names expl 'zpty command names' compadd -d list - "$names[@]"
   else
-    compadd "$expl[@]" - "$names[@]"
+    _all_labels names expl 'zpty command names' compadd - "$names[@]"
   fi
 fi
diff --git a/Completion/Builtins/_zstyle b/Completion/Builtins/_zstyle
index f072f79ae..cd470598a 100644
--- a/Completion/Builtins/_zstyle
+++ b/Completion/Builtins/_zstyle
@@ -1,7 +1,8 @@
 #compdef zstyle
 
-local curcontext="$curcontext" state ostate line expl ctop
-local nm=$compstat[nmatches]
+local curcontext="$curcontext" state context ostate line expl ctop
+local nm=$compstate[nmatches] mesg
+typeset -A opt_args
 
 typeset -A styles
 # Assoc array of styles; the values give the possible top-level
@@ -9,15 +10,18 @@ typeset -A styles
 # followed by a colon, followed by a state to enter, empty if none.
 styles=(
   accept-exact		 c:bool
+  add-space		 c:bool
   arguments		 c:
   auto-description	 c:
-  cache-path		 'c:_path_files -/'
+  break                  c:
   completer		 c:completer
   completions		 c:
   condition		 c:
-  cursor		 c:bool
+  cursor		 c:cursor
   disable-stat		 c:bool
+  domains                c:
   expand		 c:
+  file-patterns		 c:filepat
   format		 c:
   glob			 c:
   group-name		 c:
@@ -26,8 +30,9 @@ styles=(
   hidden		 c:bool
   hosts			 c:_hosts
   hosts-ports		 c:host-port
-  hosts-ports-users	 c:host-port-user
-  ignored-suffixes	 c:
+  users-hosts-ports	 c:user-host-port
+  ignore-parents         c:ignorepar
+  ignored-patterns	 c:
   insert-unambiguous	 c:bool
   last-prompt		 c:bool
   list			 c:listwhen
@@ -36,21 +41,26 @@ styles=(
   list-packed		 c:bool
   list-rows-first	 c:bool
   local			 c:
+  matcher-list		 c:
   max-errors		 c:
   menu			 c:boolauto
   numbers		 c:bool
   original		 c:bool
-  path			 'c:_path_files -/'
+  packageset		 c:packageset
+  path			 'c:_wanted directories expl directory _path_files -/'
   ports			 c:_ports
   prefix-hidden		 c:bool
   prefix-needed		 c:bool
   prompt		 c:
   remove-all-dups	 c:bool
+  single-ignored         c:single-ignored
   sort			 c:bool
-  tag-order		 c:tag
   special-dirs		 c:sdirs
+  squeeze-slashes	 c:bool
   stop			 c:stop
+  subst-glob-only        c:
   substitute		 c:
+  tag-order		 c:tag
   users			 c:_users
   users-hosts		 c:user-host
   verbose		 c:bool
@@ -83,9 +93,20 @@ while [[ -n $state ]]; do
 
   case "$ostate" in
     contexts)
-      if [[ $PREFIX != :*: ]]; then
-	_wanted contexts expl context &&
-	compadd -P : -S : "$expl[@]" completion zftp
+      if _wanted contexts; then
+        if [[ $PREFIX != :*: ]]; then
+	  _all_labels contexts expl context compadd -P : -S : completion zftp
+        elif [[ $PREFIX = :completion:* ]]; then
+          mesg=''
+          case "$PREFIX" in
+          :completion:[^:]#) mesg=function ;;
+          :completion:[^:]#:[^:]#) mesg=completer ;;
+          :completion:[^:]#:[^:]#:[^:]#) mesg='command or context' ;;
+          :completion:[^:]#:[^:]#:[^:]#:[^:]#) mesg=argument ;;
+          :completion:[^:]#:[^:]#:[^:]#:[^:]#:[^:]#) mesg=tag ;;
+	  esac
+	  [[ -n "$mesg" ]] && _message "$mesg"
+        fi
       fi
       ;;
 
@@ -96,8 +117,8 @@ while [[ -n $state ]]; do
       else
         ctop=cz
       fi
-      _wanted styles expl style &&
-         compadd "$expl[@]" - ${(k)styles[(R)[^:]#[$ctop][^:]#:*]}
+      _wanted styles expl style \
+         compadd -M 'r:|-=* r:|=*' - ${(k)styles[(R)[^:]#[$ctop][^:]#:*]}
       ;;
       
     style-arg)
@@ -105,66 +126,116 @@ while [[ -n $state ]]; do
       ;;
 
     bool) 
-      _wanted values expl boolean &&
-	compadd "$expl[@]" true false
+      _wanted values expl boolean compadd true false
       ;;
 
     boolauto) 
-      _wanted values expl boolean &&
-	compadd "$expl[@]" true false auto select
+      _wanted values expl boolean compadd true false auto select
+      ;;
+
+    cursor)
+      if [[ "$words[2]" = *:completion:inc* ]]; then
+        _wanted values expl 'cursor positioning' compadd complete key default
+      elif [[ "$words[2]" = *:completion::* ]]; then
+        _wanted values expl 'cursor positioning' compadd true false
+      else
+        _wanted values expl 'cursor positioning' \
+	  compadd complete key default true false
+      fi
       ;;
 
     completer)
-      _wanted values expl completer &&
-	compadd "$expl[@]" _complete _approximate _correct _match \
-          _expand _list _menu _oldlist
+      _wanted values expl completer \
+	compadd _complete _approximate _correct _match \
+                _expand _list _menu _oldlist _next_tags
       ;;
 
-    host-port*)
+    user-host-port)
+      if [[ $PREFIX != *[@:]* ]]; then
+	_users -S @
+      elif [[ $PREFIX = *[@:]*[[@:]* ]]; then
+	compset -P 2 '*[:@]'
+	_ports
+      else
+	compset -P 1 '*[:@]'
+	_hosts -S :
+      fi
+      ;;
+
+    host-port)
       if [[ $PREFIX != *:* ]]; then
 	_hosts -S :
-      elif [[ $ostate != *user || $PREFIX != *:*:* ]]; then
+      else
 	compset -P 1 '*:'
 	_ports
-      else
-	compset -P 2 '*:'
-        _users
       fi
       ;;
 
     listwhen)
-      _wanted values expl 'when to list completions' &&
-	compadd "$expl[@]" always never sometimes
+      _wanted values expl 'when to list completions' \
+	compadd always never sometimes
+      ;;
+
+    packageset)
+      _wanted values expl 'default package set' \
+        compadd available installed uninstalled
       ;;
 
     progress)
-      _wanted values expl 'progress meter style' &&
-        compadd "$expl[@]" none bar percent
+      _wanted values expl 'progress meter style' \
+        compadd none bar percent
       ;;
 
     sdirs)
-      _wanted values expl 'whether to complete . or ..' &&
-        compadd "$expl[@]" true false ..
+      _wanted values expl 'whether to complete . or ..' \
+        compadd true false ..
       ;;
 
     stop)
-      _wanted values expl 'when to insert matches' &&
-	compadd "$expl[@]" true false verbose
+      _wanted values expl 'when to insert matches' \
+	compadd true false verbose
       ;;
 
     tag)
-      _wanted tags expl tag && compadd "$expl[@]" - $taglist
+      compset -q
+      if compset -P '*:*:'; then
+        _message description
+      elif compset -P '*:'; then
+        _message 'tag alias'
+      else
+        _wanted tags expl tag compadd - $taglist
+      fi
+      ;;
+
+    filepat)
+      if compset -P '*:*:'; then
+        _message description
+      elif compset -P '*:'; then
+        _message tag
+      else
+        _message 'glob patterns'
+      fi
       ;;
 
     user-host)
-      if [[ $PREFIX = *:* ]]; then
-	compset -P '*:'
+      if [[ $PREFIX = *[@:]* ]]; then
+	compset -P '*[@:]'
 	_hosts
       else
-	_users
+	_users -S @
       fi
       ;;
 
+    ignorepar)
+      _wanted values expl 'which parents to ignore' \
+        compadd parent pwd .. directory
+      ;;
+
+    single-ignored)
+      _wanted values expl 'how to handle a single ignored match' \
+          compadd - show menu
+      ;;
+
     _*)
       ${=ostate}
       ;;
diff --git a/Completion/Commands/_complete_help b/Completion/Commands/_complete_help
index cfefdcf90..cfc922df5 100644
--- a/Completion/Commands/_complete_help
+++ b/Completion/Commands/_complete_help
@@ -1,35 +1,80 @@
 #compdef -k complete-word \C-xh
 
 _complete_help() {
-  local _sort_tags=_help_sort_tags text i
-  typeset -A help_tags
-  typeset -U help_contexts
-
-  help_contexts=()
+  local _sort_tags=_help_sort_tags text i j k
+  typeset -A help_funcs help_tags help_sfuncs help_styles
 
   compadd() { return 1 }
+  zstyle() {
+    local _f="${${(@)${(@)funcstack[2,(i)_(main_complete|complete|approximate|normal)]}:#_(wanted|requested|loop|try)}% *}"
+
+    [[ -z "$_f" ]] && _f="${${(@)funcstack[2,(i)_(main_complete|complete|approximate|normal)]}:#_(wanted|requested|loop|try)}"
+
+    if [[ "$help_sfuncs[$2]" != *${_f}* ||
+          "$help_styles[${2}${_f}]" != *${3}* ]]; then
+      [[ "$help_sfuncs[$2]" != *${_f}* ]] &&
+          help_sfuncs[$2]="${help_sfuncs[$2]}:${_f}"
+      local _t
+
+      case "$1" in
+      -s) _t='[string] ';;
+      -a) _t='[array]  ';;
+      -h) _t='[assoc]  ';;
+      *)  _t='[boolean]';;
+      esac
+      help_styles[${2}${_f}]="${help_styles[${2}${_f}]},${_t} ${3}:${_f}"
+    fi
+    builtin zstyle "$@"
+  }
 
   _main_complete
 
-  unfunction compadd
+  unfunction compadd zstyle
 
-  for i in "$help_contexts[@]"; do
+  for i in "${(@ok)help_funcs}"; do
     text="${text}
-tags in context \`${i}': ${help_tags[$i]}"
+tags in context :completion:${i}:"
+    tmp=()
+    for j in "${(@s.:.)help_funcs[$i][2,-1]}"; do
+      tmp=( "$tmp[@]" "${(@s.,.)help_tags[${i}${j}][2,-1]}" )
+    done
+    zformat -a tmp '  (' "$tmp[@]"
+    tmp=( '
+    '${^tmp}')' )
+    text="${text}${tmp}"
   done
 
-  compstate[list]=list
-  compstate[force_list]=yes
+  text="$text
+"
+  for i in "${(@ok)help_sfuncs}"; do
+    text="${text}
+styles in context ${i}"
+    tmp=()
+    for j in "${(@s.:.)help_sfuncs[$i][2,-1]}"; do
+      tmp=( "$tmp[@]" "${(@s.,.)help_styles[${i}${j}][2,-1]}" )
+    done
+    zformat -a tmp '  (' "$tmp[@]"
+    tmp=( '
+    '${^tmp}')' )
+    text="${text}${tmp}"
+  done
+
+  compstate[list]='list force'
   compstate[insert]=''
 
   compadd -UX "$text[2,-1]" -n ''
 }
 
 _help_sort_tags() {
-  help_contexts=( "$help_contexts[@]" "$curcontext" )
-  help_tags[$curcontext]="${help_tags[$curcontext]}
-    ${argv}"
-  comptry "$@"
+  local f="${${(@)${(@)funcstack[3,(i)_(main_complete|complete|approximate|normal)]}:#_(wanted|requested|loop|try)}% *}"
+
+  if [[ "$help_funcs[$curcontext]" != *${f}* ||
+        "$help_tags[${curcontext}${f}]" != *(${(j:|:)~argv})* ]]; then
+    [[ "$help_funcs[$curcontext]" != *${f}* ]] &&
+        help_funcs[$curcontext]="${help_funcs[$curcontext]}:${f}"
+    help_tags[${curcontext}${f}]="${help_tags[${curcontext}${f}]},${argv}:${f}"
+    comptry "$@"
+  fi
 }
 
 _complete_help "$@"
diff --git a/Completion/Commands/_history_complete_word b/Completion/Commands/_history_complete_word
index fc67c0f14..d904e01f1 100644
--- a/Completion/Commands/_history_complete_word
+++ b/Completion/Commands/_history_complete_word
@@ -1,2 +1,105 @@
-#compdef -k complete-word \e/
-compgen -Q -H 0 ''
+#compdef -K _history-complete-older complete-word \e/ _history-complete-newer complete-word \e,
+#
+# Complete words from the history
+#
+# by Adam Spiers, with help gratefully received from
+# Sven Wischnowsky and Bart Schaefer
+#
+# Available styles:
+#
+#   :history-words:list -- display lists of available matches
+#   :history-words:stop -- prevent looping at beginning and end of matches
+#                          during menu-completion
+#   :history-words:sort -- sort matches lexically (default is to sort by age)
+#   :history-words:remove-all-dups --
+#                          remove /all/ duplicate matches rather than just
+#                          consecutives
+#
+
+_history_complete_word () {
+  local expl direction stop
+
+  if [[ $WIDGET = *newer ]]; then
+    direction=newer
+  else
+    direction=older
+  fi
+
+  zstyle -s ":completion:${curcontext}:history-words" stop stop
+
+  zstyle -t ":completion:${curcontext}:history-words" list || compstate[list]=''
+
+  if [[ -n "$compstate[old_list]" &&
+        ( -n "$stop" || "$compstate[insert]" = menu ) ]] ; then
+    # array of matches is newest -> oldest (reverse of history order)
+    if [[ "$direction" == 'older' ]]; then
+      if [[ compstate[old_insert] -eq $_hist_menu_length ||
+            "$_hist_stop" == 'oldest' ]]; then
+        _hist_stop='oldest'
+        [[ "$stop" = verbose ]] &&
+          _message 'beginning of history reached'
+      elif [[ "$_hist_stop" == 'newest' ]]; then
+        zle -Rc
+        _history_complete_word_gen_matches
+      else
+        compstate[old_list]=keep
+        (( compstate[insert] = compstate[old_insert] + 1 ))
+      fi
+    elif [[ "$direction" == 'newer' ]]; then
+      if [[ compstate[old_insert] -eq 1 || "$_hist_stop" == 'newest' ]]; then
+        _hist_stop='newest'
+        [[ "$stop" = verbose ]] && _message 'end of history reached'
+      elif [[ "$_hist_stop" == 'oldest' ]]; then
+        zle -Rc
+        _history_complete_word_gen_matches
+      else
+        compstate[old_list]=keep
+        (( compstate[insert] = compstate[old_insert] - 1 ))
+      fi
+    fi
+  else
+    _hist_stop=''
+    _hist_old_prefix="$PREFIX"
+    _history_complete_word_gen_matches
+  fi
+
+  [[ -n "$compstate[nmatches]" ]]
+}
+
+_history_complete_word_gen_matches () {
+  local opt
+
+  [[ -n "$_hist_stop" ]] && PREFIX="$_hist_old_prefix"
+
+  if zstyle -t ":completion:${curcontext}:history-words" remove-all-dups; then
+    opt=-
+  else
+    opt=-1
+  fi
+  if zstyle -t ":completion:${curcontext}:history-words" sort; then
+    opt="${opt}J"
+  else
+    opt="${opt}V"
+  fi
+
+  _wanted "$opt" history-words expl 'history word' \
+      compadd -Q - "$historywords[@]"
+
+  zstyle -t ":completion:${curcontext}:history-words" list ||
+      compstate[list]=
+
+  _hist_menu_length="$compstate[nmatches]"
+
+  case "$direction" in 
+    newer)  compstate[insert]=$_hist_menu_length
+	    [[ -n "$_hist_stop" ]] && (( compstate[insert]-- ))
+            ;;
+    older)  compstate[insert]=1
+	    [[ -n "$_hist_stop" ]] && (( compstate[insert]++ ))
+            ;;
+  esac
+
+  [[ -n "$_hist_stop" ]] && _hist_stop=''
+}
+
+_history_complete_word "$@"
diff --git a/Completion/Commands/_next_tags b/Completion/Commands/_next_tags
index 8bd3f5921..4861d1adf 100644
--- a/Completion/Commands/_next_tags
+++ b/Completion/Commands/_next_tags
@@ -1,70 +1,92 @@
 #compdef -k complete-word \C-xn
 
-# Main widget/completer.
+# Main widget.
 
 _next_tags() {
+  local comp
 
-  if [[ $#funcstack -gt 1 ]]; then
+  if [[ -z $compstate[old_list] ]]; then
+    comp=()
+  else
+    comp=(_complete)
+  fi
 
-    # Called as completer, probably `remove' our helper function. A better
-    # test would be nice, but I think one should still be able to edit the
-    # current word between attempts to complete it.
+  (( $+_sort_tags )) || _next_tags_not=
 
-    [[ $_next_tags_pre != ${LBUFFER%${PREFIX}} ]] && unset _sort_tags
+  _sort_tags=_next_tags_sort
+  _next_tags_pre="${LBUFFER%${PREFIX}}"
+  _next_tags_not="$_next_tags_not $_lastcomp[tags]"
 
-    return 1
-  else
-    local comp
+  _main_complete "$comp[@]"
 
-    if [[ -z $compstate[old_list] ]]; then
-      comp=()
-    else
-      comp=(_next_tags _complete)
-    fi
+  [[ $compstate[insert] = automenu ]] &&
+     compstate[insert]=automenu-unambiguous
+
+  compstate[insert]=''
+  compstate[list]='list force'
 
-    (( $+_sort_tags )) || _next_tags_not=
+  compprefuncs=( "$compprefuncs[@]" _next_tags_pre )
+}
 
-    _sort_tags=_next_tags_sort
-    _next_tags_pre="${LBUFFER%${PREFIX}}"
-    _next_tags_not="$_next_tags_not $_lastcomp[tags]"
+# Pre-completion function.
 
-    _main_complete "$comp[@]"
+_next_tags_pre() {
 
-    [[ $compstate[insert] = automenu ]] &&
-       compstate[insert]=automenu-unambiguous
+  # Probably `remove' our sort function. A better test would be nice, but
+  # I think one should still be able to edit the current word between
+  # attempts to complete it.
 
-    compstate[insert]=''
-    compstate[list]='list force'
+  if [[ $_next_tags_pre != ${LBUFFER%${PREFIX}} ]]; then
+    unset _sort_tags
+  else
+    compprefuncs=( "$compprefuncs[@]" _next_tags_pre )
   fi
 }
 
 # Helper function for sorting tags. Most of this is copied from _tags.
 
 _next_tags_sort() {
-  local order tags tag nodef
+  local order tags tag nodef tmp
 
   zstyle -a ":completion:${curcontext}:" tag-order order ||
-    order=( 'arguments values' options globbed-files directories all-files )
+      order=('arguments values' options)
 
   # But we also remove the tags we've already tried...
 
-  tags=( "${(@)order:#(${(j:|:)~${=_next_tags_not}})}" )
+  tags=( "${(@)order:#(${(j:|:)~${=_next_tags_not}})(|:*)}" )
 
   # ... unless that would remove all offered tags.
 
-  [[ $#tags -ne $#order && "$tags" != *(${(j:|:)~argv})* ]] &&
-    tags=( $order ) _next_tags_not=
-
+  if [[ $funcstack[4] = _files ]]; then
+    if zstyle -a ":completion:${curcontext}:" file-patterns tmp; then
+      [[ "$tags" = *${${tmp[-1]##[^\\]:}%:*}* ]] &&
+          tags=( $order ) _next_tags_not=
+    else
+      [[ "$tags" = *all-files* ]] && tags=( $order ) _next_tags_not=
+    fi
+  else
+     [[ $#tags -ne $#order && "$tags" != *(${(j:|:)~argv})* ]] &&
+        tags=( $order ) _next_tags_not=
+  fi
   for tag in $tags; do
     case $tag in
     -)     nodef=yes;;
     *\(\)) "${${tag%%[ 	]#\(\)}##[ 	]#}" "$@";;
-    \!*)   comptry "${(@)argv:#(${(j:|:)~${=tag[2,-1]}})}";;
-    ?*)    comptry ${=tag};;
+    \!*)   comptry "${(@)argv:#(${(j:|:)~${=~tag[2,-1]}})}";;
+    ?*)    comptry -m "$tag";;
     esac
   done
 
-  [[ -z "$nodef" ]] && comptry "$@"
+  if [[ -z "$nodef" ]]; then
+    if [[ $funcstack[4] = _files ]]; then
+      if zstyle -a ":completion:${curcontext}:" file-patterns tmp; then
+        [[ "$argv" = *${${tmp[-1]##[^\\]:}%:*}* ]] && _next_tags_not=
+      else
+        [[ "$argv" = *all-files* ]] && _next_tags_not=
+      fi
+    fi
+    comptry "${(@)argv:#(${(j:|:)~${=_next_tags_not}})(|:*)}"
+  fi
 }
 
 [[ -o kshautoload ]] || _next_tags "$@"
diff --git a/Completion/Core/_all_labels b/Completion/Core/_all_labels
new file mode 100644
index 000000000..fa7118ec4
--- /dev/null
+++ b/Completion/Core/_all_labels
@@ -0,0 +1,44 @@
+#autoload
+
+local gopt=-J len tmp pre suf tloop ret=1 descr
+
+if [[ "$1" = -t ]]; then
+  tloop=yes
+  shift
+fi
+if [[ "$1" = -([12]|)[VJ] ]]; then
+  gopt="$1"
+  shift
+fi
+
+tmp=${argv[(ib:4:)-]}
+len=$#
+if [[ tmp -lt len ]]; then
+  pre=$(( tmp-1 ))
+  suf=$tmp
+elif [[ tmp -eq $# ]]; then
+  pre=-2
+  suf=$(( len+1 ))
+else
+  pre=4
+  suf=5
+fi
+
+while [[ -z "$tloop" ]] || comptags -N; do
+  while comptags -A "$1" curtag; do
+    if [[ "$curtag" = *:* ]]; then
+      zformat -f descr "${curtag#*:}" "d:$3"
+      _description "$gopt" "${curtag%:*}" "$2" "$descr"
+      curtag="${curtag%:*}"
+
+      "$4" "${(P@)2}" "${(@)argv[5,-1]}"
+    else
+      _description "$gopt" "$curtag" "$2" "$3"
+
+      "${(@)argv[4,pre]}" "${(P@)2}" "${(@)argv[suf,-1]}" && ret=0
+    fi
+  done
+  [[ -z "$tloop" || ret -eq 0 ]] && break
+done
+
+return ret
diff --git a/Completion/Core/_alternative b/Completion/Core/_alternative
index 158f3a07a..b038aa8a4 100644
--- a/Completion/Core/_alternative
+++ b/Completion/Core/_alternative
@@ -1,19 +1,23 @@
 #autoload
 
-local tags def expl descr action mesgs nm="$compstack[nmatches]"
-local context
+local tags def expl descr action mesgs nm="$compstate[nmatches]" subopts
+local opt curcontext="$curcontext"
+
+subopts=()
+while getopts 'O:C:' opt; do
+  case "$opt" in
+  O) subopts=( "${(@P)OPTARG}" ) ;;
+  C) curcontext="${curcontext%:*}:$OPTARG" ;;
+  esac
+done
+
+shift OPTIND-1
 
-if [[ "$1" = -C?* ]]; then
-  context="${1[3,-1]}"
-  shift
-elif [[ "$1" = -C ]]; then
-  context="$2"
-  shift 2
-fi
+[[ "$1" = -(|-) ]] && shift
 
 mesgs=()
 
-_tags -C "$context" "${(@)argv%%:*}"
+_tags "${(@)argv%%:*}"
 
 while _tags; do
   for def; do
@@ -21,7 +25,7 @@ while _tags; do
       descr="${${def#*:}%%:*}"
       action="${def#*:*:}"
 
-      _description expl "$descr"
+      _description "${def%%:*}" expl "$descr"
 
       if [[ "$action" = \ # ]]; then
 
@@ -35,28 +39,35 @@ while _tags; do
 
         eval ws\=\( "${action[3,-3]}" \)
 
-        _describe "$descr" ws -M 'r:|[_-]=* r:|=*'
+        _describe "$descr" ws -M 'r:|[_-]=* r:|=*' "$subopts[@]"
       elif [[ "$action" = \(*\) ]]; then
 
         # Anything inside `(...)' is added directly.
 
-        compadd "$expl[@]" - ${=action[2,-2]}
+        _all_labels "${def%%:*}" expl "$descr" \
+            compadd "$subopts[@]" - ${=action[2,-2]}
       elif [[ "$action" = \{*\} ]]; then
 
         # A string in braces is evaluated.
 
-        eval "$action[2,-2]"
+        while _next_label "${def%%:*}" expl "$descr"; do
+          eval "$action[2,-2]"
+        done
       elif [[ "$action" = \ * ]]; then
 
         # If the action starts with a space, we just call it.
 
-        ${(e)=~action}
+        eval "action=( $action )"
+        while _next_label "${def%%:*}" expl "$descr"; do
+          "$action[@]"
+        done
       else
 
         # Otherwise we call it with the description-arguments built above.
 
-        action=( $=action )
-        ${(e)action[1]} "$expl[@]" ${(e)~action[2,-1]}
+        eval "action=( $action )"
+        _all_labels "${def%%:*}" expl "$descr" \
+            "$action[1]" "$subopts[@]" "${(@)action[2,-1]}"
       fi
     fi
   done
diff --git a/Completion/Core/_approximate b/Completion/Core/_approximate
index 1b40f7cbf..0815a308e 100644
--- a/Completion/Core/_approximate
+++ b/Completion/Core/_approximate
@@ -1,102 +1,30 @@
 #autoload
 
 # This code will try to correct the string on the line based on the
-# strings generated for the context if `compconfig[correct]' is set.
-# These corrected strings will be shown in a list and one can
-# cycle through them as in a menucompletion or get the corrected prefix.
-#
-# Supported configuration keys:
-#
-#  approximate_accept
-#    This should be set to a number, specifying the maximum number
-#    of errors that should be accepted. If the string also contains
-#    a `n' or `N', the code will use the numeric argument as the
-#    maximum number of errors if a numeric argument was given. If no
-#    numeric argument was given, the number from the value of this
-#    key will be used. E.g. with `compconf approximate_accept=2n' two
-#    errors will be accepted, but if the user gives another number
-#    with the numeric argument, this will be prefered. Also, with
-#    `compconf approximate_accept=0n', normally no correction will be
-#    tried, but if a numeric argument is given, automatic correction
-#    will be used. On the other hand, if the string contains an `!'
-#    and a `n' or `N', correction is not attempted if a numeric
-#    argument is given. Once the number of errors to accept is
-#    determined, the code will repeatedly try to generate matches by
-#    allowing one error, two errors, and so on. Independent of the
-#    number of errors the user wants to accept, the code will allow
-#    only fewer errors than there are characters in the string from
-#    the line.
-#
-#  approximate_original
-#    This value is used to determine if the original string should
-#    be included in the list (and thus be presented to the user when
-#    cycling through the corrections). If it is set to any non-empty
-#    value, the original string will be offered. If it contains the
-#    sub-string `last', the original string will appear as the last
-#    string when cycling through the corrections, otherwise it will
-#    appear as the first one (so that the command line does not
-#    change immediately). Also, if the value contains the sub-string
-#    `always', the original string will always be included, whereas
-#    normally it is included only if more than one possible
-#    correction was generated.
-#
-#  approximate_prompt
-#    This can be set to a string that should be printed before the
-#    list of corrected strings when cycling through them. This string
-#    may contain the control sequences `%n', `%B', etc. known from
-#    the `-X' option of `compctl'. Also, the sequence `%e' will be
-#    replaced by the number of errors accepted to generate the
-#    corrected strings.
-#
-#  approximate_insert
-#    If this is set to a string starting with `unambig', the code
-#    will try to insert a usable unambiguous string in the command
-#    line instead of always cycling through the corrected strings.
-#    If such a unambiguous string could be found, the original
-#    string is not used, independent of the setting of
-#    `approximate_original'. If no sensible string could be found,
-#    one can cycle through the corrected strings as usual.
-#
-# If any of these keys is not set, but the the same key with the
-# prefix `correct' instead of `approximate' is set, that value will
-# be used.
-
-local _comp_correct _correct_prompt comax
-local cfgacc cfgorig cfgps cfgins
-
-# Only if all global matchers hav been tried.
-
-[[ compstate[matcher] -ne compstate[total_matchers] ]] && return 1
-
-# We don't try correction if the string is too short.
-
-[[ "${#:-$PREFIX$SUFFIX}" -le 1 ]] && return 1
-
-# Get the configuration values, using either the prefix `correct' or
-# `approximate'.
-
-if [[ "$compstate[pattern_match]" = (|\**) ]]; then
-  cfgacc="${compconfig[approximate_accept]:-$compconfig[correct_accept]}"
-  cfgorig="${compconfig[approximate_original]:-$compconfig[correct_original]}"
-  cfgps="${compconfig[approximate_prompt]:-$compconfig[correct_prompt]}"
-  cfgins="${compconfig[approximate_insert]:-$compconfig[correct_insert]}"
-else
-  cfgacc="$compconfig[correct_accept]"
-  cfgorig="$compconfig[correct_original]"
-  cfgps="$compconfig[correct_prompt]"
-  cfgins="$compconfig[correct_insert]"
-fi
+# strings generated for the context. These corrected strings will be
+# shown in a list and one can cycle through them as in a menucompletion
+# or get the corrected prefix.
+
+# We don't try correction if the string is too short or we have tried it
+# already.
+
+[[ _matcher_num -gt 1 || "${#:-$PREFIX$SUFFIX}" -le 1 ]] && return 1
+
+local _comp_correct _correct_expl comax cfgacc
+local oldcontext="${curcontext}" opm="$compstate[pattern_match]"
+
+zstyle -s ":completion:${curcontext}:" max-errors cfgacc || cfgacc='2 numeric'
 
 # Get the number of errors to accept.
 
-if [[ "$cfgacc" = *[nN]* && NUMERIC -ne 1 ]]; then
-  # Stop if we also have a `!'.
+if [[ "$cfgacc" = *numeric* && ${NUMERIC:-1} -ne 1 ]]; then
+  # A numeric argument may mean that we should not try correction.
 
-  [[ "$cfgacc" = *\!* ]] && return 1
+  [[ "$cfgacc" = *not-numeric* ]] && return 1
 
   # Prefer the numeric argument if that has a sensible value.
 
-  comax="$NUMERIC"
+  comax="${NUMERIC:-1}"
 else
   comax="${cfgacc//[^0-9]}"
 fi
@@ -105,13 +33,15 @@ fi
 
 [[ "$comax" -lt 1 ]] && return 1
 
-# Otherwise temporarily define functions to use instead of
-# the builtins that add matches. This is used to be able
-# to stick the `(#a...)' into the right place (after an
+_tags corrections original
+
+# Otherwise temporarily define a function to use instead of
+# the builtin that adds matches. This is used to be able
+# to stick the `(#a...)' in the right place (after an
 # ignored prefix).
 
 compadd() {
-  [[ "$*" != *-([a-zA-Z/]#|)U* &&
+  [[ ${argv[(I)-[a-zA-Z]#U[a-zA-Z]#]} -eq 0 &&
      "${#:-$PREFIX$SUFFIX}" -le _comp_correct ]] && return
 
   if [[ "$PREFIX" = \~*/* ]]; then
@@ -119,79 +49,49 @@ compadd() {
   else
     PREFIX="(#a${_comp_correct})$PREFIX"
   fi
-  if [[ -n "$_correct_prompt" ]]; then
-    builtin compadd -X "$_correct_prompt" -J _correct "$@"
-  else
-    builtin compadd -J _correct "$@"
-  fi
+  builtin compadd "$_correct_expl[@]" "$@"
 }
 
-compgen() {
-  [[ "$*" != *-([a-zA-Z/]#|)U* &&
-     "${#:-$PREFIX$SUFFIX}" -le _comp_correct ]] && return
-
-  if [[ "$PREFIX" = \~*/* ]]; then
-    PREFIX="${PREFIX%%/*}/(#a${_comp_correct})${PREFIX#*/}"
-  else
-    PREFIX="(#a${_comp_correct})$PREFIX"
-  fi
-  if [[ -n "$_correct_prompt" ]]; then
-    builtin compgen "$@" -X "$_correct_prompt" -J _correct
-  else
-    builtin compgen "$@" -J _correct
-  fi
-}
-
-# Now initialise our counter. We also set `compstate[matcher]'
-# to `-1'. This allows completion functions to use the simple
-# `[[ compstate[matcher] -gt 1 ]] && return' to avoid being
-# called for multiple global match specs and still be called 
-# again when correction is done. Also, this makes it easy to
-# test if correction is attempted since `compstate[matcher]'
-# will never be set to a negative value by the completion code.
-
 _comp_correct=1
-compstate[matcher]=-1
-
-_correct_prompt="${cfgps//\%e/1}"
-
-# We also need to set `extendedglob' and make the completion
-# code behave as if globcomplete were set.
-
-setopt extendedglob
 
 [[ -z "$compstate[pattern_match]" ]] && compstate[pattern_match]='*'
 
 while [[ _comp_correct -le comax ]]; do
+  curcontext="${oldcontext/(#b)([^:]#:[^:]#:)/${match[1][1,-2]}-${_comp_correct}:}"
+
+  _description corrections _correct_expl corrections \
+               "e:$_comp_correct" "o:$PREFIX$SUFFIX"
+
   if _complete; then
-    if [[ "$cfgins" = unambig* &&
-          "${#compstate[unambiguous]}" -ge "${#:-$PREFIX$SUFFIX}" ]]; then
+    if zstyle -t ":completion:${curcontext}:" insert-unambiguous &&
+       [[ "${#compstate[unambiguous]}" -ge "${#:-$PREFIX$SUFFIX}" ]]; then
       compstate[pattern_insert]=unambiguous
-    elif [[ compstate[nmatches] -gt 1 || "$cfgorig" = *always* ]]; then
-      if [[ "$cfgorig" = *last* ]]; then
-        builtin compadd -U -V _correct_original -nQ - "$PREFIX$SUFFIX"
-      elif [[ -n "$cfgorig" ]]; then
-	builtin compadd -U -nQ - "$PREFIX$SUFFIX"
-      fi
+    elif _requested original &&
+         { [[ compstate[nmatches] -gt 1 ]] ||
+           zstyle -t ":completion:${curcontext}:" original }; then
+      local expl
+
+      _description -V original expl original
+
+      builtin compadd "$expl[@]" -U -Q - "$PREFIX$SUFFIX"
 
       # If you always want to see the list of possible corrections,
-      # set `compstate[list]=list' here.
+      # set `compstate[list]=list force' here.
 
-      compstate[force_list]=list
+      [[ "$compstate[list]" != list* ]] &&
+          compstate[list]="$compstate[list] force"
     fi
-    compstate[matcher]="$compstate[total_matchers]"
-    unfunction compadd compgen
+    unfunction compadd
+    compstate[pattern_match]="$opm"
 
     return 0
   fi
 
   [[ "${#:-$PREFIX$SUFFIX}" -le _comp_correct+1 ]] && break
   (( _comp_correct++ ))
-
-  _correct_prompt="${cfgps//\%e/$_comp_correct}"
 done
 
-compstate[matcher]="$compstate[total_matchers]"
-unfunction compadd compgen
+unfunction compadd
+compstate[pattern_match]="$opm"
 
 return 1
diff --git a/Completion/Core/_call b/Completion/Core/_call
index 345dae50d..b038a80bc 100644
--- a/Completion/Core/_call
+++ b/Completion/Core/_call
@@ -1,4 +1,4 @@
-#autoload
+#autoload +X
 
 local tmp
 
diff --git a/Completion/Core/_complete b/Completion/Core/_complete
index 0f4d5ff4b..c2679dcb8 100644
--- a/Completion/Core/_complete
+++ b/Completion/Core/_complete
@@ -2,51 +2,65 @@
 
 # Generate all possible completions. Note that this is not intended as
 # a normal completion function, but as one possible value for the
-# compconfig[completer] parameter.
+# completer style.
 
-local comp name
+local comp name oldcontext
+typeset -T curcontext="$curcontext" ccarray
+
+oldcontext="$curcontext"
+
+# If we have a user-supplied context name, use only that.
+
+if [[ -n "$compcontext" ]]; then
+  ccarray[3]="$compcontext"
+
+  comp="$_comps[$compcontext]"
+  [[ -z "$comp" ]] || "$comp"
+
+  return
+fi
 
 # An entry for `-first-' is the replacement for `compctl -T'
-# Completion functions may set `_compskip' to any value to make the 
-# main loops stop calling other completion functions.
 
 comp="$_comps[-first-]"
 if [[ ! -z "$comp" ]]; then
+  ccarray[3]=-first-
   "$comp"
-  if (( $+_compskip )); then
-    unset _compskip
+  if [[ "$_compskip" = all ]]; then
+    _compskip=''
     (( compstate[nmatches] ))
     return
   fi
 fi
 
+
 # For arguments and command names we use the `_normal' function.
 
 if [[ "$compstate[context]" = command ]]; then
-  _normal
+  curcontext="$oldcontext"
+  _normal -s
 else
   # Let's see if we have a special completion definition for the other
   # possible contexts.
 
-  comp=''
-
-  case $compstate[context] in
-  equal)           comp="$_comps[-equal-]";;
-  tilde)           comp="$_comps[-tilde-]";;
-  redirect)        comp="$_comps[-redirect-]";;
-  math)            comp="$_comps[-math-]";;
-  subscript)       comp="$_comps[-subscript-]";;
-  value)           comp="$_comps[-value-]";;
-  array_value)     comp="$_comps[-array-value-]";;
-  condition)       comp="$_comps[-condition-]";;
-  parameter)       comp="$_comps[-parameter-]";;
-  brace_parameter) comp="$_comps[-brace-parameter-]";;
-  esac
+  local cname="-${compstate[context]:s/_/-/}-"
+
+  ccarray[3]="$cname"
+
+  comp="$_comps[$cname]"
 
   # If not, we use default completion, if any.
 
-  [[ -z "$comp" ]] && comp="$_comps[-default-]"
+  if [[ -z "$comp" ]]; then
+    if [[ "$_compskip" = *default* ]]; then
+      _compskip=''
+      return 1
+    fi
+    comp="$_comps[-default-]"
+  fi
   [[ -z "$comp" ]] || "$comp"
 fi
 
+_compskip=''
+
 (( compstate[nmatches] ))
diff --git a/Completion/Core/_correct b/Completion/Core/_correct
index 35ab01cf1..c9c3d999c 100644
--- a/Completion/Core/_correct
+++ b/Completion/Core/_correct
@@ -1,8 +1,8 @@
 #autoload
 
-# This is mainly a wrapper around the more general `_approximate.
+# This is mainly a wrapper around the more general `_approximate'.
 # By setting `compstate[pattern_match]' to something unequal to `*' and
-# then calling `_approximate, we get only corrections, not all strings
+# then calling `_approximate', we get only corrections, not all strings
 # with the corrected prefix and something after it.
 #
 # Supported configuration keys are the same as for `_approximate', only
diff --git a/Completion/Core/_description b/Completion/Core/_description
index 874ba8a96..7db47228b 100644
--- a/Completion/Core/_description
+++ b/Completion/Core/_description
@@ -1,22 +1,56 @@
 #autoload
 
-local gropt=-J
+local name gropt=-J format gname hidden hide match opts
 
-if [[ "$1" = -V ]]; then
-  gropt=-V
+opts=()
+
+if [[ "$1" = -([12]|)[VJ] ]]; then
+  gropt="$1"
   shift
 fi
 
-if [[ -n "$compconfig[group_matches]" ]]; then
-  if [[ -n "$compconfig[description_format]" ]]; then
-    eval "$1=($gropt ${(q)2} -X ${(q)compconfig[description_format]//\\%d/$2})"
+_lastdescr=( "$_lastdescr[@]" "$3" )
+
+_setup "$1"
+
+name="$2"
+
+zstyle -s ":completion:${curcontext}:$1" format format ||
+    zstyle -s ":completion:${curcontext}:descriptions" format format
+
+zstyle -s ":completion:${curcontext}:$1" hidden hidden
+if [[ "$hidden" = (all|yes|true|1|on) ]]; then
+  [[ "$hidden" = all ]] && format=''
+  opts=(-n)
+fi
+zstyle -s ":completion:${curcontext}:$1" group-name gname &&
+    [[ -z "$gname" ]] && gname="$1"
+zstyle -s ":completion:${curcontext}:$1" matcher match &&
+    opts=($opts -M "${(q)match}")
+[[ -n "$_matcher" ]] && opts=($opts -M "${(q)_matcher}")
+
+if [[ -z "$_comp_no_ignore" ]] &&
+   zstyle -a ":completion:${curcontext}:$1" ignored-patterns _comp_ignore; then
+  opts=( $opts -F _comp_ignore )
+else
+  _comp_ignore=()
+fi
+
+shift 2
+[[ -n "$format" ]] && zformat -f format "$format" "d:$1" "${(@)argv[2,-1]}"
+
+if [[ -n "$gname" ]]; then
+  if [[ -n "$format" ]]; then
+    eval "${name}=($opts $gropt ${(q)gname} -X \"${format}\")"
   else
-    eval "$1=($gropt ${(q)2})"
+    eval "${name}=($opts $gropt ${(q)gname})"
   fi
 else
-  if [[ -n "$compconfig[description_format]" ]]; then
-    eval "$1=(-X ${(q)compconfig[description_format]//\\%d/$2})"
+  if [[ -n "$format" ]]; then
+    eval "${name}=($opts $gropt -default- -X \"${format}\")"
   else
-    eval "$1=()"
+    eval "${name}=($opts $gropt -default-)"
   fi
 fi
+
+return 0
diff --git a/Completion/Core/_expand b/Completion/Core/_expand
index 9172b6cbf..eff8d8601 100644
--- a/Completion/Core/_expand
+++ b/Completion/Core/_expand
@@ -6,61 +6,20 @@
 # This function will allow other completer functions to be called if
 # the expansions done produce no result or do not change the original
 # word from the line.
-#
-# Configuration keys:
-#
-#  expand_substitute
-#    If this is unset or set to the empty string, the code will first
-#    try to expand all substitutions in the string (such as $(...) and
-#    ${...}). If this is set to an non-empty string it should be 
-#    an expression usable inside a $[...] arithmetical expression.
-#    In this case, expansion of substitutions will be done if the
-#    expression evaluates to `1'. For example, with
-#
-#      compconf expand_substitute='NUMERIC != 1'
-#
-#    substitution will be performed only if given an explicit numeric
-#    argument other than `1', as by typing ESC 2 TAB.
-#
-#  expand_glob
-#    If this is unset or set to an empty string, globbing will be
-#    attempted on the word resulting from substitution or the
-#    original string. The values accepted for this key are the same
-#    as for expand_substitute.
-#
-#  expand_menu
-#    If this is unset or set to the empty string, the words resulting
-#    from expansion (if any) will simply be inserted in the ommand line,
-#    replacing the original string. However, if this key is set to an
-#    non-empty string, the user can cycle through the expansion as in
-#    a menucompletion. Unless the value contains the sub-string `only',
-#    the user will still be offered all expansions at once as one of
-#    the strings to insert in the command line. Also, if the value
-#    contains the sub-string `last', the string with all expansion will
-#    be offered first, whereas normally it is offered as the last string
-#    to insert. Finally, if the value contains the sub-string `sort',
-#    the expansions will be sorted alphabetically, normally they are
-#    kept in the order the expansion produced them in.
-#    
-#  expand_original
-#    If this is set to an non-empty string, the original string from the
-#    line will be included in the list of strings the user can cycle
-#    through as in a menucompletion. If the value contains the sub-string
-#    `last', the original string will appear as the last string, with
-#    other values it is inserted as the first one (so that the command
-#    line does not change immediatly).
-#
-#  expand_prompt
-#    This may be set to a string that should be displayed before the
-#    possible expansions. This is given to the -X option and thus may
-#    contain the control sequences `%n', `%B', etc. Also, the sequence
-#    `%o' in this string will be replaced by the original string.
-
-local exp word="$PREFIX$SUFFIX" group=-V
-
-# Do this only for the first global matcher.
-
-[[ "$compstate[matcher]" -le 1 ]] || return 1
+
+setopt localoptions nullglob
+
+[[ _matcher_num -gt 1 ]] && return 1
+
+local exp word="$PREFIX$SUFFIX" sort expr expl subd suf=" "
+
+# First, see if we should insert all *completions*.
+
+if zstyle -s ":completion:${curcontext}:" completions expr &&
+   [[ "${(e):-\$[$expr]}" -eq 1 ]]; then
+  compstate[insert]=all
+  return 1
+fi
 
 # In exp we will collect the expansion.
 
@@ -69,79 +28,68 @@ exp=("$word")
 # First try substitution. That weird thing spanning multiple lines
 # changes quoted spaces, tabs, and newlines into spaces.
 
-[[ -z "$compconfig[expand_substitute]" ||
-   "${(e):-\$[$compconfig[expand_substitute]]}" -eq 1 ]] &&
+zstyle -s ":completion:${curcontext}:" substitute expr &&
+    [[ "${(e):-\$[$expr]}" -eq 1 ]] &&
     exp=( "${(e)exp//\\[ 	
 ]/ }" )
 
 # If the array is empty, store the original string again.
 
-[[ -z "$exp" ]] && exp=("$word")
+(( $#exp )) || exp=("$word")
+
+subd=("$exp[@]")
 
 # Now try globbing.
 
-[[ -z "$compconfig[expand_glob]" ||
-   "${(e):-\$[$compconfig[expand_glob]]}" -eq 1 ]] &&
-    exp=( ${~exp}(N) )
+zstyle -s ":completion:${curcontext}:" glob expr &&
+    [[ "${(e):-\$[$expr]}" -eq 1 ]] &&
+    exp=( ${~exp} )
 
 # If we don't have any expansions or only one and that is the same
 # as the original string, we let other completers run.
 
-[[ $#exp -eq 0 ||
-   ( $#exp -eq 1 && "$exp[1]" = "$word" ) ]] && return 1
+(( $#exp )) || exp=("$subd[@]")
 
-# We have expansions, should we menucomplete them?
+[[ $#exp -eq 1 && "$exp[1]" = "$word"(|\(N\)) ]] && return 1
 
-if [[ -z "$compconfig[expand_menu]" ]]; then
+# With subst-globs-only we bail out if there were no glob expansions,
+# regardless of any substitutions
 
-  # No, so if the user only wants a list, we add the strings
-  # separately. Otherwise we add the whole array as one string,
-  # probably also adding the original string.
+zstyle -s ":completion:${curcontext}:" subst-globs-only expr &&
+    [[ "${(e):-\$[$expr]}" -eq 1 && "$subd" = "$exp"(|\(N\)) ]] && return 1
 
-  if [[ -z "$compstate[insert]" ]]; then
-    compadd -U -V _expand -Q - "$exp[@]"
-  else
-    [[ -n "$compconfig[expand_original]" && 
-       "$compconfig[expand_original]" != *last* ]] &&
-        compadd -UnQ -V _expand_original - "$word"
+# Now add as matches whatever the user requested.
 
-    compadd -UQ -V _expand - "$exp"
+zstyle -s ":completion:${curcontext}:" sort sort
 
-    [[ -n "$compconfig[expand_original]" && 
-       "$compconfig[expand_original]" = *last* ]] &&
-        compadd -UnQ -V _expand_original - "$word"
+[[ "$sort" = (yes|true|1|on) ]] && exp=( "${(@o)exp}" )
 
-    compstate[insert]=menu
-  fi
-else
-  # Sorting? We just use a different group type then.
+# If there is only one expansion, add a suitable suffix
+(($#exp == 1)) && suf='' && [[ -d $exp && "$exp[1]" != */ ]] && suf='/'  
 
-  [[ "$compconfig[expand_menu]" = *sort* ]] && group=-J
+if [[ -z "$compstate[insert]" ]] ;then
+  _description all-expansions expl 'all expansions' "o:$word"
 
-  # Now add the expansion string, probably also adding the original
-  # and/or the string containing all expanded string.
+  compadd "$expl[@]" -UQ -qS "$suf" - "$exp"
+else
+  _tags all-expansions expansions original
 
-  [[ -n "$compconfig[expand_original]" && 
-     "$compconfig[expand_original]" != *last* ]] &&
-      compadd -UnQ -V _expand_original - "$word"
 
-  [[ "$compconfig[expand_menu]" = *last* &&
-     "$compconfig[expand_menu]" != *only* ]] &&
-      compadd -UnQ -V _expand_all - "$exp"
+  if _requested all-expansions; then
+    _description all-expansions expl 'all expansions'
+    compadd "$expl[@]" -UQ -qS "$suf" - "$exp"
+  fi
 
-  if [[ -z "$compconfig[expand_prompt]" ]]; then
-    compadd -UQ $group _expand - "$exp[@]"
-  else
-    compadd -UQ -X "${compconfig[expand_prompt]//\%o/$word}" \
-            $group _expand - "$exp[@]"
+  if [[ $#exp -gt 1 ]] && _requested expansions; then
+    if [[ "$sort" = menu ]]; then
+      _description expansions expl expansions "o:$word"
+    else
+      _description -V expansions expl expansions "o:$word"
+    fi
+    compadd "$expl[@]" -UQ - "$exp[@]"
   fi
-  [[ "$compconfig[expand_menu]" != *last* &&
-     "$compconfig[expand_menu]" != *only* ]] &&
-      compadd -UnQ -V _expand_all - "$exp"
 
-  [[ -n "$compconfig[expand_original]" && 
-     "$compconfig[expand_original]" = *last* ]] &&
-      compadd -UnQ -V _expand_original - "$word"
+  _requested original expl original && compadd "$expl[@]" -UQ - "$word"
 
   compstate[insert]=menu
 fi
diff --git a/Completion/Core/_files b/Completion/Core/_files
index d2cce35e7..1755abebd 100644
--- a/Completion/Core/_files
+++ b/Completion/Core/_files
@@ -1,26 +1,49 @@
 #autoload
 
-# Utility function for completing files of a given type or any file.
-# In many cases you will want to call this one instead of _path_files().
+local opts tmp glob pats expl tag i pat descr minus
 
-local nm=$NMATCHES
+zparseopts -a opts \
+    '/=tmp' 'f=tmp' 'g+:-=tmp' q n 1 2 P: S: r: R: W: X+: M+: F: J+: V+:
 
-_path_files "$@"
+type="${(@j::M)${(@)tmp#-}#?}"
+(( $tmp[(I)-g*] )) && glob="${(j: :)${(M)tmp:#-g*}#-g}"
 
-if [[ $# -ne 0 && -nmatches nm ]]; then
-  local opt opts
+if zstyle -a ":completion:${curcontext}:" file-patterns pats; then
+  [[ "$type" = */* ]] && glob="$glob *(-/)"
+  pats=( \ ${(M)^${pats//\\%p/ ${glob:-\*} }:#*[^\\]:*} )
+else
+  if [[ "$type" = *g* ]]; then
+    if [[ "$type" = */* ]]; then
+      pats=( " ${glob//:/\\:} *(-/):globbed-files" '*:all-files' )
+    else
+      pats=( " ${glob//:/\\:}:globbed-files"
+             '*(-/):directories' '*:all-files' )
+    fi
+  elif [[ "$type" = */* ]]; then
+    pats=( '*(-/):directories' '*:all-files' )
+  else
+    pats=( '*:all-files' )
+  fi
+fi
 
-  # We didn't get any matches for those types of files described by
-  # the `-g' or `-/' option. Now we try it again accepting all files.
-  # First we get those options that we have to use even if then. If
-  # we find out that the `-f' option was given, we already accepted
-  # all files and give up immediatly.
+for tag in "${(@)${(@)pats#*[^\\]:}%%:*}"; do
 
-  opts=()
-  while getopts "P:S:W:F:J:V:X:f/g:" opt; do
-    [[ "$opt" = f ]] && return
-    [[ "$opt" = [PSWFJVX] ]] && opts=("$opts[@]" "-$opt" "$OPTARG")
-  done
+  i="$pats[(I)*[^\\\\]:${tag}(|:*)]"
+  pat="${${pats[i]%%:${tag}*}//\\\\:/:}"
 
-  _path_files "$opts[@]"
-fi
+  if [[ i -gt 0 && "$pat" != \ # ]]; then
+    if [[ "$pats[i]" = *:${tag}:* ]]; then
+      descr="${pats[i]#*:${tag}:}"
+      minus=()
+    else
+      descr=file
+      minus=(-)
+    fi
+  fi
+
+  _wanted "$tag" expl "$descr" \
+      _path_files -g "$pat" "$opts[@]" "$minus[@]" && return 0
+
+done
+
+return 1
diff --git a/Completion/Core/_ignored b/Completion/Core/_ignored
index 69a5244cc..4046f4c2d 100644
--- a/Completion/Core/_ignored
+++ b/Completion/Core/_ignored
@@ -4,11 +4,10 @@
 
 (( $compstate[ignored] )) || return 1
 
-local curcontext="${curcontext/:[^:]#:/:ignored-${(M)#_completers[1,_completer_num]:#_ignored}:}"
 local comp i _comp_no_ignore=yes tmp expl
 
 zstyle -a ":completion:${curcontext}:" completer comp ||
-  comp=( "${(@)_completers[1,_completer_num-1][(R)_ignored,-1]}" )
+  comp=( "${(@)_completers[1,_completer_num-1][(R)_ignored(|:*),-1]}" )
 
 for i in "$comp[@]"; do
   if [[ "$i" != _ignored ]] && "$i"; then
diff --git a/Completion/Core/_list b/Completion/Core/_list
index 099c6bc7b..37167726c 100644
--- a/Completion/Core/_list
+++ b/Completion/Core/_list
@@ -1,38 +1,16 @@
 #autoload
 
 # This completer function makes the other completer functions used
-# insert possible completions only after once the list has been
-# shown.
-#
-# Configuration keys:
-#
-#  list_condition
-#    If this key is unset or set to the empty string, this completer
-#    will delay the insertion of matches unconditionally. However,
-#    if this value is set, it should be set to an expression usable
-#    inside a $[...] arithmetical expression. In this case, delaying
-#    will be done if the expression evaluates to `1'.
-#    For example, with
-#
-#      compconf list_condition='NUMERIC != 1'
-#
-#    delaying will be done only if given an explicit numeric argument
-#    other than `1'.
-#
-#  list_word
-#    To find out if only listing should be done, the code normally
-#    compares the contents of the line with the contents the line
-#    had at the time of the last invocation. If this key is set to
-#    an non-empty string comparison is done using only the current
-#    word. So if it is set, attempting completion on a word equal
-#    to the one completion was called on the last time will not
-#    delay the generation of matches.
-
-local pre suf
+# insert possible completions only after the list has been shown at
+# least once.
+
+[[ _matcher_num -gt 1 ]] && return 1
+
+local pre suf expr
 
 # Get the strings to compare.
 
-if [[ -z "$compconfig[list_word]" ]]; then
+if zstyle -t ":completion:${curcontext}:" word; then
   pre="$HISTNO$LBUFFER"
   suf="$RBUFFER"
 else
@@ -42,16 +20,15 @@ fi
 
 # Should we only show a list now?
 
-if [[ ( -z "$compconfig[list_condition]" ||
-        "${(e):-\$[$compconfig[expand_glob]]}" -eq 1 ) &&
+zstyle -s ":completion:${curcontext}:" condition expr
+if [[ ( -z "$expr" || "${(e):-\$[$expr]}" -eq 1 ) &&
       ( "$pre" != "$_list_prefix" || "$suf" != "$_list_suffix" ) ]]; then
 
   # Yes. Tell the completion code about it and save the new values
   # to compare the next time.
 
   compstate[insert]=''
-  compstate[list]=list
-  compstate[force_list]=yes
+  compstate[list]='list force'
   _list_prefix="$pre"
   _list_suffix="$suf"
 fi
diff --git a/Completion/Core/_main_complete b/Completion/Core/_main_complete
index c7f5a5a96..d9278f435 100644
--- a/Completion/Core/_main_complete
+++ b/Completion/Core/_main_complete
@@ -2,47 +2,206 @@
 
 # The main loop of the completion code. This is what is called when 
 # completion is attempted from the command line.
-# The completion code gives us the special variables and the arguments
-# from the command line are given as positional parameters.
 
-local comp name
 
-setopt localoptions nullglob rcexpandparam globdots
-unsetopt markdirs globsubst shwordsplit nounset
+# If you want to complete only set or unset options for the unsetopt
+# and setopt builtin, un-comment these lines:
+#
+#   local _set_options _unset_options
+#
+#   _set_options=(${(k)options[(R)on]})
+#   _unset_options=(${(k)options[(R)off]})
+#
+# This is needed because completion functions may set options locally
+# which makes the output of setopt and unsetopt reflect a different
+# state than the global one for which you are completing.
 
-# An entry for `-first-' is the replacement for `compctl -T'
-# Completion functions may set `_compskip' to any value to make the 
-# main loops stop calling other completion functions.
+setopt localoptions nullglob rcexpandparam extendedglob
+unsetopt markdirs globsubst shwordsplit nounset ksharrays
 
-comp="$_comps[-first-]"
-if [[ ! -z "$comp" ]]; then
-  "$comp" "$@"
-  if (( $+_compskip )); then
-    unset _compskip
-    return
-  fi
+local func funcs ret=1 tmp _compskip format _comp_ignore \
+      _completers _completer _completer_num curtag \
+      _matchers _matcher _matcher_num _comp_tags \
+      context state line opt_args val_args curcontext="$curcontext" \
+      _last_nmatches=-1 _last_menu_style _def_menu_style _menu_style sel \
+      _saved_exact="${compstate[exact]}" \
+      _saved_lastprompt="${compstate[last_prompt]}" \
+      _saved_list="${compstate[list]}" \
+      _saved_insert="${compstate[insert]}"
+
+typeset -U _lastdescr
+
+[[ -z "$curcontext" ]] && curcontext=:::
+
+# Special completion contexts after `~' and `='.
+
+if compset -P 1 '='; then
+  compstate[context]=equal
+elif [[ "$PREFIX" != */* && "$PREFIX[1]" = '~' ]]; then
+  compset -p 1
+  compstate[context]=tilde
 fi
 
-# For arguments we use the `_normal function.
+# Initial setup.
+
+_setup default
+_def_menu_style=( "$_last_menu_style[@]"
+
+# We can't really do that because the current value of $SELECTMIN
+# may be the one set by this function.
+# There is a similar problem with $ZLS_COLORS in _setup.
+
+#                  ${SELECTMIN+select${SELECTMIN:+\=$SELECTMIN}}
+
+                )
+_last_menu_style=()
 
-if [[ $CONTEXT == argument || $CONTEXT == command ]]; then
-  _normal "$@"
+# Get the names of the completers to use in the positional parameters.
+
+if (( $# )); then
+  _completers=( "$@" )
 else
-  # Let's see if we have a special completion definition for the other
-  # possible contexts.
+  zstyle -a ":completion:${curcontext}:" completer _completers ||
+      _completers=( _complete )
+fi
+
+# And now just call the completer functions defined.
+
+_completer_num=1
+
+# Call the pre-functions.
+
+funcs=( "$compprefuncs[@]" )
+compprefuncs=()
+for func in "$funcs[@]"; do
+  "$func"
+done
+
+for tmp in "$_completers[@]"; do
+
+  if [[ "$tmp" = *:-* ]]; then
+    _completer="${${tmp%:*}[2,-1]//_/-}${tmp#*:}"
+    tmp="${tmp%:*}"
+  elif [[ $tmp = *:* ]]; then
+    _completer="${tmp#*:}"
+    tmp="${tmp%:*}"
+  else
+    _completer="${tmp[2,-1]//_/-}"
+  fi
+  curcontext="${curcontext/:[^:]#:/:${_completer}:}"
 
-  comp=''
+  zstyle -a ":completion:${curcontext}:" matcher-list _matchers ||
+      _matchers=( '' )
 
-  case $CONTEXT in
-  redirect)  comp="$_comps[-redirect-]";;
-  math)      comp="$_comps[-math-]";;
-  subscript) comp="$_comps[-subscript-]";;
-  value)     comp="$_comps[-value-]";;
-  condition) comp="$_comps[-condition-]";;
-  esac
+  _matcher_num=1
+  for _matcher in "$_matchers[@]"; do
+    if "$tmp"; then
+      ret=0
+      break 2
+    fi
+    (( _matcher_num++ ))
+  done
+  (( _completer_num++ ))
+done
 
-  # If not, we use default completion, if any.
+curcontext="${curcontext/:[^:]#:/::}"
 
-  [[ -z "$comp" ]] && comp="$_comps[-default-]"
-  [[ -z "$comp" ]] || "$comp" "$@"
+if [[ $compstate[old_list] = keep || $compstate[nmatches] -gt 1 ]]; then
+  [[ _last_nmatches -ge 0 && _last_nmatches -ne $compstate[nmatches] ]] &&
+      _menu_style=( "$_last_menu_style[@]" "$_menu_style[@]" )
+
+  if [[ "$compstate[insert]" = "$_saved_insert" ]]; then
+    if [[ -n "$_menu_style[(r)(yes|true|1|on)]" ||
+          ( -n "$_menu_style[(r)auto*]" &&
+            "$compstate[insert]" = automenu ) ]]; then
+      compstate[insert]=menu
+    elif [[ -n "$_menu_style[(r)auto*]" &&
+            "$compstate[insert]" != automenu ]]; then
+      compstate[insert]=automenu-unambiguous
+    elif [[ -n "$_menu_style[(r)(no|false|0|off)]" ]]; then
+      compstate[insert]=unambiguous
+    elif [[ -n "$_def_menu_style[(r)(yes|true|1|on)]" ||
+          ( -n "$_def_menu_style[(r)auto*]" &&
+            "$compstate[insert]" = automenu ) ]]; then
+      compstate[insert]=menu
+    elif [[ -n "$_def_menu_style[(r)auto*]" &&
+            "$compstate[insert]" != automenu ]]; then
+      compstate[insert]=automenu-unambiguous
+    elif [[ -n "$_def_menu_style[(r)(no|false|0|off)]" ]]; then
+      compstate[insert]=unambiguous
+    fi
+  fi
+
+  _menu_style=( "$_menu_style[@]" "$_def_menu_style[@]" )
+
+  if [[ "$compstate[insert]" = *menu* ]]; then
+    if [[ -n "$_menu_style[(r)no-select*]" ]]; then
+      unset SELECTMIN
+    else
+      sel=( "${(@M)_menu_style:#select*}" )
+
+      if (( $# )); then
+        local min=9999999 i num
+
+        for i in "$sel[@]"; do
+          if [[ "$i" = *\=* ]]; then
+  	    num="${i#*\=}"
+  	    [[ num -lt 0 ]] && num=0
+  	  else
+  	    num=0
+  	  fi
+  	  [[ num -lt min ]] && min="$num"
+  
+	  (( min )) || break
+        done
+
+        zmodload -i zsh/complist
+        SELECTMIN="$min"
+      fi
+    fi
+  fi
+elif [[ $compstate[nmatches] -eq 0 &&
+        $#_lastdescr -ne 0 && $compstate[old_list] != keep ]] &&
+     zstyle -s ":completion:${curcontext}:warnings" format format; then
+
+  compstate[list]='list force'
+  compstate[insert]=''
+
+  if [[ "$format" = *%d* ]]; then
+    local str mesg
+
+    _lastdescr=( "\`${(@)^_lastdescr:#}'" )
+
+    case $#_lastdescr in
+    1) str="$_lastdescr[1]";;
+    2) str="$_lastdescr[1] or $_lastdescr[2]";;
+    *) str="${(j:, :)_lastdescr[1,-2]}, or $_lastdescr[-1]";;
+    esac
+
+    zformat -f mesg "$format" "d:$str"
+    compadd -UX "$mesg" -n - ''
+  else
+    _setup warnings
+    compadd -UQX "$format" -V warnings - "${(@)_lastdescr:#}"
+  fi
 fi
+
+# Now call the post-functions.
+
+funcs=( "$comppostfuncs[@]" )
+comppostfuncs=()
+for func in "$funcs[@]"; do
+  "$func"
+done
+
+_lastcomp=( "${(@kv)compstate}" )
+_lastcomp[completer]="$_completer"
+_lastcomp[prefix]="$PREFIX"
+_lastcomp[suffix]="$SUFFIX"
+_lastcomp[iprefix]="$IPREFIX"
+_lastcomp[isuffix]="$ISUFFIX"
+_lastcomp[qiprefix]="$QIPREFIX"
+_lastcomp[qisuffix]="$QISUFFIX"
+_lastcomp[tags]="$_comp_tags"
+
+return ret
diff --git a/Completion/Core/_match b/Completion/Core/_match
index 3c639935c..18dab7423 100644
--- a/Completion/Core/_match
+++ b/Completion/Core/_match
@@ -1,53 +1,51 @@
 #autoload
 
 # This is intended to be used as a completer function after the normal
-# completer as in: `compconf completer=_complete:_match'.
+# completer as in: `zstyle ":completion:::::" completer _complete _match'.
 # It temporarily switches on pattern matching, allowing you to try 
 # completion on patterns without having to setopt glob_complete.
 #
 # Note, however, that this is only really useful if you don't use the
 # expand-or-complete function because otherwise the pattern will
 # be expanded using globbing.
-#
-# Configuration key used:
-#
-#  match_original
-#    If this is set to a `only', pattern matching will only be tried
-#    with the string from the line. If it is set to any other non-empty
-#    string, the original pattern will be tried first and if that yields
-#    no completions, matching will be tried again with a `*' inserted
-#    at the cursor position. If this key is not set or set to an empty
-#    string, matching will only be attempted with the `*' inserted.
 
-local tmp opm="$compstate[pattern_match]" ret=0
+[[ _matcher_num -gt 1 ]] && return 1
+
+local tmp opm="$compstate[pattern_match]" ret=0 orig ins
 
-# Do nothing if we don't have a pattern or there are still global
-# match specifications to try.
+# Do nothing if we don't have a pattern.
 
 tmp="${${:-$PREFIX$SUFFIX}#[~=]}"
-[[ "$tmp:q" = "$tmp" ||
-   compstate[matcher] -ne compstate[total_matchers] ]] && return 1
+[[ "$tmp:q" = "$tmp" ]] && return 1
+
+zstyle -s ":completion:${curcontext}:" match-original orig
+zstyle -b ":completion:${curcontext}:" insert-unambiguous ins
 
 # Try completion without inserting a `*'?
 
-if [[ -n "$compconfig[match_original]" ]]; then
-  compstate[matcher]=-1
+if [[ -n "$orig" ]]; then
   compstate[pattern_match]='-'
   _complete && ret=1
   compstate[pattern_match]="$opm"
-  compstate[matcher]="$compstate[total_matchers]"
 
-  (( ret )) && return 0
+  if (( ret )); then
+    [[ "$ins" = yes &&
+       $#compstate[unambiguous] -ge ${#:-${PREFIX}${SUFFIX}} ]] && 
+        compstate[pattern_insert]=unambiguous
+    return 0
+  fi
 fi
 
 # No completion with inserting `*'?
 
-[[ "$compconfig[match_original]" = only ]] && return 1
+[[ "$orig" = only ]] && return 1
 
-compstate[matcher]=-1
 compstate[pattern_match]='*'
 _complete && ret=1
 compstate[pattern_match]="$opm"
-compstate[matcher]="$compstate[total_matchers]"
+
+[[ ret -eq 1 && "$ins" = yes &&
+   $#compstate[unambiguous] -ge ${#:-${PREFIX}${SUFFIX}} ]] && 
+    compstate[pattern_insert]=unambiguous
 
 return 1-ret
diff --git a/Completion/Core/_menu b/Completion/Core/_menu
index 4cbda4e14..41fc178ba 100644
--- a/Completion/Core/_menu
+++ b/Completion/Core/_menu
@@ -1,10 +1,12 @@
 #autoload
 
+[[ _matcher_num -gt 1 ]] && return 1
+
 # This completer is an example showing how menucompletion can be
 # implemented with the new completion system.
 # Use this one before the normal _complete completer, as in:
 #
-#   compconf completer=_menu:_complete
+#   zstyle ":completion:::::" completer _menu _complete
 
 if [[ -n "$compstate[old_list]" ]]; then
 
diff --git a/Completion/Core/_next_label b/Completion/Core/_next_label
new file mode 100644
index 000000000..e309e53ea
--- /dev/null
+++ b/Completion/Core/_next_label
@@ -0,0 +1,24 @@
+#autoload
+
+local gopt=-J descr
+
+if [[ "$1" = -([12]|)[VJ] ]]; then
+  gopt="$1"
+  shift
+fi
+
+if comptags -A "$1" curtag; then
+  if [[ "$curtag" = *:* ]]; then
+    zformat -f descr "${curtag#*:}" "d:$3"
+    _description "$gopt" "${curtag%:*}" "$2" "$descr"
+    curtag="${curtag%:*}"
+    eval "${2}=( \${(P)2} \$argv[4,-1] )"
+  else
+    _description "$gopt" "$curtag" "$2" "$3"
+    eval "${2}=( \$argv[4,-1] \${(P)2} )"
+  fi
+
+  return 0
+fi
+
+return 1
diff --git a/Completion/Core/_oldlist b/Completion/Core/_oldlist
new file mode 100644
index 000000000..bcb3e148a
--- /dev/null
+++ b/Completion/Core/_oldlist
@@ -0,0 +1,53 @@
+#autoload
+
+[[ _matcher_num -gt 1 ]] && return 1
+
+local list
+
+zstyle -s ":completion:${curcontext}:" old-list list
+
+# If this is a listing widget and there is already an old list,
+# and either the style :oldlist:old-list is `always', or it is not `never'
+# and the list is not already shown, then use the existing list for listing
+# (even if it was generated by another widget).
+# Do this also if there is an old list and it was generated by the
+# completer named by the oldlist_list key.
+
+if [[ -n $compstate[old_list] && $list != never ]]; then
+  if [[ $WIDGET = *list* && ( $list = always || $list != shown ) ]]; then
+    compstate[old_list]=keep
+    return 0
+  elif [[ $list = *${_lastcomp[completer]}* ]]; then
+    [[ "$_lastcomp[insert]" = unambig* ]] && compstate[to_end]=single
+    compstate[old_list]=keep
+    if [[ -o automenu ]]; then
+      compstate[insert]=menu
+    else
+      compadd -Qs "$SUFFIX" - "$PREFIX"
+    fi
+    return 0
+  fi
+fi
+
+# If this is a completion widget, and we have a completion inserted already,
+# and the style :oldlist:old-menu is `true', then we cycle through the
+# existing list (even if it was generated by another widget).
+
+if [[ -z $compstate[old_insert] && -n $compstate[old_list] ]]; then
+  compstate[old_list]=keep
+elif [[ $WIDGET = *complete(|-prefix|-word) ]] &&
+     zstyle -t ":completion:${curcontext}:" old-menu; then
+  if [[ -n $compstate[old_insert] ]]; then
+    compstate[old_list]=keep
+    if [[ $WIDGET = *reverse* ]]; then
+      compstate[insert]=$(( compstate[old_insert] - 1 ))
+    else
+      compstate[insert]=$(( compstate[old_insert] + 1 ))
+    fi
+  else
+    return 1
+  fi
+  return 0
+fi
+
+return 1
diff --git a/Completion/Core/_path_files b/Completion/Core/_path_files
index 83b6e8a09..ac4614dd8 100644
--- a/Completion/Core/_path_files
+++ b/Completion/Core/_path_files
@@ -1,85 +1,64 @@
 #autoload
 
-# Utility function for in-path completion.
-# Supported arguments are: `-f', `-/', `-g <patterns>', `-J <group>',
-# `-V <group>', `-W paths', `-X explanation', and `-F <ignore>'. All but 
-# the last have the same syntax and meaning as for `complist'. The
-# `-F <ignore>' option may be used to give a list of suffixes either by
-# giving the name of an array or literally by giving them in a string
-# surrounded by parentheses. Files with one of the suffixes thus given
-# are treated like files with one of the suffixes in the `fignore' array
-# in normal completion.
-#
-# This function uses the helper functions `_match_test' and `_match_pattern'.
+# Utility function for in-path completion. This allows `/u/l/b<TAB>'
+# to complete to `/usr/local/bin'.
 
-# First see if we should generate matches for the global matcher in use.
+local linepath realpath donepath prepath testpath exppath skips skipped
+local tmp1 tmp2 tmp3 tmp4 i orig eorig pre suf tpre tsuf opre osuf cpre
+local pats haspats=no ignore pfxsfx rem remt sopt gopt opt
+local nm=$compstate[nmatches] menu matcher mopts atmp sort match
 
-_match_test _path_files || return
+typeset -U prepaths exppaths
 
-# Yes, so...
-
-local nm prepaths str linepath realpath donepath patstr prepath testpath rest
-local tmp1 collect tmp2 suffixes i ignore matchflags opt group sopt pats gopt
-local addpfx addsfx expl
-
-setopt localoptions nullglob rcexpandparam globdots extendedglob
+setopt localoptions nullglob rcexpandparam
 unsetopt markdirs globsubst shwordsplit nounset
 
-prepaths=('')
-ignore=()
-group=()
-sopt='-'
-gopt=''
-pats=()
-addpfx=()
-addsfx=()
-expl=()
+exppaths=()
 
 # Get the options.
 
-while getopts "P:S:W:F:J:V:X:f/g:" opt; do
-  case "$opt" in
-  P)     addpfx=(-P "$OPTARG")
-         ;;
-  S)     addsfx=(-S "$OPTARG")
-         ;;
-  W)     tmp1="$OPTARG"
-         if [[ "$tmp1[1]" = '(' ]]; then
-           prepaths=( ${^=tmp1[2,-2]}/ )
-         else
-           prepaths=( ${(P)=${tmp1}} )
-           (( ! $#prepaths )) && prepaths=( ${tmp1}/ )
-         fi
-         (( ! $#prepaths )) && prepaths=( '' )
-         ;;
-  F)     tmp1="$OPTARG"
-         if [[ "$tmp1[1]" = '(' ]]; then
-           ignore=( ${^=tmp1[2,-2]}/ )
-         else
-           ignore=( ${(P)${tmp1}} )
-         fi
-	 (( $#ignore )) && ignore=(-F "( $ignore )")
-         ;;
-  [JV])  group=("-$opt" "$OPTARG")
-         ;;
-  X)     expl=(-X "$OPTARG")
-         ;;
-  f)     sopt="${sopt}f"
-         pats=("$pats[@]" '*')
-	 ;;
-  /)     sopt="${sopt}/"
-         pats=("$pats[@]" '*(-/)')
-	 ;;
-  g)     gopt='-g'
-         pats=("$pats[@]" ${=OPTARG})
-	 ;;
-  esac
-done
+zparseopts -a mopts \
+    'P:=pfxsfx' 'S:=pfxsfx' 'q=pfxsfx' 'r:=pfxsfx' 'R:=pfxsfx' \
+    'W:=prepaths' 'F:=ignore' 'M+:=matcher' \
+    J+: V+: X+: 1: 2: n: 'f=tmp1' '/=tmp1' 'g+:-=tmp1'
+
+sopt="-${(@j::M)${(@)tmp1#-}#?}"
+(( $tmp1[(I)-[/g]*] )) && haspats=yes
+(( $tmp1[(I)-g*] )) && gopt=yes
+if (( $tmp1[(I)-/] )); then
+  pats=( '*(-/)' ${=${(M)tmp1:#-g*}#-g} )
+else
+  pats=( "${(@)=${(@M)tmp1:#-g*}#-g}" )
+fi
+pats=( "${(@)pats:# #}" )
+
+if (( $#prepaths )); then
+  tmp1="${prepaths[2]}"
+  if [[ "$tmp1[1]" = '(' ]]; then
+    prepaths=( ${^=tmp1[2,-2]%/}/ )
+  elif [[ "$tmp1[1]" = '/' ]]; then
+    prepaths=( "${tmp1%/}/" )
+  else
+    prepaths=( ${(P)^tmp1%/}/ )
+    (( ! $#prepaths )) && prepaths=( ${tmp1%/}/ )
+  fi
+  (( ! $#prepaths )) && prepaths=( '' )
+else
+  prepaths=( '' )
+fi
+
+if (( $#ignore )); then
+  if [[ "${ignore[2]}" = \(* ]]; then
+    ignore=( ${=ignore[2][2,-2]} )
+  else
+    ignore=( ${(P)ignore[2]} )
+  fi
+fi  
 
 # If we were given no file selection option, we behave as if we were given
 # a `-f'.
 
-if [[ "$sopt" = - ]]; then
+if [[ "$sopt" = -(f|) ]]; then
   if [[ -z "$gopt" ]]; then
     sopt='-f'
     pats=('*')
@@ -88,224 +67,472 @@ if [[ "$sopt" = - ]]; then
   fi
 fi
 
-# str holds the whole string from the command line with a `*' between
-# the prefix and the suffix.
-
-str="${PREFIX:q}*${SUFFIX:q}"
-
-# If the string began with a `~', the quoting turned this into `\~',
-# remove the slash.
+if (( ! $mopts[(I)-[JVX]] )); then
+  local expl
 
-[[ "$str" = \\\~* ]] && str="$str[2,-1]"
-
-# We will first try normal completion called with `complist', but only if we
-# weren't given a `-F' option.
-
-if (( ! $#ignore )); then
-  # First build an array containing the `-W' option, if there is any and we
-  # want to use it. We don't want to use it if the string from the command line
-  # is a absolute path or relative to the current directory.
-
-  if [[ -z "$tmp1[1]" || "$str[1]" = [~/] || "$str" = (.|..)/* ]]; then
-    tmp1=()
+  if [[ -z "$gopt" && "$sopt" = -/ ]]; then
+    _description directories expl directory
   else
-    tmp1=(-W "( $prepaths )")
+    _description files expl file
+  fi
+  tmp1=$expl[(I)-M*]
+  if (( tmp1 )); then
+    if (( $#matcher )); then
+      matcher[2]="$matcher[2] $expl[1+tmp1]"
+    else
+      matcher=(-M "$expl[1+tmp1]")
+    fi
   fi
+  mopts=( "$mopts[@]" "$expl[@]" )
+fi
 
-  # Now call complist.
+if zstyle -s ":completion:${curcontext}:files" sort tmp1; then
+  case "$tmp1" in
+  *size*)             sort=oL;;
+  *links*)            sort=ol;;
+  *(time|date|modi)*) sort=om;;
+  *access*)           sort=oa;;
+  *(inode|change)*)   sort=oc;;
+  *)                  sort=on;;
+  esac
+  [[ "$tmp1" = *rev* ]] && sort[1]=O
 
-  nm=$NMATCHES
-  if [[ -z "$gopt" ]]; then
-    complist "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" "$tmp1[@]" $sopt
+  if [[ "$sort" = on ]]; then
+    sort=''
   else
-    complist "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" "$tmp1[@]" $sopt -g "$pats"
+    mopts=( "${(@)mopts/#-J/-V}" )
+
+    tmp2=()
+    for tmp1 in "$pats[@]"; do
+      if [[ "$tmp1" = (#b)(?*)(\(\([^\|~]##\)\)) ]]; then
+        tmp2=( "$tmp2[@]" "${match[1]}((${sort}${match[2][3,-1]}" )
+      elif [[ "$tmp1" = (#b)(?*)(\([^\|~]##\)) ]]; then
+        tmp2=( "$tmp2[@]" "${match[1]}(${sort}${match[2][2,-1]}" )
+      else
+        tmp2=( "$tmp2[@]" "${tmp1}(${sort})" )
+      fi
+    done
+    pats=( "$tmp2[@]" )
   fi
+fi
+
+# Check if we have to skip over sequences of slashes. The value of $skips
+# is used below to match the pathname components we always have to accept
+# immediatly.
+
+if zstyle -t ":completion:${curcontext}:paths" squeeze-slashes; then
+  skips='((.|..|)/)##'
+else
+  skips='((.|..)/)##'
+fi
+
+# We get the prefix and the suffix from the line and save the whole
+# original string. Then we see if we will do menucompletion.
+
+pre="$PREFIX"
+suf="$SUFFIX"
+opre="$PREFIX"
+osuf="$SUFFIX"
+orig="${PREFIX}${SUFFIX}"
+eorig="$orig"
 
-  # If this generated any matches, we don't want to do in-path completion.
+[[ $compstate[insert] = (*menu|[0-9]*) || -n "$_comp_correct" ||
+   ( -n "$compstate[pattern_match]" &&
+     "${orig#\~}" != "${${orig#\~}:q}" ) ]] && menu=yes
 
-  [[ -nmatches nm ]] || return
+# If given no `-F' option, we may want to use $fignore, turned into patterns.
 
-  # No `-F' option, so we want to use `fignore'.
+[[ -z "$_comp_no_ignore" && $#ignore -eq 0 &&
+   ( -z $gopt || "$pats" = \ #\*\ # ) && -n $FIGNORE ]] && 
+    ignore=( "?*${^fignore[@]}" )
 
-  ignore=(-F fignore)
+if (( $#ignore )); then
+  _comp_ignore=( "$_comp_ignore[@]" "$ignore[@]" )
+  (( $mopts[(I)-F] )) || mopts=( "$mopts[@]" -F _comp_ignore )
 fi
 
+(( $#matcher )) && mopts=( "$mopts[@]" "$matcher[@]" )
+
 # Now let's have a closer look at the string to complete.
 
-if [[ "$str[1]" = \~ ]]; then
+if [[ "$pre[1]" = \~ ]]; then
   # It begins with `~', so remember anything before the first slash to be able
   # to report it to the completion code. Also get an expanded version of it
   # (in `realpath'), so that we can generate the matches. Then remove that
   # prefix from the string to complete, set `donepath' to build the correct
   # paths and make sure that the loop below is run only once with an empty
   # prefix path by setting `prepaths'.
-  
-  linepath="${str%%/*}/"
-  eval realpath\=$linepath
-  str="${str#*/}"
+
+  linepath="${pre[2,-1]%%/*}"
+  if [[ -z "$linepath" ]]; then
+    realpath="${HOME%/}/"
+  elif (( $+userdirs[$linepath] )); then
+    realpath="${userdirs[$linepath]%/}/"
+  elif (( $+nameddirs[$linepath] )); then
+    realpath="${nameddirs[$linepath]%/}/"
+  else
+    _message "unknown user \`$linepath'"
+    return 1
+  fi
+  linepath="~${linepath}/"
+  [[ "$realpath" = "$linepath" ]] && return 1
+  pre="${pre#*/}"
+  orig="${orig#*/}"
+  donepath=''
+  prepaths=( '' )
+elif [[ "$pre" = *\$*/* ]]; then
+
+  # If there is a parameter expansion in the word from the line, we try
+  # to complete the beast by expanding the prefix and completing anything
+  # after the first slash after the parameter expansion.
+  # This fails for things like `f/$foo/b/<TAB>' where the first `f' is
+  # meant as a partial path.
+
+  linepath="${(M)pre##*\$[^/]##/}"
+  realpath=${(e)~linepath}
+  [[ "$realpath" = "$linepath" ]] && return 1
+  pre="${pre#${linepath}}"
+  i="${#linepath//[^\\/]}"
+  orig="${orig[1,(in:i:)/][1,-2]}"
   donepath=''
   prepaths=( '' )
 else
   # If the string does not start with a `~' we don't remove a prefix from the
   # string.
 
-  liniepath=''
+  linepath=''
   realpath=''
 
-  if [[ "$str[1]" = / ]]; then
+  if [[ "$pre[1]" = / ]]; then
     # If it is a absolut path name, we remove the first slash and put it in
     # `donepath' meaning that we treat it as the path that was already handled.
     # Also, we don't use the paths from `-W'.
 
-    str="$str[2,-1]"
+    pre="$pre[2,-1]"
+    orig="$orig[2,-1]"
     donepath='/'
     prepaths=( '' )
   else
     # The common case, we just use the string as it is, unless it begins with
     # `./' or `../' in which case we don't use the paths from `-W'.
     
-    [[ "$str" = (.|..)/* ]] && prepaths=( '' )
+    [[ "$pre" = (.|..)/* ]] && prepaths=( '' )
     donepath=''
   fi
 fi
 
-# First we skip over all pathname components in `str' which really exist in
-# the file-system, so that `/usr/lib/l<TAB>' doesn't offer you `lib' and
-# `lib5'. Pathname components skipped this way are taken from `str' and added
-# to `donepath'.
+# Now we generate the matches. First we loop over all prefix paths given
+# with the `-W' option.
 
-while [[ "$str" = */* ]] do
-  [[ -e "$realpath$donepath${str%%/*}" ]] || break
-  donepath="$donepath${str%%/*}/"
-  str="${str#*/}"
-done
+for prepath in "$prepaths[@]"; do
 
-# Now build the glob pattern by calling `_match_pattern'.
-patstr="$str"
-matchflags=""
-_match_pattern _path_files patstr matchflags
+  # Get local copies of the prefix, suffix, and the prefix path to use
+  # in the following loop, which walks through the pathname components
+  # in the string from the line.
 
-# We almost expect the pattern to have changed `..' into `*.*.', `/.' into
-# `/*.', and probably to contain two or more consecutive `*'s. Since these
-# have special meaning for globbing, we remove them. But before that, we
-# add the pattern for matching any characters before a slash.
+  tpre="$pre"
+  tsuf="$suf"
+  testpath="$donepath"
 
-patstr="$patstr:gs-/-*/-:gs/*.*.//:gs-/*.-/.-:gs/**/*/"
+  tmp2="${(M)tpre##${~skips}}"
+  tpre="${tpre#$tmp2}"
 
-# Finally, generate the matches. First we loop over all the paths from `-W'.
-# Note that in this loop `str' is used as a modifyable version of `patstr'
-# and `testpath' is a modifyable version of `donepath'.
+  tmp1=( "$prepath$realpath$donepath$tmp2" )
 
-for prepath in "$prepaths[@]"; do
-  str="$patstr"
-  testpath="$donepath"
+  while true; do
 
-  # The second loop tests the components of the path in `str' to get the
-  # possible matches.
+    # Get the prefix and suffix for matching.
 
-  while [[ "$str" = */* ]] do
-    # `rest' is the pathname after the first slash that is left. In `tmp1'
-    # we get the globbing matches for the pathname component currently
-    # handled.
+    if [[ "$tpre" = */* ]]; then
+      PREFIX="${tpre%%/*}"
+      SUFFIX=""
+    else
+      PREFIX="${tpre}"
+      SUFFIX="${tsuf%%/*}"
+    fi
 
-    rest="${str#*/}"
-    tmp1="${prepath}${realpath}${testpath}${~matchflags}${str%%/*}(-/)"
-    tmp1=( $~tmp1 )
+    # Get the matching files by globbing.
 
-    if [[ $#tmp1 -eq 0 ]]; then
-      # If this didn't produce any matches, we don't need to test this path
-      # any further, so continue with the next `-W' path, if any.
+    tmp2=( "$tmp1[@]" )
+    if [[ "$tpre$tsuf" = */* ]]; then
+      if [[ ! -o globdots && "$PREFIX" = .* ]]; then
+        tmp1=( ${^tmp1}${skipped}*(-/) ${^tmp1}${skipped}.*(-/) )
+      else
+        tmp1=( ${^tmp1}${skipped}*(-/) )
+      fi
+      if [[ -o globdots || "$PREFIX" = .* ]] &&
+         zstyle -s ":completion:${curcontext}:paths" special-dirs atmp; then
+	if [[ "$atmp" = (yes|true|1|on) ]]; then
+	  tmp1=( "$tmp1[@]" . .. )
+	elif [[ "$atmp" = .. ]]; then
+	  tmp1=( "$tmp1[@]" .. )
+        fi
+      fi
+    else
+      if [[ ! -o globdots && "$PREFIX" = .* ]]; then
+        tmp1=( ${^tmp1}${skipped}${^~pats} ${^tmp1}${skipped}.${^~pats:#.*} )
+      else
+        tmp1=( ${^tmp1}${skipped}${^~pats} )
+      fi
+      if [[ "$sopt" = *[/f]* && ( -o globdots || "$PREFIX" = .* ) ]] &&
+	  zstyle -s ":completion:${curcontext}:paths" special-dirs atmp; then
+	if [[ "$atmp" = (yes|true|1|on) ]]; then
+	  tmp1=( "$tmp1[@]" . .. )
+	elif [[ "$atmp" = .. ]]; then
+	  tmp1=( "$tmp1[@]" .. )
+        fi
+      fi
+    fi
 
-      continue 2
-    elif [[ $#tmp1 -gt 1 ]]; then
-      # If it produced more than one match, we want to remove those which
-      # don't have possible following pathname components matching the 
-      # rest of the string we are completing. (The case with only one
-      # match is handled below.)
-      # In `collect' we will collect those of the produced pathnames that
-      # have a matching possible path-suffix. In `suffixes' we build an
-      # array containing strings build from the rest of the string to 
-      # complete and the glob patterns we were given as arguments.
-
-      collect=()
-      suffixes=( $rest$^pats )
-      suffixes=( "${(@)suffixes:gs.**.*.}" )
-
-      # In the loop the prefixes from the `tmp1' array produced above and
-      # the suffixes we just built are used to produce possible matches
-      # via globbing.
-
-      for i in $tmp1; do
-        tmp2=( ${~i}/${~matchflags}${~suffixes} )
-        [[ $#tmp2 -ne 0 ]] && collect=( $collect $i )
-      done
-
-      # If this test showed that none of the matches from the glob in `tmp1'
-      # has a possible sub-path matching what's on the line, we give up and
-      # continue with the next `-W' path.
-
-      if [[ $#collect -eq 0 ]]; then
+    if [[ -n "$PREFIX$SUFFIX" ]]; then
+      # See which of them match what's on the line.
+
+      if [[ -n "$_comp_correct" ]]; then
+        tmp2=( "$tmp1[@]" )
+        builtin compadd -D tmp1 -F _comp_ignore "$matcher[@]" - "${(@)tmp1:t}"
+
+        if [[ $#tmp1 -eq 0 ]]; then
+          tmp1=( "$tmp2[@]" )
+	  compadd -D tmp1 -F _comp_ignore "$matcher[@]" - "${(@)tmp2:t}"
+        fi
+      else
+        [[ "$tmp1[1]" = */* ]] && tmp2=( "$tmp1[@]" )
+
+        builtin compadd -D tmp1 -F _comp_ignore "$matcher[@]" - "${(@)tmp1:t}"
+      fi
+
+      # If no file matches, save the expanded path and continue with
+      # the outer loop.
+
+      if (( ! $#tmp1 )); then
+ 	if [[ "$tmp2[1]" = */* ]]; then
+	  tmp2=( "${(@)tmp2#${prepath}${realpath}}" )
+	  if [[ "$tmp2[1]" = */* ]]; then
+	    tmp2=( "${(@)tmp2:h}" )
+	    compquote tmp2
+	    if [[ "$tmp2" = */ ]]; then
+	      exppaths=( "$exppaths[@]" ${^tmp2}${tpre}${tsuf} )
+	    else
+	      exppaths=( "$exppaths[@]" ${^tmp2}/${tpre}${tsuf} )
+	    fi
+          else
+	    exppaths=( "$exppaths[@]" ${tpre}${tsuf} )
+	  fi
+        fi
         continue 2
-      elif [[ $#collect -ne 1 ]]; then
-        # If we have more than one possible match, this means that the
-	# pathname component currently handled is ambiguous, so we give
-	# it to the completion code.
-	# First we build the full path prefix in `tmp1'.
+      fi
+    elif (( ! $#tmp1 )); then
+      # A little extra hack: if we were completing `foo/<TAB>' and `foo'
+      # contains no files, this will normally produce no matches and other
+      # completers might think that's it's their time now. But if the next
+      # completer is _correct or something like that, this will result in
+      # an attempt to correct a valid directory name. So we just add the
+      # original string in such a case so that the command line doesn't 
+      # change but other completers still think there are matches.
+      # We do this only if we weren't given a `-g' or `-/' option because
+      # otherwise this would keep `_files' from completing all filenames
+      # if none of the patterns match.
+
+      if [[ -z "$tpre$tsuf" && -n "$pre$suf" ]]; then
+	pfxsfx=(-S '' "$pfxsfx[@]")
+	### Don't remember what the break was good for. We explicitly
+	### execute this only when there are no matches in the directory,
+	### so why continue?
+	###
+        ### tmp1=( "$tmp2[@]" )
+	### break
+      elif [[ "$haspats" = no && -z "$tpre$tsuf" &&
+	"$pre" = */ && -z "$suf" ]]; then
+	PREFIX="${opre}"
+	SUFFIX="${osuf}"
+        compadd -nQS '' - "$linepath$donepath$orig"
+        tmp4=-
+      fi
+      continue 2
+    fi
 
-        tmp1="$prepath$realpath$testpath"
+    if [[ -z "$_comp_no_ignore" && "$tpre$tsuf" != */* && $#tmp1 -ne 0 ]] &&
+       zstyle -s ":completion:${curcontext}:files" ignore-parents rem &&
+       [[ ( "$rem" != *dir* || "$pats" = '*(-/)' ) &&
+	  ( "$rem" != *..* || "$tmp1" = *../* ) ]]; then
+      if [[ "$rem" = *parent* ]]; then
+	for i in ${(M)^tmp1:#*/*}(-/); do
+	  remt="${${i#$prepath$realpath$donepath}%/*}"
+	  while [[ "$remt" = */* &&
+	           ! "$prepath$realpath$donepath$remt" -ef "$i" ]]; do
+	    remt="${remt%/*}"
+	  done
+	  [[ "$remt" = */* || "$remt" -ef "$i" ]] &&
+	      _comp_ignore=( "$_comp_ignore[@]" "${(q)i}" )
+	done
+      fi
+      if [[ "$rem" = *pwd* ]]; then
+        for i in ${^tmp1}(-/); do
+	  [[ "$i" -ef "$PWD" ]] && _comp_ignore=( "$_comp_ignore[@]" "${(q)i}" )
+	done
+      fi
+      (( $#_comp_ignore && $mopts[(I)-F] )) || mopts=( "$mopts[@]" -F _comp_ignore )
+    fi
 
-	# Now produce all matching pathnames in `collect'.
+    # Step over to the next component, if any.
 
-        collect=( ${~collect}/${~matchflags}${~suffixes} )
+    if [[ "$tpre" = */* ]]; then
+      tpre="${tpre#*/}"
+    elif [[ "$tsuf" = */* ]]; then
+      tpre="${tsuf#*/}"
+      tsuf=""
+    else
+      break
+    fi
 
-	# And then remove the common path prefix from all these matches.
+    # There are more components, so skip over the next components and make a
+    # slash be added.
 
-        collect=( ${collect#$tmp1} )
+    tmp2="${(M)tpre##((.|..|)/)##}"
+    if [[ -n "$tmp2" ]]; then
+      skipped="/$tmp2"
+      tpre="${tpre#$tmp2}"
+    else
+      skipped=/
+    fi
+  done
+
+  # The next loop searches the first ambiguous component.
+
+  tmp3="$pre$suf"
+  tpre="$pre"
+  tsuf="$suf"
+  tmp1=( "${(@)tmp1#${prepath}${realpath}${testpath}}" )
 
-	# Finally, we add all these matches with the common (unexpanded)
-	# pathprefix (the `-p' option), the path-prefix (the `-W' option)
-	# to allow the completion code to test file type, and the path-
-	# suffix (the `-s' option). We also tell the completion code that
-	# these are file names and that `fignore' should be used as usual
-	# (the `-f' and `-F' options).
+  while true; do
 
-        for i in $collect; do
-          compadd "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" -p "$linepath$testpath" -W "$tmp1" -s "/${i#*/}" -f "$ignore[@]" - "${i%%/*}"
-        done
+    # First we check if some of the files match the original string
+    # for this component. If there are some we remove all other
+    # names. This avoids having `foo' complete to `foo' and `foobar'.
 
-	# We have just finished handling all the matches from above, so we
-	# can continue with the next `-W' path.
+    if [[ "$tmp3" = */* ]]; then
+      tmp4=( "${(@M)tmp1:#${tmp3%%/*}/*}" )
+      (( $#tmp4 )) && tmp1=( "$tmp4[@]" )
+    fi
+
+    # Next we see if this component is ambiguous.
 
-	continue 2
+    if [[ "$tmp3" = */* ]]; then
+       tmp4=$tmp1[(I)^${(q)tmp1[1]%%/*}/*]
+    else
+       tmp4=$tmp1[(I)^${(q)tmp1[1]}]
+    fi
+
+    if [[ "$tpre" = */* ]]; then
+      tmp2="${cpre}${tpre%%/*}"
+      PREFIX="${donepath}${linepath}${tmp2}"
+      SUFFIX="/${tpre#*/}${tsuf#*/}"
+    else
+      tmp2="${cpre}${tpre}"
+      PREFIX="${donepath}${linepath}${tmp2}"
+      SUFFIX="${tsuf}"
+    fi
+
+    if (( tmp4 )) ||
+       [[ -n "$compstate[pattern_match]" && "$tmp2" != "${(q)tmp2}" ]]; then
+      # It is. For menucompletion we now add the possible completions
+      # for this component with the unambigous prefix we have built
+      # and the rest of the string from the line as the suffix.
+      # For normal completion we add the rests of the filenames
+      # collected as the suffixes to make the completion code expand
+      # it as far as possible.
+
+      tmp2="$testpath"
+      compquote tmp1 tmp2
+
+      if [[ -n $menu || -z "$compstate[insert]" ]] ||
+         ! zstyle -t ":completion:${curcontext}:paths" expand suffix; then
+        (( tmp4 )) && zstyle -t ":completion:${curcontext}:paths" cursor &&
+            compstate[to_end]=''
+        if [[ "$tmp3" = */* ]]; then
+	  compadd -Qf "$mopts[@]" -p "$linepath$tmp2" -s "/${tmp3#*/}" \
+	          -W "$prepath$realpath$testpath" \
+		  "$pfxsfx[@]" -M "r:|/=* r:|=*" \
+		  - "${(@)tmp1%%/*}"
+	else
+	  compadd -Qf "$mopts[@]" -p "$linepath$tmp2" \
+	          -W "$prepath$realpath$testpath" \
+		   "$pfxsfx[@]" -M "r:|/=* r:|=*" \
+		   - "$tmp1[@]"
+	fi
+      else
+        if [[ "$tmp3" = */* ]]; then
+	  atmp=( -Qf "$mopts[@]" -p "$linepath$tmp2"
+	         -W "$prepath$realpath$testpath"
+	         "$pfxsfx[@]" -M "r:|/=* r:|=*" )
+          for i in "$tmp1[@]"; do
+	    compadd "$atmp[@]" -s "/${i#*/}" - "${i%%/*}"
+	  done
+        else
+	  compadd -Qf "$mopts[@]" -p "$linepath$tmp2" \
+                  -W "$prepath$realpath$testpath" \
+		  "$pfxsfx[@]" -M "r:|/=* r:|=*" \
+		  - "$tmp1[@]"
+        fi
       fi
-      # We reach this point if only one of the path prefixes in `tmp1'
-      # has a existing path-suffix matching the string from the line.
-      # In this case we accept this match and continue with the next
-      # path-name component.
+      tmp4=-
+      break
+    fi
+
+    # If we have checked all components, we stop now and add the 
+    # strings collected after the loop.
 
-      tmp1=( "$collect[1]" )
+    if [[ "$tmp3" != */* ]]; then
+      tmp4=""
+      break
     fi
-    # This is also reached if the first globbing produced only one match
-    # in this case we just continue with the next pathname component, too.
 
-    tmp1="$tmp1[1]"
-    testpath="$testpath${tmp1##*/}/"
-    str="$rest"
+    # Otherwise we add the unambiguous component to `testpath' and
+    # take it from the filenames.
+
+    testpath="${testpath}${tmp1[1]%%/*}/"
+    tmp1=( "${(@)tmp1#*/}" )
+
+    tmp3="${tmp3#*/}"
+
+    if [[ "$tpre" = */* ]]; then
+      cpre="${cpre}${tpre%%/*}/"
+      tpre="${tpre#*/}"
+    elif [[ "$tsuf" = */* ]]; then
+      cpre="${cpre}${tpre}/"
+      tpre="${tsuf#*/}"
+      tsuf=""
+    else
+      tpre=""
+      tsuf=""
+    fi
   done
 
-  # We are here if all pathname components except the last one (which is still
-  # not tested) are unambiguous. So we add matches with the full path prefix, 
-  # no path suffix, the `-W' we are currently handling, all the matches we
-  # can produce in this directory, if any.
-
-  tmp1="$prepath$realpath$testpath"
-  suffixes=( $str$^pats )
-  suffixes=( "${(@)suffixes:gs.**.*.}" )
-  tmp2=( ${~tmp1}${~matchflags}${~suffixes} )
-  if [[ $#tmp2 -eq 0 && "$sopt" = */* ]]; then
-    [[ "$testpath[-1]" = / ]] && testpath="$testpath[1,-2]"
-    compadd "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" -f - "$linepath$testpath"
-  else
-    compadd "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" -p "$linepath$testpath" -W "$prepath$realpath$testpath" -f "$ignore[@]" - ${(@)tmp2#$tmp1}
+  if [[ -z "$tmp4" ]]; then
+    if [[ "$osuf" = */* ]]; then
+      PREFIX="${opre}${osuf}"
+      SUFFIX=""
+    else
+      PREFIX="${opre}"
+      SUFFIX="${osuf}"
+    fi
+    tmp4="$testpath"
+    compquote tmp4 tmp1
+    compadd -Qf "$mopts[@]" -p "$linepath$tmp4" -W "$prepath$realpath$testpath" \
+	    "$pfxsfx[@]" -M "r:|/=* r:|=*" - "$tmp1[@]"
   fi
 done
+
+# If we are configured to expand paths as far as possible and we collected
+# expanded paths that are different from the string on the line, we add
+# them as possible matches.
+
+if zstyle -t ":completion:${curcontext}:paths" expand prefix &&
+   [[ nm -eq compstate[nmatches] && $#exppaths -ne 0 &&
+      "$exppaths" != "$eorig" ]]; then
+  PREFIX="${opre}"
+  SUFFIX="${osuf}"
+  compadd -Q "$mopts[@]" -S '' -M "r:|/=* r:|=*" -p "$linepath" - "$exppaths[@]"
+fi
+
+[[ nm -ne compstate[nmatches] ]]
diff --git a/Completion/Core/_prefix b/Completion/Core/_prefix
index 6306b4aa0..f6e3b0831 100644
--- a/Completion/Core/_prefix
+++ b/Completion/Core/_prefix
@@ -4,10 +4,10 @@
 
 [[ -n "$SUFFIX" ]] || return 1
 
-local curcontext="${curcontext/:[^:]#:/:prefix:}" comp i
+local comp i
 
 zstyle -a ":completion:${curcontext}:" completer comp ||
-  comp=( "${(@)_completers[1,-${#_completers_left}-1][(R)_prefix,-1]}" )
+  comp=( "${(@)_completers[1,_completer_num-1][(R)_prefix(|:*),-1]}" )
 
 if zstyle -t ":completion:${curcontext}:" add-space; then
   ISUFFIX=" $SUFFIX"
diff --git a/Completion/Core/_requested b/Completion/Core/_requested
index 082c45820..bd838a28e 100644
--- a/Completion/Core/_requested
+++ b/Completion/Core/_requested
@@ -1,9 +1,20 @@
 #autoload
 
-local tag tname="$funcstack[2,-1]"
+local gopt=-J
 
-for tag; do
-  [[ "${_cur_tags[${tname}]}" = *:${tag}(:|\[*\]:)* ]] && return 0
-done
+if [[ "$1" = -([12]|)[VJ] ]]; then
+  gopt="$1"
+  shift
+fi
 
-return 1
+if comptags -R "$1"; then
+  _comp_tags="$_comp_tags $1"
+  if [[ $# -gt 3 ]]; then
+    _all_labels "$gopt" "$@"
+  elif [[ $# -gt 1 ]]; then
+    _description "$gopt" "$@"
+  fi
+  return 0
+else
+  return 1
+fi
diff --git a/Completion/Core/_setup b/Completion/Core/_setup
index f12c34b34..ed7307e69 100644
--- a/Completion/Core/_setup
+++ b/Completion/Core/_setup
@@ -1,13 +1,61 @@
 #autoload
 
-local colors i
-
-for i; do
-  if _style -a "$i" list-colors colors; then
-    if [[ "$1" = default ]]; then
-      ZLS_COLORS="${(j.:.)${(@)colors:gs/:/\\\:}}"
-    else
-      eval "ZLS_COLORS=\"(${i})\${(j.:(${i}).)\${(@)colors:gs/:/\\\:}}:\${ZLS_COLORS}\""
-    fi
+local val nm="$compstate[nmatches]"
+
+if zstyle -a ":completion:${curcontext}:$1" list-colors val; then
+  zmodload -i zsh/complist
+  if [[ "$1" = default ]]; then
+    ZLS_COLORS="${(j.:.)${(@)val:gs/:/\\\:}}"
+  else
+    eval "ZLS_COLORS=\"(${1})\${(j.:(${1}).)\${(@)val:gs/:/\\\:}}:\${ZLS_COLORS}\""
   fi
-done
+
+# Here is the problem mentioned in _main_complete.
+
+# elif [[ "$1" = default && -n "$ZLS_COLORS$ZLS_COLOURS" ]]; then
+#   zmodload -i zsh/complist
+#   ZLS_COLORS="$ZLS_COLORS$ZLS_COLOURS"
+
+fi
+
+if zstyle -t ":completion:${curcontext}:$1" list-packed; then
+  compstate[list]="${compstate[list]} packed"
+elif [[ $? -eq 1 ]]; then
+  compstate[list]="${compstate[list]:gs/packed//}"
+else
+  compstate[list]="$_saved_list"
+fi
+
+if zstyle -t ":completion:${curcontext}:$1" list-rows-first; then
+  compstate[list]="${compstate[list]} rows"
+elif [[ $? -eq 1 ]]; then
+  compstate[list]="${compstate[list]:gs/rows//}"
+else
+  compstate[list]="$_saved_list"
+fi
+
+if zstyle -t ":completion:${curcontext}:$1" last-prompt; then
+  compstate[last_prompt]=yes
+elif [[ $? -eq 1 ]]; then
+  compstate[last_prompt]=''
+else
+  compstate[last_prompt]="$_saved_lastprompt"
+fi
+
+if zstyle -t ":completion:${curcontext}:$1" accept-exact; then
+  compstate[exact]=accept
+elif [[ $? -eq 1 ]]; then
+  compstate[exact]=''
+else
+  compstate[exact]="$_saved_exact"
+fi
+
+[[ _last_nmatches -ge 0 && _last_nmatches -ne nm ]] &&
+    _menu_style=( "$_last_menu_style[@]" "$_menu_style[@]" )
+
+if zstyle -a ":completion:${curcontext}:$1" menu val; then
+  _last_nmatches=$nm
+  _last_menu_style=( "$val[@]" )
+else
+  _last_nmatches=-1
+fi
diff --git a/Completion/Core/_tags b/Completion/Core/_tags
index af8dc21dd..496f5b7e0 100644
--- a/Completion/Core/_tags
+++ b/Completion/Core/_tags
@@ -1,81 +1,83 @@
 #autoload
 
-if (( $# )); then
-  local cmd="$words[1]" func="$funcstack[2]" defs i tags tag pat style prio
-
-  while getopts 'c:f:' i; do
-    if [[ "$i" = c ]]; then
-      cmd="$OPTARG"
-    else
-      func="$OPTARG"
-    fi
-  done
-
-  shift OPTIND-1
-
-  defs=( "${(@M)argv:#${(kj:|:)~override_tags[(R)(|+*)]}}" )
-  (( $#defs )) && set -- "$defs[@]"
-
-  _offered_tags=( "$_offered_tags[@]" "$@" )
-  _last_tags=()
-
-  defs=()
-  for i; do
-    if [[ -n ${override_tags[$i]} && ${override_tags[$i]} != (\[|+\[)* ]]; then
-      if [[ ${override_tags[$i]} = *\[* ]]; then
-        prio=( "${i}:*=${override_tags[$i]#+}" )
-      else
-        prio=( "${i}:${(@v)^comptags[(I)(|*:)${i}(|:*)]}" )
-        (( $#prio )) || prio=( "${i}:${comptags[any]}" )
-        prio="${${${prio[(r)(|*:)\*=[^:]#\[*\](|:*)]}##(|*:)\*}%%:*}"
-        prio=( "${i}:*=${override_tags[$i]#+}${(M)prio%%\[*\]}" )
-      fi
-    else
-      prio=( "${i}:${(@v)^comptags[(I)(|*:)${i}(|:*)]}" )
-      (( $#prio )) || prio=( "${i}:${comptags[any]}" )
-    fi
-    defs=( "$defs[@]" "$prio[@]" )
-  done
-
-  tags=()
-  for i in "$defs[@]"; do
-    tag="${i%%:*}"
-    for pat in "${(s.:.)i#*:}"; do
-      if [[ ( "$pat" = _* && "$func" = ${~pat%%\=*} ) ||
-            "$cmd" = ${~pat%%\=*} ]]; then
-        prio="${pat#*\=}"
-	[[ "$prio" = -* ]] && continue 2
-
-	if [[ "$prio" = *\[*\] ]]; then
-	  style="${(M)prio%%\[*}"
-	  prio="${prio%%\[*}"
-        else
-	  style=''
-        fi
-	[[ ${override_tags[$tag]} = (|+)\[* ]] &&
-	    style="${override_tags[$tag]#+}"
-
-	(( prio++ ))
-
-        tags[$prio]="${tags[$prio]}:${tag}${style}"
-        break
-      fi
-    done
-  done
+local prev
 
-  prios=( "${(@)tags:#}" )
+# A `--' as the first argument says that we should tell comptags to use
+# the preceding function nesting level. This is only documented here because
+# if everythings goes well, users won't have to worry about it and should
+# not mess with it.
 
-  return 0
+if [[ "$1" = -- ]]; then
+  prev=-
+  shift
 fi
 
-_failed_tags=( "$_failed_tags[@]" "$_last_tags[@]" )
+if (( $# )); then
+
+  # We have arguments: the tags supported in this context.
+
+  local curcontext="$curcontext" order tag nodef tmp
+
+  if [[ "$1" = -C?* ]]; then
+    curcontext="${curcontext%:*}:${1[3,-1]}"
+    shift
+  elif [[ "$1" = -C ]]; then
+    curcontext="${curcontext%:*}:${2}"
+    shift 2
+  else
+    targs=()
+  fi
+
+  [[ "$1" = -(|-) ]] && shift
 
-(( $#prios )) || return 1
+  if zstyle -a ":completion:${curcontext}:" group-order order; then
+    local name
 
-tags="${prios[1]}:"
-shift 1 prios
+    for name in "$order[@]"; do
+      compadd -J "$name"
+      compadd -V "$name"
+      compadd -J "$name" -1
+      compadd -V "$name" -1
+      compadd -J "$name" -2
+      compadd -V "$name" -2
+    done
+  fi
+
+  # Set and remember offered tags.
+
+  comptags "-i$prev" "$curcontext" "$@"
+
+  # Sort the tags.
+
+  if [[ -n "$_sort_tags" ]]; then
+    "$_sort_tags" "$@"
+  else
+    zstyle -a ":completion:${curcontext}:" tag-order order ||
+        order=('arguments values' options)
+
+    for tag in $order; do
+      case $tag in
+      -)     nodef=yes;;
+      *\(\)) if ! "${${tag%%[ 	]#\(\)}##[ 	]#}" "$@"; then
+               nodef=yes
+               break
+             fi
+             ;;
+      \!*)   comptry "${(@)argv:#(${(j:|:)~${=~tag[2,-1]}})}";;
+      ?*)    comptry -m "$tag";;
+      esac
+    done
+
+    [[ -z "$nodef" ]] && comptry "$@"
+  fi
+
+  # Return non-zero if at least one set of tags should be used.
+
+  comptags "-T$prev"
+
+  return
+fi
 
-_last_tags=( "${(@s.:.)${${tags#:}%:}}" )
-_tried_tags=( "$_tried_tags[@]" "$_last_tags[@]" )
+# The other mode: switch to the next set of tags.
 
-return 0
+comptags "-N$prev"
diff --git a/Completion/Core/_wanted b/Completion/Core/_wanted
index 7baa3e724..32875ec57 100644
--- a/Completion/Core/_wanted
+++ b/Completion/Core/_wanted
@@ -1,6 +1,6 @@
 #autoload
 
-local targs
+local targs gopt=-J
 
 if [[ "$1" = -C?* ]]; then
   targs=( -C "${1[3,-1]}" )
@@ -12,10 +12,22 @@ else
   targs=()
 fi
 
-[[ "$1" = -(|-) ]] && shift
+if [[ "$1" = -([12]|)[VJ] ]]; then
+  gopt="$1"
+  shift
+fi
+
+if [[ $# -gt 3 ]]; then
+  if _tags "$targs[@]" "$1"; then
+    _comp_tags="$_comp_tags $1"
 
-if [[ $# -gt 1 ]]; then
-  _tags "$targs[@]" "$1" && _description "${(@)argv[2,-1]}"
+    _all_labels -t "$gopt" "$@"
+  else
+    return 1
+  fi
+elif [[ $# -gt 1 ]]; then
+  _tags -- "$targs[@]" "$1" && _comp_tags="$_comp_tags $1" &&
+    _description "$gopt" "$@"
 else
-  _tags "$targs[@]" "$1"
+  _tags -- "$targs[@]" "$1" && _comp_tags="$_comp_tags $1"
 fi
diff --git a/Completion/Core/compdump b/Completion/Core/compdump
index 8be096f50..3cccbd06e 100644
--- a/Completion/Core/compdump
+++ b/Completion/Core/compdump
@@ -1,4 +1,4 @@
-# This is a file to be sourced to dump the definitions for new-style
+# This is a function to dump the definitions for new-style
 # completion defined by 'compinit' in the same directory.  The output
 # should be directed into the "compinit.dump" in the same directory as
 # compinit. If you rename init, just stick .dump onto the end of whatever
@@ -9,33 +9,46 @@
 # To do this, simply remove the .dump file, start a new shell, and
 # create the .dump file as before.  Again, compinit -d handles this
 # automatically.
-#
-# It relies on KSH_ARRAYS not being set.
 
 # Print the number of files used for completion. This is used in compinit
 # to see if auto-dump should re-dump the dump-file.
 
-_d_file=${COMPDUMP-${0:h}/compinit.dump}
+emulate -L zsh
+setopt extendedglob
+
+typeset _d_file _d_f _d_bks _d_line _d_als
+
+_d_file=${_comp_dumpfile-${0:h}/compinit.dump}.$HOST.$$
 
 typeset -U _d_files
-_d_files=( ${^~fpath}/_*~*~(N:t) )
+_d_files=( ${^~fpath:/.}/^([^_]*|*~|*.zwc)(N:t) )
 
 print "#files: $#_d_files" > $_d_file
 
-unset _d_files
-
 # First dump the arrays _comps and _patcomps.  The quoting hieroglyphyics
 # ensure that a single quote inside a variable is itself correctly quoted.
 
 print "_comps=(" >> $_d_file
 for _d_f in ${(ok)_comps}; do
-    print -r - "'${_d_f//\'/'\\''}'" "'${_comps[$_d_f]//\'/'\\''}'"
+    print -r - "${(q)_d_f}" "${(q)_comps[$_d_f]}"
 done  >> $_d_file
 print ")" >> $_d_file
 
 print "\n_patcomps=(" >> $_d_file
-for _d_f in "$_patcomps[@]"; do
-  print -r - "'${_d_f//\'/'\\''}'"
+for _d_f in "${(ok@)_patcomps}"; do
+  print -r - "${(q)_d_f}" "${(q)_patcomps[$_d_f]}"
+done >> $_d_file
+print ")" >> $_d_file
+
+print "\n_postpatcomps=(" >> $_d_file
+for _d_f in "${(ok@)_postpatcomps}"; do
+  print -r - "${(q)_d_f}" "${(q)_postpatcomps[$_d_f]}"
+done >> $_d_file
+print ")" >> $_d_file
+
+print "\n_compautos=(" >> $_d_file
+for _d_f in "${(ok@)_compautos}"; do
+  print -r - "${(q)_d_f}" "${(q)_compautos[$_d_f]}"
 done >> $_d_file
 print ")" >> $_d_file
 
@@ -44,11 +57,13 @@ print >> $_d_file
 # Now dump the key bindings. We dump all bindings for zle widgets
 # whose names start with a underscore.
 # We need both the zle -C's and the bindkey's to recreate.
+# We can ignore any zle -C which rebinds a standard widget (second
+# argument to zle does not begin with a `_').
 
 _d_bks=()
 zle -lL |
   while read -rA _d_line; do
-    if [[ ${_d_line[5]} = _* ]]; then
+    if [[ ${_d_line[3]} = _* && ${_d_line[5]} = _* ]]; then
       print -r - ${_d_line}
       _d_bks=($_d_bks ${_d_line[3]})
     fi
@@ -73,17 +88,26 @@ done))
 
 # print them out:  about five to a line looks neat
 
+_i=5
+print -n autoload -U >> $_d_file
 while (( $#_d_als )); do
-  print -n autoload
-  for (( _i = 0; _i < 5; _i++ )); do
-    if (( $#_d_als )); then
-      print -n " $_d_als[1]"
-      shift _d_als
+  if (( ! $+_compautos[$_d_als[1]] )); then
+    print -n " $_d_als[1]"
+    if (( _i-- && $#_d_als > 1 )); then
+      _i=5
+      print -n '\nautoload -U'
     fi
-  done
-  print
+  fi
+  shift _d_als
 done >> $_d_file
 
 print >> $_d_file
 
-unset _d_line _d_zle _d_bks _d_als _d_f _f_file
+for _i in "${(ok@)_compautos}"; do
+  print "autoload -U $_compautos[$_i] $_i" >> $_d_file
+done
+
+mv $_d_file ${_d_file%.$HOST.$$}
+
+unfunction compdump
+autoload -U compdump
diff --git a/Completion/Core/compinit b/Completion/Core/compinit
index ec5867838..6a35d17a7 100644
--- a/Completion/Core/compinit
+++ b/Completion/Core/compinit
@@ -1,25 +1,23 @@
 # Initialisation for new style completion. This mainly contains some helper
-# function and aliases. Everything else is split into different files in this
-# directory that will automatically be made autoloaded (see the end of this
-# file).
+# functions and aliases. Everything else is split into different files that
+# will automatically be made autoloaded (see the end of this file).
 # The names of the files that will be considered for autoloading have to
-# start with a underscores (like `_setopt).
+# start with an underscores (like `_setopt').
 # The first line of these files will be read and has to say what should be
 # done with its contents:
 #
-#   `#defcomp <names ...>'
-#     if the first line looks like this, the file is
-#     autoloaded as a function and that function will
-#     be called to generate the matches when completing
-#     for one of the commands whose <name> is given
+#   `#compdef <names ...>'
+#     If the first line looks like this, the file is autoloaded as a
+#     function and that function will be called to generate the matches
+#     when completing for one of the commands whose <names> are given.
 #
-#   `#defpatcomp <pattern>'
-#     this defines a function that should be called to generate
-#     matches for commands whose name matches <pattern>; note
-#     that only one pattern may be given
+#   `#compdef -p <pattern>'
+#     This defines a function that should be called to generate matches
+#     for commands whose name matches <pattern>. Note that only one pattern
+#     may be given.
 #
-#   `#defkeycomp <style> [ <key-sequence> ... ]
-#     this is used to bind special completions to all the given
+#   `#compdef -k <style> [ <key-sequence> ... ]'
+#     This is used to bind special completions to all the given
 #     <key-sequence>(s). The <style> is the name of one of the built-in
 #     completion widgets (complete-word, delete-char-or-list,
 #     expand-or-complete, expand-or-complete-prefix, list-choices,
@@ -29,35 +27,89 @@
 #     rather than by the context.  The widget has the same name as
 #     the autoload file and can be bound using bindkey in the normal way.
 #
-#   `#autoload'
-#     this is for helper functions that are not used to
+#   `#compdef -K <widget-name> <style> <key-sequence> [ ... ]'
+#     This is similar to -k, except it takes any number of sets of
+#     three arguments.  In each set, the widget <widget-name> will
+#     be defined, which will behave as <style>, as with -k, and will
+#     be bound to <key-sequence>, exactly one of which must be defined.
+#     <widget-name> must be different for each:  this must begin with an
+#     underscore, else one will be added, and should not clash with other
+#     completion widgets (names based on the name of the function are the
+#     clearest), but is otherwise arbitrary.  It can be tested in the
+#     function by the parameter $WIDGET.
+#
+#   `#autoload [ <options> ]'
+#     This is for helper functions that are not used to
 #     generate matches, but should automatically be loaded
-#     when they are called
+#     when they are called. The <options> will be given to the
+#     autoload builtin when making the function autoloaded. Note
+#     that this need not include `-U'.
 #
 # Note that no white space is allowed between the `#' and the rest of
 # the string.
 #
-# See the file `compdump' for how to speed up initialiation.
-#
-# If you are using global matching specifications with `compctl -M ...'
-# have a look at the files `_match_test' and `_match_pattern'. To make
-# all the example functions use matching as specified with `-M' these
-# need some editing.
+# Functions that are used to generate matches should return zero if they
+# were able to add matches and non-zero otherwise.
 #
+# See the file `compdump' for how to speed up initialisation.
+
 # If we got the `-d'-flag, we will automatically dump the new state (at
-# the end).
+# the end).  This takes the dumpfile as an argument.  -d (with the
+# default dumpfile) is now the default; to turn off dumping use -D.
+
+emulate -L zsh
+setopt extendedglob
+
+typeset _i_dumpfile _i_files _i_line _i_done _i_dir _i_autodump=1
+typeset _i_tag _i_file _i_addfiles
+
+while [[ $# -gt 0 && $1 = -[dDf] ]]; do
+  if [[ "$1" = -d ]]; then
+    _i_autodump=1
+    shift
+    if [[ $# -gt 0 && "$1" != -[df] ]]; then
+      _i_dumpfile="$1"
+      shift
+    fi
+  elif [[ "$1" = -D ]]; then
+    _i_autodump=0
+    shift
+  elif [[ "$1" = -f ]]; then
+    # Not used any more; use _compdir
+    shift
+    shift
+  fi
+done
 
-if [[ "$1" = -d ]]; then
-  _i_autodump=1
+# The associative array containing the definitions for the commands.
+# Definitions for patterns will be stored in the associations `_patcomps'
+# and `_postpatcomps'. `_compautos' contains the names and options
+# for autoloaded functions that get options.
+
+typeset -gA _comps _patcomps _postpatcomps _compautos
+
+# The associative array use to report information about the last
+# cmpletion to the outside.
+
+typeset -gA _lastcomp
+
+# Remember dumpfile.
+if [[ -n $_i_dumpfile ]]; then
+  # Explicitly supplied dumpfile.
+  _comp_dumpfile="$_i_dumpfile"
 else
-  _i_autodump=0
+  _comp_dumpfile="${ZDOTDIR:-$HOME}/.zcompdump"
 fi
 
-# The associative array containing the definitions for the commands.
-# Definitions for patterns will be stored in the normal array `_patcomps'.
+# These can hold names of functions that are to be called before/after all
+# matches have been generated.
 
-typeset -A _comps
-_patcomps=()
+compprefuncs=()
+comppostfuncs=()
+
+# Loading it now ensures that the `funcstack' parameter is always correct.
+
+: $funcstack
 
 # This function is used to register or delete completion functions. For
 # registering completion functions, it is invoked with the name of the
@@ -70,6 +122,9 @@ _patcomps=()
 # function will be invoked when completing for a command whose name 
 # matches the pattern given as argument after the function name (in this
 # case only one argument is accepted).
+# The option `-P' is like `-p', but the function will be called after
+# trying to find a function defined for the command on the line if no
+# such function could be found.
 # With the `-k' option a function for a special completion keys is 
 # defined and immediatly bound to those keys. Here, the extra arguments
 # are the name of one of the builtin completion widgets and any number
@@ -78,7 +133,8 @@ _patcomps=()
 # whose name is given as the first argument be autoloaded. When defining
 # a function for command names the `-n' option may be given and keeps
 # the definitions from overriding any previous definitions for the
-# commands.
+# commands; with `-k', the `-n' option prevents compdef from rebinding
+# a key sequence which is already bound.
 # For deleting definitions, the `-d' option must be given. Without the
 # `-p' option, this deletes definitions for functions for the commands
 # whose names are given as arguments. If combined with the `-p' option
@@ -110,11 +166,16 @@ compdef() {
 
   # Get the options.
 
-  while getopts "anpkd" opt; do
+  if [[ $#* -eq 0 ]]; then
+    echo "compdef needs parameters"
+    return 1
+  fi
+  
+  while getopts "anpPkKd" opt; do
     case "$opt" in
     a)    autol=yes;;
     n)    new=yes;;
-    [pk]) if [[ -n "$type" ]]; then
+    [pPkK]) if [[ -n "$type" ]]; then
             # Error if both `-p' and `-k' are given (or one of them
 	    # twice).
             echo "$0: type already set to $type"
@@ -122,6 +183,10 @@ compdef() {
 	  fi
 	  if [[ "$opt" = p ]]; then
 	    type=pattern
+	  elif [[ "$opt" = P ]]; then
+	    type=postpattern
+	  elif [[ "$opt" = K ]]; then
+	    type=widgetkey
 	  else
 	    type=key
 	  fi
@@ -131,12 +196,17 @@ compdef() {
   done
   shift OPTIND-1
 
+  if [[ $#* -eq 0 ]]; then
+    echo "compdef needs parameters"
+    return 1
+  fi
+  
   if [[ -z "$delete" ]]; then
     # Adding definitions, first get the name of the function name
     # and probably do autoloading.
 
     func="$1"
-    [[ -n "$autol" ]] && autoload "$func"
+    [[ -n "$autol" ]] && autoload -U "$func"
     shift
 
     case "$type" in
@@ -145,11 +215,33 @@ compdef() {
         echo "$0: only one pattern allowed"
 	return 1
       fi
-      # Patterns are stored in strings like `c* foo', with a space
-      # between the pattern and the function name.
-
-      _patcomps=("$_patcomps[@]" "$1 $func")
+      _patcomps[$1]="$func"
       ;;
+    postpattern)
+      if [[ $# -gt 1 ]]; then
+        echo "$0: only one pattern allowed"
+	return 1
+      fi
+      _postpatcomps[$1]="$func"
+      ;;
+    widgetkey)
+      while [[ -n $1 ]]; do
+	if [[ $# -lt 3 ]]; then
+	  echo "$0: compdef -K requires <widget> <comp-widget> <key>"
+	  return 1
+	fi
+	[[ $1 = _* ]] || 1="_$1"
+	[[ $2 = .* ]] || 2=".$2"
+	zle -C "$1" "$2" "$func"
+	if [[ -n $new ]]; then
+	  bindkey "$3" | read -A opt
+	  [[ $opt[-1] = undefined-key ]] && bindkey "$3" "$1"
+	else
+	  bindkey "$3" "$1"
+	fi
+	shift 3
+      done
+      ;;	 
     key)
       if [[ $# -lt 2 ]]; then
         echo "$0: missing keys"
@@ -157,30 +249,44 @@ compdef() {
       fi
 
       # Define the widget.
-      zle -C "$func" "$1" "$func"
+      if [[ $1 = .* ]]; then
+	zle -C "$func" "$1" "$func"
+      else
+	zle -C "$func" ".$1" "$func"
+      fi
       shift
 
       # And bind the keys...
       for i; do
+        if [[ -n $new ]]; then
+	   bindkey "$i" | read -A opt
+	   [[ $opt[-1] = undefined-key ]] || continue
+	fi
         bindkey "$i" "$func"
       done
       ;;
     *)
       # For commands store the function name in the `_comps'
       # associative array, command names as keys.
-      for i; do
-        [[ -z "$new" || "${+_comps[$i]}" -eq 0 ]] && _comps[$i]="$func"
-      done
+      if [[ -z "$new" ]]; then
+	for i; do
+	  _comps[$i]="$func"
+	done
+      else
+        for i; do
+          [[ "${+_comps[$i]}" -eq 0 ]] && _comps[$i]="$func"
+        done
+      fi
       ;;
     esac
   else
     # Handle the `-d' option, deleting.
     case "$type" in
     pattern)
-      # Note the space.
-      for i; do
-        _patcomps=("${(@)patcomps:#$i *}")
-      done
+      unset "_patcomps[$^@]"
+      ;;
+    postpattern)
+      unset "_postpatcomps[$^@]"
       ;;
     key)
       # Oops, cannot do that yet.
@@ -189,81 +295,210 @@ compdef() {
       return 1
       ;;
     *)
-      # Deleting definitons for command is even simpler.
-      for i; do
-        unset "_comps[$i]"
-      done
+      unset "_comps[$^@]"
     esac
   fi
 }
 
-# Now we automatically make the definition files autoloaded.
+# Do *not* use this...
 
-# First we get the name of a dump file if this will be used.
+compconf() {
 
-: ${COMPDUMP:=$0.dump}
+  local style name val i tmp cmt
 
-if [[ ! -o extendedglob ]]; then
-  _i_noextglob=yes
-  setopt extendedglob
-fi
+  if [[ -z "$_compconf_warn" ]]; then
+    _compconf_warn=yep
+
+    print "
+
+Hello
+
+\`compconf' will be removed in the near future, we now use a more
+general (and powerful) mechanism using the \`zstyle' builtin. An
+approximation to your old setup using \`zstyle' should be available
+in the file:
+
+    \`${HOME}/.zsh-styles'
+
+Note that the values for the styles may be partly incorrect. Please
+read the manual to find out how to configure the completion system
+with styles.
+
+Have fun
+
+   Sven
+" 1>&2
+    command rm -f ${HOME}/.zsh-styles
+  fi
+
+  for i; do
+    name="${i%%\=*}"
+    val="${i#*\=}"
+
+    tmp=''
+    cmt=''
+
+    case "$name" in
+    urls_path)
+      tmp="'*:urls' path ${(qq)val}"
+      ;;
+    urls_localhttp)
+      tmp="'*:urls' local ${${(qqs.:.)val}}"
+      ;;
+    describe_options)
+      tmp="'*:options' verbose 'yes'"
+      ;;
+    describe_values)
+      tmp="'*:values' verbose 'yes'"
+      ;;
+    autodescribe_options)
+      tmp="'*:options' auto-description ${(qq)val}"
+      ;;
+    description_format)
+      tmp="'*:descriptions' format ${(qq)val}"
+      ;;
+    message_format)
+      tmp="'*:messages' format ${(qq)val}"
+      ;;
+    warning_format)
+      tmp="'*:warnings' format ${(qq)val}"
+      ;;
+    option_prefix)
+      tmp="'*:options' prefix-needed yes"
+      [[ "$val" = hide* ]] &&
+          tmp="$tmp
+zstyle ':completion:*:options' prefix-hidden yes"
+      ;;    
+    group_matches)
+      tmp="'*' group-name ''"
+      ;;
+    colors_path)
+      tmp="'*:colors' path ${(qq)val}"
+      ;;
+    path_expand)
+      tmp="'*:paths' expand ${(qq)val}"
+      ;;
+    path_cursor)
+      tmp="'*:paths' cursor ${(qq)val}"
+      ;;
+    (approximate|incremental|predict|list|oldlist|match)_*)
+      tmp="'*${name%%_*}:*' ${${name#*_}//_/-} ${(qq)val}"
+      ;;
+    correct_*)
+      cmt="# This one is a bit ugly. You may want to use only \`*:correct'
+# if you also have the \`correctword_*' or \`approximate_*' keys.
+"
+      tmp="'*(correct(|-word)|approximate):*' ${name#*_} ${(qq)val}"
+      ;;
+    correctword_*)
+      tmp="'*:correct-word' ${name#correctword_} ${(qq)val}"
+      ;;
+    expand_*)
+      cmt="# This one is a bit ugly. You may want to use only \`*:expand'
+# if you also have the \`expandword_*' keys.
+"
+      tmp="'*expand(|expand-word):*' ${name#*_} ${(qq)val}"
+      ;;
+    expandword_*)
+      tmp="'expand-word:*' ${name#expandword_} ${(qq)val}"
+      ;;
+    history_*)
+      tmp="'history-words:*' ${name#history_} ${(qq)val}"
+      ;;
+    completer)
+      tmp="'*' completer ${${(qqs.:.)val}}"
+      ;;
+    last_prompt)
+      tmp="'*' last-prompt 'yes'"
+      ;;
+    esac
+    [[ -n "$tmp" ]] && style="${style}${cmt}zstyle :completion:${tmp}
+"
+  done
+
+  eval "${style}"
+
+  print "$style" >>! ${HOME}/.zsh-styles
+}
+
+# Now we automatically make the definition files autoloaded.
 
 typeset -U _i_files
-_i_files=( ${^~fpath}/_*~*~(N:t) )
-_i_initname=$0
+_i_files=( ${^~fpath:/.}/^([^_]*|*~|*.zwc)(N:t) )
+if [[ $#_i_files -lt 20 || $_compdir = */Core || -d $_compdir/Core ]]; then
+  # Too few files:  we need some more directories,
+  # or we need to check that all directories (not just Core) are present.
+  if [[ -n $_compdir ]]; then
+    _i_addfiles=()
+    if [[ $_compdir = */Core ]]; then
+      # Add all the Completion subdirectories
+      _i_addfiles=(${_compdir:h}/*(/))
+    elif [[ -d $_compdir/Core ]]; then
+      # Likewise
+      _i_addfiles=(${_compdir}/*(/))
+    fi
+    for _i_line in {1..$#i_addfiles}; do
+      _i_file=${_i_addfiles[$_i_line]}
+      [[ -d $_i_file && -z ${fpath[(r)$_i_file]} ]] ||
+        _i_addfiles[$_i_line]=
+    done
+    fpath=($fpath $_i_addfiles)
+    _i_files=( ${^~fpath:/.}/^([^_]*|*~|*.zwc)(N:t) )
+  fi
+fi
+
+
+# Rebind the standard widgets
+for _i_line in complete-word delete-char-or-list expand-or-complete \
+  expand-or-complete-prefix list-choices menu-complete \
+  menu-expand-or-complete reverse-menu-complete; do
+  zle -C $_i_line .$_i_line _main_complete
+done
+zle -la menu-select && zle -C menu-select .menu-select _main_complete
+
 _i_done=''
 
+# Make sure compdump is available, even if we aren't going to use it.
+autoload -U compdump compinstall
+
 # If we have a dump file, load it.
 
-if [[ -f "$COMPDUMP" ]]; then
-  read -rA _i_line < "$COMPDUMP"
+if [[ -f "$_comp_dumpfile" ]]; then
+  read -rA _i_line < "$_comp_dumpfile"
   if [[ _i_autodump -eq 1 && $_i_line[2] -eq $#_i_files ]]; then
-    builtin . "$COMPDUMP"
+    builtin . "$_comp_dumpfile"
     _i_done=yes
   fi
-  unset _i_line
 fi
 if [[ -z "$_i_done" ]]; then
   for _i_dir in $fpath; do
     [[ $_i_dir = . ]] && continue
-    for _i_file in $_i_dir/_*~*~(N); do
+    for _i_file in $_i_dir/^([^_]*|*~|*.zwc)(N); do
       read -rA _i_line < $_i_file
       _i_tag=$_i_line[1]
       shift _i_line
-      if [[ $_i_tag = '#defcomp' ]]; then
-        compdef -na "${_i_file:t}" "${_i_line[@]}"
-      elif [[ $_i_tag = '#defpatcomp' ]]; then
-        compdef -pa "${_i_file:t}" "${_i_line[@]}"
-      elif [[ $_i_tag = '#defkeycomp' ]]; then
-        compdef -ka "${_i_file:t}" "${_i_line[@]}"
-      elif [[ $_i_tag = '#autoload' ]]; then
-	autoload ${_i_file:t}
-      fi
+      case $_i_tag in
+      (\#compdef)
+	if [[ $_i_line[1] = -[pPkK](n|) ]]; then
+	  compdef ${_i_line[1]}na "${_i_file:t}" "${(@)_i_line[2,-1]}"
+	else
+	  compdef -na "${_i_file:t}" "${_i_line[@]}"
+	fi
+	;;
+      (\#autoload)
+	autoload -U "$_i_line[@]" ${_i_file:t}
+	[[ "$_i_line" != \ # ]] && _compautos[${_i_file:t}]="$_i_line"
+	;;
+      esac
     done
   done
 
-  bindkey |
-    while read -rA _i_line; do
-      if [[ "$_i_line[2]" = complete-word ||
-	"$_i_line[2]" = delete-char-or-list ||
-	"$_i_line[2]" = expand-or-complete ||
-	"$_i_line[2]" = expand-or-complete-prefix ||
-	"$_i_line[2]" = list-choices ||
-	"$_i_line[2]" = menu-complete ||
-	"$_i_line[2]" = menu-expand-or-complete ||
-	"$_i_line[2]" = reverse-menu-complete ]]; then
-	zle -C _complete_$_i_line[2] $_i_line[2] _main_complete
-	bindkey "${_i_line[1][2,-2]}" _complete_$_i_line[2]
-      fi
-    done
-
-  unset _i_dir _i_line _i_file _i_tag
-
   # If autodumping was requested, do it now.
 
-  (( _i_autodump )) && builtin . ${_i_initname:h}/compdump
+  if [[ $_i_autodump = 1 ]]; then
+    compdump
+  fi
 fi
 
-[[ -z "$_i_noextglob" ]] || unsetopt extendedglob
-
-unset _i_files _i_initname _i_done _i_autodump _i_noextglob
+unfunction compinit
+autoload -U compinit
diff --git a/Completion/Core/compinstall b/Completion/Core/compinstall
index d96121cf2..ad05cb5a1 100644
--- a/Completion/Core/compinstall
+++ b/Completion/Core/compinstall
@@ -1,72 +1,149 @@
-# This script is to be run by a user to setup the new function based
+# This script is to be run by a user to set up the new function based
 # completion system.  The functions themselves are assumed to be already
 # available in some directory; they should have been installed with the
-# the shell (except we haven't written that yet).
+# the shell.  If they have been, the commands `autoload -U compinit; compinit'
+# in the shell startup file should be enough, although you can run
+# compinstall for more configuration choices.
 #
-# Run it as a script under zsh and answer the questions.
-# You can run it as `zsh compinstall $FPATH' and it will be able to check
-# your function path for the completion functions.
-#
-# Normally, this will alter ~/.zshrc (or wherever ZDOTDIR puts it),
-# but you can make that unwritable and it will leave the lines in a
-# temporary file instead.
-#
-# You can use this script to modify what compinstall previously
-# added to ~/.zshrc.
+# Simply run this script as a function and answer the questions.
+# Normally it will alter ~/.zshrc (or wherever ZDOTDIR puts it), but you
+# can make that unwritable and it will leave the lines in a temporary file
+# instead.  It doesn't matter if .zshrc didn't exist before.  If your
+# .zshrc usually exits before the end, then you should take the code added
+# by compinstall and put it (including the comment lines at the start and
+# end) at the point you want it to be executed.  If you run compinstall
+# again it will find and replace those lines, so you can use this script to
+# modify what compinstall previously added to ~/.zshrc.
 #
 # It is safe to abort with ^C any time you are being prompted for
 # information; your .zshrc will not be altered.
 #
 # To do:
-#  - Maybe this should be sourced, then it can check the user's current
-#    setup better.  But then there is a potentially horrendous option
-#    setting/resetting problem.  (Maybe we need another way of doing that.)
 #  - Should probably offer to set different options for _approximate than
 #    for _complete if both are used.
 #  - Could add code for setting other completers and options.
 #  - Could add keys for context-sensitive help.
-#  - Probably should allow a set of directories to be added to $fpath,
-#    like Core, Base, etc.
 
-# In case a startup script changed options
-emulate zsh
 
-[[ -n $1 ]] && FPATH=$1
+emulate -L zsh
 
-for f in $fpath; do
-  if [[ $f != . && -f $f/compinit && -f $f/compdump ]]; then
-    fdir=$f
-    break
-  fi
-done
+typeset _ci_options _ci_f _ci_fdir _ci_files _ci_dumpfile _ci_lines
+typeset _ci_type _ci_completer _ci_accept _ci_cprompt _ci_startline
+typeset _ci_endline _ci_ifile _ci_tmpf _ci_compstyle _ci_warn
+typeset _ci_dtype _ci_existing _ci_line _ci_end
 
-if [[ -z $fdir ]]; then
-  print "Trying to find where the completion functions are..."
-  if [[ $0 = */* && -f $0:h/compinit && -f $0:h/compdump ]]; then
-    fdir=$0:h
-  else
-    # more guesses?
-    print \
+# Look for the defaults.
+_ci_startline='# The following lines were added by compinstall'
+_ci_endline='# End of lines added by compinstall'
+
+_ci_ifile=${ZDOTDIR:-~}/.zshrc
+_ci_lines=''
+_ci_existing=''
+
+typeset -A _ci_defaults
+
+if [[ -f $_ci_ifile ]]; then
+  # This assumes the lines haven't been altered by the user too much
+  # after they were added.
+  _ci_compstyle=0
+  sed -n "/^$_ci_startline/,/^$_ci_endline/p" $_ci_ifile |
+  while read -rA _ci_line; do
+    if (( $_ci_compstyle )); then
+      # parse a compstyle component as first argument
+      if [[ $_ci_line[-1] != \\ ]]; then
+	_ci_end=-1
+	_ci_compstyle=0
+      else
+	_ci_end=-2
+      fi
+      if [[ $_ci_line[1] = *=* ]]; then
+	_ci_f="${${_ci_line[1,$_ci_end]}#*=}"
+	if [[ $_ci_f = \'*\' ]]; then
+	  # strip quotes
+	  _ci_f=${_ci_f[2,-2]//\'\\\'\'/\'}
+	fi
+	_ci_defaults[${_ci_line[1]%%\=*}]=$_ci_f
+      fi
+      _ci_existing="${_ci_existing}  $_ci_line
+"
+    elif [[ $_ci_line[1] = compinit ]]; then
+      # parse the line running compinit
+      [[ $_ci_line[2] = -f ]]  && _ci_fdir=$_ci_line[3]
+      [[ $_ci_line[-2] = -d ]] && _ci_dumpfile=$_ci_line[-1]
+    elif [[ $_ci_line[1] = _compdir=* ]]; then
+      _ci_fdir=${_ci_line[1]##_compdir=}
+    elif [[ $_ci_line[1] = compstyle ]]; then
+      # parse a compstyle component as second argument (should be completer)
+      [[ $_ci_line[3] = completer ]] &&
+        _ci_completer=${_ci_line[3,-1]}
+      [[ $_ci_line[-1] == \\ ]] && _ci_compstyle=1
+      _ci_existing="${_ci_existing}$_ci_line
+"
+    elif [[ $_ci_line[1] != \#* && $_ci_line[1] != (autoload|\[\[) ]]; then
+      if [[ -z $_ci_warn ]]; then
+	_ci_warn=1
+	print "Warning:  existing lines in compinstall setup not understood:"
+      fi
+      print - $_ci_line
+      _ci_existing="${_ci_existing}$_ci_line
+"
+    fi
+  done
+fi
+
+
+# Find out where the completion functions are kept.
+
+if [[ -z $_ci_fdir || ! -f ${~_ci_fdir}/compinit ||
+  ! -f ${~_ci_fdir}/compdump ]]; then
+  for _ci_f in $fpath; do
+    if [[ $_ci_f != . && -f $_ci_f/compinit && -f $_ci_f/compdump ]]; then
+      _ci_fdir=$_ci_f
+      break
+    elif [[ $_ci_f != . && -f $_ci_f/Core/compinit &&
+      -f $_ci_f/Core/compdump ]]
+    then
+      _ci_fdir=$_ci_f/Core
+      break
+    fi
+  done
+fi
+
+if [[ -z $_ci_fdir || ! -d ${~_ci_fdir} ]]; then
+  print \
 "Please edit the name of the directory where the completion functions are
 installed.  If they are not installed, you will need to find them in the
 Completion/* directories of the zsh distribution and install them yourself,
 or insult your system manager for incompetence."
-    vared -c fdir
-    while [[ ! -d ${~fdir} || ! -f ${~fdir}/compinit || 
-      ! -f ${~fdir}/compdump ]]; do
-      print "I can't find them in that directory.  Try again or abort."
-      vared fdir
-    done
+  vared -c _ci_fdir
+  while [[ ! -d ${~_ci_fdir} || 
+    ((! -f ${~_ci_fdir}/compinit || ! -f ${~_ci_fdir}/compdump) &&
+    (! -f ${~_ci_fdir}/Core/compinit || ! -f ${~_ci_fdir}/Core/compdump)) ]]
+  do
+    print "I can't find them in that directory.  Try again or abort."
+    vared _ci_fdir
+  done
+  if [[ -f ${~_ci_fdir}/Core/compinit && ! -f ${~_ci_fdir}/compinit ]]; then
+    _ci_fdir=$_ci_fdir/Core
   fi
-  eval "fpath=($fdir \$fpath)"
-  fdir=${fdir/#$HOME/\~}
-  lines="fpath=($fdir \$fpath)\n"
 else
-  print "Found completion functions in your fpath, will not alter it."
+  print "Keeping existing completion directiory $_ci_fdir"
+fi
+
+if [[ ${~_ci_fdir} != /* ]]; then
+  _ci_fdir=$(cd $_ci_fdir;builtin pwd)
 fi
 
-files=( ${^~fpath:/.}/_(|*[^~])(N:t) )
-if [[ $#files -lt 20 ]]; then
+# Check if this is in fpath already, else put it there (with ~'s expanded).
+_ci_f=${~_ci_fdir}
+[[ -z ${fpath[(r)$_ci_f]} ]] && fpath=($fpath $_ci_f)
+
+# Contract $HOME to ~ in the parameter to be used for writing.
+_ci_fdir=${_ci_fdir/#$HOME/\~}
+
+# Now check the fpath, ignoring the directory .
+_ci_files=( ${^~fpath:/.}/_(|*[^~])(N:t) )
+if [[ $#_ci_files -lt 20 ]]; then
   print "
 Hmmm, completion functions seem a bit thin on the ground.  There should
 be lots of files with names beginning with an underscore (_).  You should
@@ -75,12 +152,20 @@ look and see what's happened to these.
   read
 fi
 
-if [[ -w ${~fdir} && ( ! -f ${~fdir}/compinit.dump ||
-  -w ${~fdir}/compinit.dump ) ]]
+
+# Set up the dumpfile
+_ci_dtype=existing
+if [[ -z $_ci_dumpfile ]]; then
+  _ci_dumpfile="${ZDOTDIR:-$HOME}/.zcompdump"
+  _ci_dtype=standard
+fi
+
+if [[ -w ${~_ci_dumpfile:h} && ( ! -f ${~_ci_dumpfile} ||
+  -w ${~_ci_dumpfile} ) ]]
 then
   print "
-Using standard dumpfile
-  ${~fdir}/compinit.dump
+Using $_ci_dtype dumpfile
+  ${_ci_dumpfile}
 to speed up initialisation.
 [Hit return to continue]"
   read
@@ -88,23 +173,32 @@ else
   print "
 I will force completion to dump its status, which will speed up the shell's
 start-up considerably.  However, I can't write the file I'd like to, namely
-$fdir/compinit.dump.  Please edit a replacement."
-  dumpfile='~/.compinit.dump'
-  vared dumpfile
-  while ! touch ${~dumpfile} >& /dev/null; do
+${_ci_dumpfile}.  Please edit a replacement."
+  vared _ci_dumpfile
+  while ! touch ${~_ci_dumpfile} >& /dev/null; do
     print "Sorry, I can't write that either.  Try again."
-    vared dumpfile
+    vared _ci_dumpfile
   done
-  [[ -s $dumpfile ]] || rm -f $dumpfile
-  dumpfile=" $dumpfile"
+  [[ -s $_ci_dumpfile ]] || rm -f $_ci_dumpfile
 fi
 
-fdir=${fdir/#$HOME/\~}
-
-lines="${lines}. $fdir/compinit -d$dumpfile\n"
+_ci_lines="${_ci_lines}_compdir=$_ci_fdir
+[[ -z \$fpath[(r)\$_compdir] ]] && fpath=(\$fpath \$_compdir)
+autoload -U compinit
+compinit"
+[[ $_ci_dtype != standard ]] && _ci_lines="${_ci_lines} $_ci_dumpfile"
+_ci_lines="${_ci_lines}
+"
 
 
 print "
+Would you like to set some more advanced options?  Otherwise, you
+can re-run compinstall later to set these. [n]"
+
+# The whole of the next part should be indented, but I can't be bothered.
+if read -q; then
+
+ print "
 In addition to completion, zsh can also perform correction of the
 current word, or approximate completion, i.e. completion where the part of
 the word typed so far can be corrected; or it can try correction, then
@@ -112,105 +206,156 @@ approximate completion if that fails.  Would you like:
   0:  Just ordinary completion
   C:  Correction
   A:  Approximate completion
-  B:  Both?
-Please type one of the keys above:"
-while read -k type; do
-  print
-  case $type in
-    0*) completer=_complete
-	break
-	;;
-    [cC]*) completer=_complete:_correct
-	   break
-	   ;;
-    [aA]*) completer=_complete:_approximate
-	   break;
-	   ;;
-    [bB]*) completer=_complete:_correct:_approximate
-	   break
-	   ;;
-    *) print Try again
-       ;;
-  esac
-done
-
-lines="${lines}compconf completer=$completer"
-
-
-if [[ $completer = *(correct|approx)* ]]; then
-  print "
-Correction and approximation will normally allow up to two errors,
-and you will be able to use a numeric prefix (e.g. <Esc>4) to allow
-more.  The standard prompt is \`correct to:'. Do you want to change
-any of this? [n]"
-  if read -q; then
-    print "Number of errors to accept normally (0 is OK):"
-    read accept
-    while [[ $accept != <-> ]]; do
-      read accept"?Please enter a number: "
-    done
-    print \
+  B:  Both"
+  if [[ -n $_ci_completer ]]; then
+    print "  Default: use the current completers:\n$_ci_completer"
+  else
+    print "Please type one of the keys above."
+  fi
+  while read -k _ci_type; do
+    print
+    case $_ci_type in
+      0*) _ci_completer=_complete
+	  break
+	  ;;
+      [cC]*) _ci_completer='_complete _correct'
+	     break
+	     ;;
+      [aA]*) _ci_completer='_complete _approximate'
+	     break;
+	     ;;
+      [bB]*) _ci_completer='_complete _correct _approximate'
+	     break
+	     ;;
+      *) [[ -n $_ci_completer ]] && break
+	 print Try again
+	 ;;
+    esac
+  done
+
+  _ci_lines="${_ci_lines}zstyle ':completion*' completer $_ci_completer"
+
+
+  if [[ $_ci_completer = *(correct|approx)* ]]; then
+    _ci_accept=${_ci_defaults[correct_accept]}
+    _ci_cprompt=${_ci_defaults[correct_prompt]}
+    print "
+Correction and approximation will allow up to ${${_ci_accept:-2}%%[^0-9]*} \
+errors. "
+    case $_ci_accept in
+      *n*!*|*!*n) print "A numeric prefix, if not 1, will cause correction \
+not to be done."
+		  ;;
+      *n*) print "A numeric prefix gives the maximum number of errors which \
+will be accepted."
+           ;;
+      *) print "The numeric prefix will not be used."
+    esac
+print "The correction prompt is \`${_ci_cprompt:-correct to:}'.
+Do you want to change any of this? [n]"
+    if read -q; then
+      print "Number of errors to accept normally (0 is OK):"
+      _ci_accept=${_ci_accept%%[^0-9]*}
+      vared _ci_accept
+      while [[ $_ci_accept != <-> ]]; do
+	print "Please enter a number:"
+	vared _ci_accept
+      done
+      print \
 "How would you like the numeric prefix to be treated:
   0:  Not used by correction
-  U:  Used to given the number of errors
+  U:  The number gives the largest number of errors which will be
+      accepted when correcting
   I:  If present, and not 1, do not perform correction?
 Please type one of the keys above:"
-    while read -k type; do
-      print
-      case $type in
-	0*) break
-	    ;;
-	[uU]*) accept="${accept}n"
-	       break
-	       ;;
-	[Ii]*) accept="${accept}!n"
-	       break
-	       ;;
-	*) print Try again
-	   ;;
-      esac
-    done
-    lines="$lines \\\\
-  correct_accept='$accept'"
-    print "
+      while read -k _ci_type; do
+	print
+	case $_ci_type in
+	  0*) break
+	      ;;
+	  [uU]*) _ci_accept="${_ci_accept}n"
+		 break
+		 ;;
+	  [Ii]*) _ci_accept="${_ci_accept}!n"
+		 break
+		 ;;
+	  *) print Try again
+	     ;;
+	esac
+      done
+      print "
 Instead of the prompt \`correct to:', you can have no prompt, or a
 prompt of your choosing which can display the number of errors found by
 containing the string \`%e'.  Do you wish to change the correction
 prompt? [n]"
-    if read -q; then
-      cprompt=''
-      print "Edit a new prompt (may be empty):"
-      vared cprompt
-      lines="$lines \\\\
-  correct_prompt='${cprompt//\'/\'\\\'\'}'"
+      if read -q; then
+	print "Edit a new prompt (may be empty):"
+	vared _ci_cprompt
+	[[ -z $_ci_cprompt ]] && _ci_cprompt=':empty:'
+      fi
+    fi
+    if [[ -n $_ci_accept ]]; then
+      _ci_lines="$_ci_lines \\
+  correct_accept='$_ci_accept'"
+      unset '_ci_defaults[correct_accept]'
+    fi
+    if [[ -n $_ci_cprompt ]]; then
+      _ci_cprompt=${_ci_cprompt##:empty:}
+      _ci_lines="$_ci_lines \\
+  correct_prompt='${_ci_cprompt//\'/\'\\\'\'}'"
+      unset '_ci_defaults[correct_prompt]'
     fi
   fi
-fi
 
-lines="$lines\n"
+  _ci_warn=''
+  for _ci_f in ${(k)_ci_defaults}; do
+    if [[ -z $_ci_warn ]]; then
+      print "
+(Keeping other existing configuration settings...)"
+      _ci_warn=1
+    fi
+    _ci_lines="$_ci_lines \\
+  ${_ci_f}='${_ci_defaults[$_ci_f]//\'/\'\\\'\'}'"
+  done
 
+  _ci_lines="$_ci_lines
+"
 
-startline='# The following lines were added by compinstall'
-endline='# End of lines added by compinstall'
+else
 
-ifile=${ZDOTDIR:-~}/.zshrc
-[[ -f $ifile ]] || touch $ifile
-tmpf=${TMPPPREFIX:-/tmp/zsh}compinstall$$
+  if [[ -n $_ci_existing ]]; then
+    print -nr "
+I will retain the following lines from the existing completion setup:
+$_ci_existing"
+    _ci_lines="$_ci_lines${_ci_existing}"
+  fi
+
+fi				# End of advanced options
 
-if [[ ! -w $ifile ]]; then
-  print "\nI can't write to $ifile.  I will leave the lines to add in
-\`$tmpf' and you must add them by hand."
-  print "\n$startline\n$lines\n$endline" >$tmpf
-  return 0
-fi
 
-if grep $endline $ifile >& /dev/null; then
-  print -- "$startline\n$lines$endline" >$tmpf
-  sed -e "/^$endline/r $tmpf
-/^$startline/,/^$endline/d" $ifile >${tmpf}2 && mv ${tmpf}2 $ifile &&
-  print "\nSuccesfully modified old compinstall lines in $ifile."
-  rm -f $tmpf ${tmpf}2
+[[ -f $_ci_ifile ]] || touch $_ci_ifile
+_ci_tmpf=${TMPPPREFIX:-/tmp/zsh}compinstall$$
+
+if [[ ! -w $_ci_ifile ]]; then
+  print "\nI can't write to $_ci_ifile.  I will leave the lines to add in
+\`$_ci_tmpf' and you must add them by hand."
+  print -r - "$_ci_startline
+$_ci_lines$_ci_endline" >$_ci_tmpf
+elif grep $_ci_endline $_ci_ifile >& /dev/null; then
+  print -r - "$_ci_startline
+$_ci_lines$_ci_endline" >$_ci_tmpf
+  sed -e "/^$_ci_endline/r $_ci_tmpf
+/^$_ci_startline/,/^$_ci_endline/d" $_ci_ifile >${_ci_tmpf}2 && 
+  mv ${_ci_tmpf}2 $_ci_ifile &&
+  print "\nSuccesfully modified old compinstall lines in $_ci_ifile."
+  rm -f $_ci_tmpf ${_ci_tmpf}2
 else
-  print "\n$startline\n$lines\n$endline" >>$ifile &&
-  print "\nSuccessfully appended lines to $ifile."
+  print -r - "$_ci_startline
+$_ci_lines$_ci_endline" >>$_ci_ifile &&
+  print "\nSuccessfully appended lines to $_ci_ifile."
 fi
+
+unfunction compinstall
+autoload -U compinstall
+
+return 0
diff --git a/Completion/Linux/_rpm b/Completion/Linux/_rpm
index 7fdc80ab0..9ef2d57d9 100644
--- a/Completion/Linux/_rpm
+++ b/Completion/Linux/_rpm
@@ -3,7 +3,7 @@
 # This uses `_arguments' in a state-machine kind of way. These states
 # have names and before executing the default action for such a state
 # we try to call a function with the name `_rpm_<state>'. If such a
-# function exists, we return with it's return status immediatly. This
+# function exists, we return with its return status immediately. This
 # allows users to override the default completions by simply defining
 # these functions.
 # The states (and possible values for the `<state>' above) are:
@@ -43,28 +43,36 @@ local ret=1 tmp expl
 
 # Used by `_arguments', made local here.
 
-local state lstate line
-tyeset -A options
+local curcontext="$curcontext" state lstate line
+typeset -A opt_args
 
 state=''
 
 # Do simple completions or get the first state.
 
-_arguments \
+_arguments -C -s \
   '--rcfile:resource file:_files' \
   '--ftpproxy:FTP proxy server:_hosts' \
   '--ftpport:FTP port number:' \
-  '-q:*:query:->query' \
-  -{V,v,vv,y,-{setperms,setugids,querytags,initdb,showrc}} \
-  '-pipe:*:pipe command:_command_names -e' \
-  '--verify:*:verify:->verify' \
-  -{i,-install}':*:install:->install' \
-  -{U,-upgrade}':*:upgrade:->upgrade' \
-  -{e,-erase}':*:uninstall:->uninstall' \
-  -'b+:build stage:((p\:execute\ \%prep\ stage l\:do\ a\ list\ check c\:execute\ build\ stage i\:execute\ install\ stage b\:build\ a\ binary\ package a\:build\ binary\ and\ source\ packages)):*:build:->build_b' \
-  -'t+:build stage:((p\:execute\ \%prep\ stage l\:do\ a\ list\ check c\:execute\ build\ stage i\:execute\ install\ stage b\:build\ a\ binary\ package a\:build\ binary\ and\ source\ packages)):*:build:->build_t' \
+  '-q+[query mode]:*:query:->query' \
+  '*-v[verbose mode]' \
+  --{setperms,setugids,querytags,initdb,showrc} \
+  '--pipe:pipe command:_command_names -e' \
+  -{V,y}'[verify mode]:*:verify:->verify' \
+  '--verify[verify mode]:*:verify:->verify' \
+  '-i+[install mode]:*:install:->install' \
+  '--install:*:install:->install' \
+  '-U+[upgrade mode]:*:upgrade:->upgrade' \
+  '--upgrade:*:upgrade:->upgrade' \
+  '-F+[freshen mode]:*:upgrade:->upgrade' \
+  '--freshen:*:upgrade:->upgrade' \
+  '-e+[uninstall mode]:*:uninstall:->uninstall' \
+  '--erase:*:uninstall:->uninstall' \
+  -'b+[build mode (spec file)]:build stage:((p\:execute\ \%prep\ stage l\:do\ a\ list\ check c\:execute\ build\ stage i\:execute\ install\ stage b\:build\ a\ binary\ package a\:build\ binary\ and\ source\ packages)):*:build:->build_b' \
+  -'t+[build mode (tar file)]:build stage:((p\:execute\ \%prep\ stage l\:do\ a\ list\ check c\:execute\ build\ stage i\:execute\ install\ stage b\:build\ a\ binary\ package a\:build\ binary\ and\ source\ packages)):*:build:->build_t' \
   --{rebuild,rmsource,recompile,resign,addsign}':*:RPM package:->package' \
-  -{K,-checksig}':*:sigcheck:->sigcheck' \
+  '-K+[signature check mode]:*:sigcheck:->sigcheck' \
+  '--checksig:*:sigcheck:->sigcheck' \
   '--rebuilddb:*:rebuild:->rebuild' && ret=0
 
 # As long as we have a state name...
@@ -73,7 +81,7 @@ while [[ -n "$state" ]]; do
 
   # First try to call a user-defined function.
 
-  funcall ret _rpm_$state && return ret
+  _funcall ret _rpm_$state && return ret
 
   # Copy the state and reset `state', to simplify the test above.
 
@@ -85,24 +93,24 @@ while [[ -n "$state" ]]; do
 
   case "$lstate" in
   query)
-    _arguments \
-      -{v,vv} \
+    _arguments -s \
+      '*-v[verbose mode]' -q \
       '--rcfile:resource file:_files' \
       '--ftpproxy:FTP proxy server:_hosts' \
       '--ftpport:FTP port number:' \
       '--root:RPM root directory:_files -/' \
       '--dbpath:RPM database path:_files -/' \
       '--queryformat:RPM query format:->tags' \
-      '-f:file:_files' \
-      '-p:RPM package file:->package_file' \
+      '-f[specify file to query owner of]:file:_files' \
+      '-p+[specify uninstalled package file to query]:*:RPM package file:->package_file' \
       '--triggeredby:RPM package:->package' \
       '--whatprovides:RPM capability:->capability' \
       '--whatrequires:RPM capability:->capability' \
       '*:RPM package:->package_or_file' && ret=0
     ;;
   verify)
-    _arguments \
-      -{v,vv} \
+    _arguments -s \
+      '*-v[verbose mode]' '(-y)-V' '(-V)-y' \
       '--rcfile:resource file:_files' \
       '--ftpproxy:FTP proxy server:_hosts' \
       '--ftpport:FTP port number:' \
@@ -112,15 +120,18 @@ while [[ -n "$state" ]]; do
       '*:RPM package:->package' && ret=0
     ;;
   upgrade)
-    tmp=( --oldpackage )
+    tmp=( -U --oldpackage )
     ;&
   install)
-    _arguments "$tmp[@]" \
-      -{v,vv} \
+    (( $#tmp )) || tmp=(-i)
+    _arguments -s "$tmp[@]" \
+      '*-v[verbose mode]' \
       '--rcfile:resource file:_files' \
       '--ftpproxy:FTP proxy server:_hosts' \
       '--ftpport:FTP port number:' \
-      -{-{badreloc,excludedocs,force,hash,allfiles,ignorearch,ignoreos,includedocs,justdb,nodeps,noorder,noscripts,notriggers,percent,replacefiles,replacepkgs,test},h} \
+      '(-h)--hash' '(--hash)-h' \
+      '(--replacepkgs --replacefiles --oldpackage)--force' \
+      --{badreloc,excludedocs,allfiles,ignorearch,ignoreos,includedocs,justdb,nodeps,noorder,noscripts,notriggers,percent,replacefiles,replacepkgs,test} \
       '--relocate:relocate:->relocate' \
       '--prefix:package prefix directory:_files -/' \
       '--root:RPM root directory:_files -/' \
@@ -128,8 +139,8 @@ while [[ -n "$state" ]]; do
       '*:pkg file:->package_file' && ret=0
     ;;
   uninstall)
-    _arguments \
-      -{v,vv} \
+    _arguments -s \
+      '*-v[verbose mode]' -e \
       '--rcfile:resource file:_files' \
       '--ftpproxy:FTP proxy server:_hosts' \
       '--ftpport:FTP port number:' \
@@ -139,13 +150,13 @@ while [[ -n "$state" ]]; do
       '*:RPM package:->package' && ret=0
     ;;
   build_b)
-    tmp=( '*:RPM package:->package' )
+    tmp=( '*:spec file:_files -g \*.spec' )
     ;&
   build_t)
     (( $#tmp )) || tmp=( '*:tar file:_files -g \*.\(\#i\)tar\(.\*\|\)' )
 
-    _arguments \
-      -{v,vv} \
+    _arguments -s \
+      '*-v[verbose mode]' \
       '--rcfile:resource file:_files' \
       '--ftpproxy:FTP proxy server:_hosts' \
       '--ftpport:FTP port number:' \
@@ -156,8 +167,8 @@ while [[ -n "$state" ]]; do
       '--timecheck:time check (seconds):' "$tmp[1]" && ret=0
     ;;
   sigcheck)
-    _arguments \
-      -{v,vv} \
+    _arguments -s \
+      '*-v[verbose mode]' -K \
       '--rcfile:resource file:_files' \
       '--ftpproxy:FTP proxy server:_hosts' \
       '--ftpport:FTP port number:' \
@@ -165,8 +176,8 @@ while [[ -n "$state" ]]; do
       '*:RPM package file:->package_or_file' && ret=0
     ;;
   rebuild)
-    _arguments \
-      -{v,vv} \
+    _arguments -s \
+      '*-v[verbose mode]' \
       '--rcfile:resource file:_files' \
       '--ftpproxy:FTP proxy server:_hosts' \
       '--ftpport:FTP port number:' \
@@ -178,21 +189,23 @@ while [[ -n "$state" ]]; do
     state=package_file
     ;&
   package)
-    _description expl 'RPM package'
-    compadd "$expl[@]" -M 'r:|-=* r:|=*' - $(rpm -qa) && ret=0
+    _wanted packages expl 'RPM package' \
+        compadd -M 'r:|-=* r:|=*' - $(_call packages rpm -qa) && ret=0
     ;;
   package_file)
-    if compset -P ftp:; then
+    if compset -P ftp://; then
       _hosts -S/ && ret=0
     else
-      _files -g '*.(#i)rpm' && ret=0
+      _alternative \
+          'files:RPM package file:_files -g \*.\(\#i\)rpm' \
+	  'prefixes:ftp URL prefix:compadd ftp://' && ret=0
     fi
     ;;
   tags)
     if compset -P '*\{'; then
-      _description expl 'RPM tag'
-      compadd "$expl[@]" -M 'm:{a-z}={A-Z}' -S '}' - \
-              "${(@)${(@f)$(rpm --querytags)}#RPMTAG_}" && ret=0
+      _wanted tags expl 'RPM tag' \
+          compadd -M 'm:{a-z}={A-Z}' -S '\}' - \
+                  "${(@)${(@f)$(_call tags rpm --querytags)}#RPMTAG_}" && ret=0
     else
       _message 'RPM format'
     fi
@@ -201,10 +214,10 @@ while [[ -n "$state" ]]; do
     _message 'RPM capability'
     ;;
   relocate)
-    if compset -P '*\='; then
-      _description expl 'new path'
+    if compset -P '*='; then
+      _description directories expl 'new path'
     else
-      _description expl 'old path'
+      _description directories expl 'old path'
     fi
 
     _files "$expl[@]" -/ && ret=0
diff --git a/Completion/User/_gdb b/Completion/User/_gdb
index ff54e6a07..55e149bb7 100644
--- a/Completion/User/_gdb
+++ b/Completion/User/_gdb
@@ -1,36 +1,44 @@
 #compdef gdb
 
-# This uses the configuration keys `ps_args' and `ps_listargs'
-# described in the `_wait' function.
+local cur="$words[CURRENT]" prev w list ret=1 expl
 
-local cur="$words[CURRENT]" prev w list ret=1
-
-_long_options -t '*=(CORE|SYM)FILE'	'_files' \
-		 '*=EXECFILE'   	'_files *(*)' \
-		 '*=TTY'		'compadd /dev/tty*' && return 0
+[[ "$PREFIX" = --* ]] &&
+    _arguments -- '*=(CORE|SYM)FILE:core file:_files' \
+		  '*=EXECFILE:executable:_files \*\(-\*\)' \
+		  '*=TTY:terminal device:compadd /dev/tty\*' && return 0
 
 if compset -P '-(cd|directory)='; then
   _files -/
 elif compset -P '-tty='; then
-  compadd - /dev/tty*
+  _wanted devices expl 'terminal device' compadd - /dev/tty*
 elif compset -P '-(exec|se)='; then
-  _files -/g '*(*)'
+  _description files expl executable
+  _files "$expl[@]" -g '*(-*)'
 elif compset -P '-(symbols|core|command)='; then
   _files
-elif compset -P -; then
-  compadd -QS '' - symbols\= exec\= se\= core\= command\= directory\= \
-	           cd\= tty\=
-  compadd - help h s e c x d nx n quiet q batch fullname f b
+elif [[ "$PREFIX" = -* ]]; then
+  if _wanted options; then
+    while _next_label options expl option; do
+      compadd "$expl[@]" -QS '' - -symbols\= -exec\= -se\= -core\= -command\= \
+                                  -directory\= -cd\= -tty\= && ret=0
+      compadd "$expl[@]"        - -help -h -s -e -c -x -d -nx -n -quiet -q \
+	    		          -batch -fullname -f -b && ret=0
+      (( ret )) || return 0
+    done
+  fi
 else
   prev="$words[CURRENT-1]"
 
   case "$prev" in
-  (-d) _files -/ && return 0 ;;
-  (-e) _files -/g '*(*)' && return 0 ;;
+  (-d)     _files -/ && return 0 ;;
   (-[csx]) _files && return 0 ;;
-  (-b) compadd -V baud 0 50 75 110 134 150 200 300 600 1200 1800 2400 4800 \
-                       9600 19200 38400 57600 115200 230400 && return 0 ;;
+  (-e)     _description files expl executable
+           _files "$expl[@]" -g '*(-*)' && return 0 ;;
+  (-b)     _wanted -V values expl 'baud rate' \
+               compadd 0 50 75 110 134 150 200 300 600 1200 1800 2400 4800 \
+		       9600 19200 38400 57600 115200 230400 && return 0 ;;
   esac
+
   w=( "${(@)words[2,-1]}" )
   while [[ "$w[1]" = -* ]]; do
     [[ "$w[1]" = -[decsxb] ]] && shift 1 w
@@ -38,13 +46,9 @@ else
   done
 
   if [[ $#w -gt 1 ]]; then
-    _files && ret=0
-    list=("${(F)${(@Mr:COLUMNS-1:)${(f)$(ps ${compconfig[ps_listargs]:-$compconfig[ps_args]} 2>/dev/null)}[2,-1]:#[ 	]#${PREFIX}[0-9]#${SUFFIX}[ 	]*${w[1]:t}}}
-")
-    compadd -y list - ${${${(M)${(f)"$(ps $compconfig[ps_args] 2>/dev/null)"}:#*${w[1]:t}*}## #}%% *} && ret=0
-
-    return ret
+    _alternative 'files:: _files' "processes:: _pids -m ${w[1]:t}"
   else
-    _files -/g '*(*)'
+    _description files expl executable
+    _files "$expl[@]" -g '*(-*)'
   fi
 fi
diff --git a/Completion/User/_getconf b/Completion/User/_getconf
index 7ce709588..59e9a83bc 100644
--- a/Completion/User/_getconf
+++ b/Completion/User/_getconf
@@ -1,20 +1,19 @@
 #compdef getconf
 
-local expl
+local expl ret=1
 
 if [[ CURRENT -eq 2 ]]; then
   _tags syswideconfig pathconfig standardsconfig
 
   while _tags; do
-    if _requested -V syswideconfig expl 'systemwide configuration variables'
-    then
-      compadd "$expl[@]" -S '' ARG_MAX BC_BASE_MAX BC_DIM_MAX BC_SCALE_MAX \
+    _requested -V syswideconfig expl 'systemwide configuration variables' \
+      compadd -S '' ARG_MAX BC_BASE_MAX BC_DIM_MAX BC_SCALE_MAX \
           BC_STRING_MAX CHILD_MAX COLL_WEIGHTS_MAX EXPR_NEST_MAX LINE_MAX \
-	  NGROUPS_MAX OPEN_MAX RE_DUP_MAX STREAM_MAX TZNAME_MAX
-    fi
-    if _requested -V standardsconfig \
-        expl 'system-standards configuration variables'; then
-      compadd "$expl[@]" -S '' _POSIX_CHILD_MAX _POSIX_LINK_MAX \
+	  NGROUPS_MAX OPEN_MAX RE_DUP_MAX STREAM_MAX TZNAME_MAX && ret=0
+
+    _requested -V standardsconfig \
+        expl 'system-standards configuration variables' \
+      compadd -S '' _POSIX_CHILD_MAX _POSIX_LINK_MAX \
           _POSIX_MAX_CANON _POSIX_MAX_INPUT _POSIX_NAME_MAX _POSIX_NGROUPS_MAX \
 	  _POSIX_OPEN_MAX _POSIX_PATH_MAX _POSIX_PIPE_BUF _POSIX_SSIZE_MAX \
 	  _POSIX_STREAM_MAX _POSIX_TZNAME_MAX _POSIX_VERSION \
@@ -22,15 +21,17 @@ if [[ CURRENT -eq 2 ]]; then
 	  POSIX2_BC_STRING_MAX POSIX2_COLL_WEIGHTS_MAX POSIX2_EXPR_NEST_MAX \
 	  POSIX2_LINE_MAX POSIX2_RE_DUP_MAX POSIX2_VERSION POSIX2_C_BIND \
 	  POSIX2_C_DEV POSIX2_FORT_DEV POSIX2_FORT_RUN POSIX2_LOCALEDEF \
-	  POSIX2_SW_DEV _XOPEN_VERSION
-    fi
-    if _requested -V pathconfig expl 'system path configuration variables'
-    then
-      compadd "$expl[@]" -S '' PIPE_BUF _POSIX_CHOWN_RESTRICTED \
-          _POSIX_NO_TRUNC _POSIX_VDISABLE
-      compadd "$expl[@]" -S ' ' LINK_MAX MAX_CANON MAX_INPUT NAME_MAX PATH_MAX \
-          PIPE_BUF
-    fi
+	  POSIX2_SW_DEV _XOPEN_VERSION && ret=0
+
+    _requested pathconfig &&
+        while _next_label -V pathconfig expl 'system path configuration variables'; do
+          compadd "$expl[@]" -S '' PIPE_BUF _POSIX_CHOWN_RESTRICTED \
+                                   _POSIX_NO_TRUNC _POSIX_VDISABLE && ret=0
+          compadd "$expl[@]" -S ' ' LINK_MAX MAX_CANON MAX_INPUT NAME_MAX \
+                                    PATH_MAX PIPE_BUF && ret=0
+          (( ret )) || break
+        done
+    (( ret )) || return 0
   done
 else
   _files -/
diff --git a/Completion/User/_groups b/Completion/User/_groups
index 975189174..27444d26d 100644
--- a/Completion/User/_groups
+++ b/Completion/User/_groups
@@ -1,6 +1,19 @@
 #compdef newgrp
 
-: ${(A)groups:=${${(s: :)$(</etc/group)}%%:*}}
-# : ${(A)groups:=${${(s: :)$(ypcat group.byname)}%%:*}} # If you use NIS
+local expl groups tmp
 
-compadd $groups
+_wanted groups || return 1
+
+if ! zstyle -a ":completion:${curcontext}:" groups groups; then
+  (( $+_cache_groups )) ||
+      if (( ${+commands[ypcat]} )) &&
+	  tmp=$(_call groups ypcat group.byname); then
+        : ${(A)_cache_groups:=${${(f)tmp}%%:*}} # If you use YP
+      else
+        : ${(A)_cache_groups:=${${(s: :)$(</etc/group)}%%:*}}
+      fi
+
+  groups=( "$_cache_groups[@]" )
+fi
+
+_all_labels groups expl group compadd "$@" - "$groups[@]"
diff --git a/Completion/User/_lp b/Completion/User/_lp
index f37c62a14..cfa2a147c 100644
--- a/Completion/User/_lp
+++ b/Completion/User/_lp
@@ -1,50 +1,98 @@
 #compdef lp lpr lpq lprm
 
-local file expl ret=1 list disp strs shown
+local expl ret=1 printer list disp strs shown
 
 if (( ! $+_lp_cache )); then
+  local file entry names i
+
    file=( /etc/(printcap|printers.conf)(N) )
 
-  if (( $#file )); then
-    _lp_cache=( "${(@)${(@s:|:)${(@)${(@f)$(< $file[1])}:#[    \#]*}%%:*}%%[ 	]*}" )
-  else
-    # Default value. Could probably be improved
+  _lp_cache=()
+  _lp_alias_cache=()
 
-    _lp_cache=( lp0 )
+  if (( $#file )); then
+    while read entry; do
+      if [[ "$entry" = [^[:blank:]\#\*_]*:* ]]; then
+        names=( "${(s:|:)entry%%:*}" )
+        if [[ "$entry" = *:description=* ]]; then
+          disp="${${entry##*:description=}%%:*}"
+        elif [[ $#names -gt 1 && "$names[-1]" = *\ * ]] ;then
+          disp="$names[-1]"
+        else
+          disp=''
+        fi
+        if [[ -n "$disp" ]]; then
+          _lp_cache=( "$_lp_cache[@]" "${names[1]}:${disp}" )
+  	_lp_alias_cache=( "$_lp_alias_cache[@]" "${(@)^names[2,-1]:#*\ *}:${disp}" )
+        else
+          _lp_cache=( "$_lp_cache[@]" "${names[1]}" )
+  	_lp_alias_cache=( "$_lp_alias_cache[@]" "${(@)names[2,-1]:#*\ *}" )
+        fi
+      fi
+    done < $file[1]
   fi
+  (( $#_lp_cache )) || _lp_cache=( 'lp0:Guessed default printer' )
+  (( $#_lp_alias_cache )) || unset _lp_alias_cache
 fi
 
 if compset -P -P || [[ "$words[CURRENT-1]" = -P ]]; then
-  _wanted printers expl printer && compadd "$expl" - "$_lp_cache[@]"
+  if _wanted printers; then
+    if zstyle -T ":completion:${curcontext}:printers" verbose; then
+      zformat -a list ' -- ' "$_lp_cache[@]"
+      disp=(-ld list)
+    else
+      disp=()
+    fi
+    _all_labels printers expl printer \
+        compadd "$disp[@]" - "${(@)_lp_cache%%:*}" && return 0
+
+    (( $+_lp_alias_cache )) || return 1
+
+    if zstyle -T ":completion:${curcontext}:printers" verbose; then
+      zformat -a list ' -- ' "$_lp_alias_cache[@]"
+      disp=(-ld list)
+    else
+      disp=()
+    fi
+    compadd "$expl[@]" "$disp[@]" - "${(@)_lp_alias_cache%%:*}"
+  else
+    return 1
+  fi
 else
   if [[ "$words[1]" = (lpq|lprm) ]]; then
-    list=( "${(@M)${(f@)$(lpq)}:#[0-9]*}" )
+    if [[ "$words" = *-P* ]]; then
+      printer=(-P "${${words##*-P( |)}%% *}")
+    else
+      printer=()
+    fi
+    list=( ${(M)"${(f@)$(_call jobs lpq $printer 2> /dev/null)}":#[0-9]*} )
 
     if (( $#list )); then
       _tags users jobs
 
       while _tags; do
-        if _requested users expl user; then
+        if _requested users; then
           strs=( "${(@)${(@)list##[^ 	]##[ 	]##[^ 	]##[ 	]##}%%[ 	]*}" )
           if [[ -z "$shown" ]] &&
-             zstyle -t ":completion:${curcontext}:users" verbose; then
+             zstyle -T ":completion:${curcontext}:users" verbose; then
             disp=(-ld list)
   	  shown=yes
           else
   	  disp=()
           fi
-          compadd "$expl[@]" "$disp[@]" - "$strs[@]" || _users && ret=0
+	  _all_labels users expl user compadd "$disp[@]" - "$strs[@]" ||
+              _users && ret=0
         fi
-        if _requested jobs expl job; then
+        if _requested jobs; then
           strs=( "${(@)${(@)list##[^ 	]##[ 	]##[^ 	]##[ 	]##[^ 	]##[ 	]##}%%[ 	]*}" )
           if [[ -z "$shown" ]] &&
-             zstyle -t ":completion:${curcontext}:jobs" verbose; then
+             zstyle -T ":completion:${curcontext}:jobs" verbose; then
             disp=(-ld list)
   	  shown=yes
           else
   	  disp=()
           fi
-          compadd "$expl[@]" "$disp[@]" - "$strs[@]" && ret=0
+          _all_labels jobs expl job compadd "$disp[@]" - "$strs[@]" && ret=0
         fi
         (( ret )) || return 0
       done
diff --git a/Completion/User/_make b/Completion/User/_make
index d576b0308..741cbb7dc 100644
--- a/Completion/User/_make
+++ b/Completion/User/_make
@@ -1,3 +1,32 @@
-#defcomp make gmake pmake
+#compdef make gmake pmake
 
-complist -s "\$(awk '/^[a-zA-Z0-9][^/ 	]+:/ {print \$1}' FS=: [mM]akefile)"
+local prev="$words[CURRENT-1]" file expl tmp
+
+if [[ "$prev" = -[CI] ]]; then
+  _files -/
+elif [[ "$prev" = -[foW] ]]; then
+  _files
+else
+  file="$words[(I)-f]"
+  if (( file )); then
+    file="$words[file+1]"
+  elif [[ -e Makefile ]]; then
+    file=Makefile
+  elif [[ -e makefile ]]; then
+    file=makefile
+  else
+    file=''
+  fi
+
+  if [[ -n "$file" ]] && _wanted targets; then
+    tmp=(
+          $(awk '/^[a-zA-Z0-9][^\/ \t]+:/ {print $1}
+ 	      /^\.include  *<bsd\.port\.(subdir\.|pre\.)?mk>/ || /^\.include  *".*mk\/bsd\.pkg\.(subdir\.)?mk"/ {
+ 	        print "fetch fetch-list extract patch configure build install reinstall deinstall package describe checkpatch checksum makesum" }' \
+ 	     FS=: $file)
+         )
+    _all_labels targets expl 'make target' compadd "$tmp[@]" && return 0
+  fi
+  compset -P 1 '*='
+  _files
+fi
diff --git a/Completion/User/_mh b/Completion/User/_mh
index 67ce49fd2..c1f397744 100644
--- a/Completion/User/_mh
+++ b/Completion/User/_mh
@@ -1,28 +1,36 @@
-#defcomp folder comp inc mark refile repl scan show next prev rmm pick whom mhn mhpath mhpatch
+#compdef folder folders comp inc mark refile repl scan show next prev rmm pick whom mhn mhpath
 
 # Completion for all possible MH commands.
 # Alter the following two to your own mh directory and the directory
 # where standard mh library files live.  (It works anyway, but this
 # will save a little time.)
+
 local mymhdir=~/Mail
 local mhlib=/usr/lib/mh
 
+local prev="$words[CURRENT-1]" expl
+
 # To be on the safe side, check this exists and if not, get it anyway.
 [[ -d $mymhdir ]] || mymhdir=$(mhpath +)
 
-if [[ -iprefix - ]]; then
+if compset -P 1 -; then
   # get list of options, which MH commands can generate themselves
   # awk is just too icky to use for this, sorry.  send me one if
   # you come up with it.
-  compadd -m $($COMMAND -help | perl -ne 'if (/^\s*-\(?(\S+)/) {
-    $n = $1;
-    $n =~ s/\)//g;
-    print $n =~ s/^\[([a-z]+)\]// ? "$n\n$1$n\n" : "$n\n";
-  }')
-  return
-elif [[ -iprefix '+' || -iprefix '@' || -current -1 -draftfolder ]]; then
+  if _wanted options; then
+    _all_labels options expl option \
+        compadd - $($words[1] -help | perl -ne 'if (/^\s*-\(?(\S+)/) {
+            $n = $1;
+            $n =~ s/\)//g;
+            print $n =~ s/^\[([a-z]+)\]// ? "$n\n$1$n\n" : "$n\n";
+          }')
+    return
+  fi
+  return 1
+elif compset -P 1 '[+@]' || [[ "$prev" = -draftfolder ]]; then
   # Complete folder names.
   local mhpath
+
   if [[ $IPREFIX != '@' ]]; then
     [[ $IPREFIX = '+' ]] || IPREFIX=+
     mhpath=$mymhdir
@@ -30,13 +38,12 @@ elif [[ -iprefix '+' || -iprefix '@' || -current -1 -draftfolder ]]; then
     mhpath=$(mhpath)
   fi
 
-  # painless, or what?
-  complist -W mhpath -/
-elif [[ -mcurrent -1 -(editor|(whatnow|rmm|show|more)proc) ]]; then
-  complist -c
-elif [[ -current -1 -file ]]; then
-  complist -f
-elif [[ -mcurrent -1 -(form|audit|filter) ]]; then
+  _wanted files expl 'MH folder' _path_files -W mhpath -/
+elif [[ "$prev" = -(editor|(whatnow|rmm|show|more)proc) ]]; then
+  _command_names -e
+elif [[ "$prev" = -file ]]; then
+  _files
+elif [[ "$prev" = -(form|audit|filter) ]]; then
   # Need some MH template file, which may be in our own MH directory
   # or with the standard library.
   local mhfpath
@@ -44,15 +51,16 @@ elif [[ -mcurrent -1 -(form|audit|filter) ]]; then
   [[ -d $mhlib ]] || { mhlib=$(mhparam mhlproc); mhlib=$mhlib:h; }
   mhfpath=($mymhdir $mhlib)
 
-  complist -W mhfpath -g '*(.)'
-elif [[ -mcurrent -1 -(no|)cc ]]; then
-  compadd -m all to cc me
-elif [[ -mcurrent -1 -[rw]cache ]]; then
-  compadd -m public private never ask
+  _wanted files expl 'MH template file' _files -W mhfpath -g '*(.)'
+elif [[ "$prev" = -(no|)cc ]]; then
+  _wanted -C "$prev" values expl 'CC address' compadd all to cc me
+elif [[ "$prev" = -[rw]cache ]]; then
+  _wanted -C "$prev" values expl cache compadd public private never ask
 else
   # Generate sequences.
-  local foldnam folddir f
-  for f in $argv; do
+  local foldnam folddir f ret
+
+  for f in $words; do
     [[ $f = [@+]* ]] && foldnam=$f
   done
   if [[ $foldnam = '+'* ]]; then
@@ -64,7 +72,14 @@ else
     # leaving foldnam empty works here
   fi
 
-  complist -s '$(mark $foldnam | awk -F: '\''{ print $1 }'\'')'
-  compadd -m reply next cur prev first last all unseen
-  complist -W folddir -g '<->'
+  if _wanted sequences; then
+    while _next_label sequences expl sequence; do
+      compadd "$expl[@]" $(mark $foldnam 2>/dev/null | awk -F: '{ print $1 }') &&
+        ret=0
+      compadd "$expl[@]" reply next cur prev first last all unseen && ret=0
+      _files "$expl[@]" -W folddir -g '<->' && ret=0
+      (( ret )) || return 0
+    done
+  fi
+  return ret
 fi
diff --git a/Completion/User/_nedit b/Completion/User/_nedit
index 1f030e369..a3fcd9785 100644
--- a/Completion/User/_nedit
+++ b/Completion/User/_nedit
@@ -40,10 +40,11 @@ else
     '(-background)-bg[specify background color]:background color:_x_color' \
     '(-fg)-foreground:foreground color:_x_color' \
     '(-foreground)-fg[specify foreground color]:foreground color:_x_color' \
-    '-import[load additional preferences file]:nedit preferences file:_files' \
+    '*-import[load additional preferences file]:nedit preferences file:_files' \
     "$nedit_common[@]"
 fi
 
-[[ $state = lang ]] && _wanted neditlanguages expl 'language mode' &&
-    compadd "$expl[@]" -  ${(f)"$(sed -n \
-      '/^nedit.languageMode/,/^nedit/ s/.*	\([^:]*\).*/\1/p' < ~/.nedit)"}
+[[ $state = lang ]] &&
+    _wanted neditlanguages expl 'language mode' \
+        compadd -  ${(f)"$(sed -n \
+            '/^nedit.languageMode/,/^nedit/ s/.*	\([^:]*\).*/\1/p' < ~/.nedit)"}
diff --git a/Completion/User/_netscape b/Completion/User/_netscape
index f176083d2..b29c27c6c 100644
--- a/Completion/User/_netscape
+++ b/Completion/User/_netscape
@@ -1,8 +1,9 @@
 #compdef netscape
 
-local state
+local curcontext="$curcontext" state line ret=1
+typeset -A opt_args
 
-_x_arguments \
+_x_arguments -C \
   '-xrm:resource:_x_resource' \
   '-help[show usage message]' \
   '-version[show the version number and build date]' \
@@ -21,55 +22,70 @@ _x_arguments \
   -{,no-}{,irix-}session-management \
   -{done-save,ignore}-geometry-prefs \
   -{component-bar,composer,edit,messenger,mail,discussions,news} \
-  '*:location:->urls'
+  '*:location:->urls' && ret=0
+
+[[ "$state" = "urls" ]] &&
+  _files "$@" && return 0
 
-[ "$state" = "urls" ] && _files "$@" && return
 
 # Handle netscape remote commands
-if [ "$state" = "remote" ]; then  
+if [[ "$state" = "remote" ]]; then  
   local -a remote_commands
   remote_commands=(openURL openFile saveAs mailto addBookmark)
 
   [[ $compstate[quoting] = (double|single) ]] && compset -q
   compset -P '*\('
   case $IPREFIX in
-    openURL*|addBookmark* ) state=urls;;
-    openFile* ) _files -W ~;;
-    saveAs* ) 
+    openURL*|addBookmark*) state=urls;;
+    openFile*) _files -W ~;;
+    saveAs*) 
       if compset -P "*,"; then
-        compadd -s")" -M 'm:{a-zA-Z}={A-Za-z}' HTML Text PostScript
+        _wanted types expl 'data type' \
+            compadd -s")" -M 'm:{a-zA-Z}={A-Za-z}' HTML Text PostScript &&
+                ret=0
       else
-        _path_files -W ~
+        _files -W ~ && ret=0
       fi
     ;;
-    mailto* )
+    mailto*)
       compset -P "*,"
       if compset -P '*@'; then
-        _description expl 'remote host name'
-        _hosts "$expl[@]" -q -S,
+        _wanted hosts expl 'remote host name' _hosts -q -S, && ret=0
       else
-        _description expl 'login name'
-        _users "$expl[@]" -q -S@
+        _wanted users expl 'login name' _users -q -S@ && ret=0
       fi
     ;;
-    * )
-      if [ "$QIPREFIX" ]; then
-        compadd -q -S '(' -M 'm:{a-zA-Z}={A-Za-z}' $remote_commands
-      else
-	compadd -s'(' -S '' -M 'm:{a-zA-Z}={A-Za-z}' $remote_commands
+    *)
+      if _wanted commands; then
+        if [[ -z "$QIPREFIX" ]]; then
+	  _all_labels commands expl 'remote commands' \
+  	      compadd  -s'(' -S '' -M 'm:{a-zA-Z}={A-Za-z}' - \
+                      $remote_commands && ret=0
+        else
+	  _all_labels commands expl 'remote commands' \
+              compadd -qS '(' -M 'm:{a-zA-Z}={A-Za-z}' - \
+                      $remote_commands && ret=0
+	fi
       fi
     ;;
   esac
 fi
 
-if [ "$state" = "urls" ]; then
+if [[ "$state" = "urls" ]]; then
   # Complete netscape urls
-  if [[ -prefix about: ]]; then
-    compset -P about:
-    compadd authors blank cache document fonts global hype image-cache \
-        license logo memory-cache mozilla plugins
+  if compset -P about: ; then
+    _wanted values expl 'about what' \
+        compadd authors blank cache document fonts global hype image-cache \
+            license logo memory-cache mozilla plugins && ret=0
   else
-    compadd -S '' about: mocha: javascript:
-    _urls "$@"
+    if _wanted prefixes; then
+      while _next_label prefixes expl 'URL prefix'; do
+        compadd "$expl[@]" -S '' about: mocha: javascript: && ret=0
+        _urls "$@" && ret=0
+	(( ret )) || return 0
+      done
+    fi
   fi
 fi
+
+return ret
diff --git a/Completion/User/_tiff b/Completion/User/_tiff
index bbc331442..8fd008f0f 100644
--- a/Completion/User/_tiff
+++ b/Completion/User/_tiff
@@ -10,21 +10,22 @@ fi
 
 if [[ $# -ne 0 || $+_in_tiff -ne 0 ]]; then
   if (( ! $# )); then
-    _description expl 'picture file'
+    _description files expl 'picture file'
     set -- "$expl[@]"
   fi
-  _path_files "$@" -g "$pat" || _files "$@" -g '*.(#i)tiff'
+  _wanted files expl 'picture file' _path_files "$@" -g "$pat" - ||
+      _files "$@" "$expl[@]" -g '*.(#i)tiff'
   return
 fi
 
 local _in_tiff=yes
 
-local state line ret=1
-typeset -A options
+local curcontext="$curcontext" state line ret=1
+typeset -A opt_args
 
 case "$words[1]" in
 tiff2bw)
-  _arguments \
+  _arguments -C \
     '-c[specify compression scheme]:compression scheme:->compress' \
     '-r[specify rows per strip]:rows per strip:' \
     '-R[specify percentage of red channel]:percentage of red channel:' \
@@ -59,7 +60,7 @@ tiffcmp)
     ':second input TIFF file:_files -g \*.\(\#i\)' && ret=0
   ;;
 tiffcp)
-  _arguments \
+  _arguments -C \
     '-B[write output in bin-endian byte order]' \
     '-c[specify compression scheme]:compression scheme:->compress' \
     '-o[set initial TIFF directory (file offset)]:file offset:' \
@@ -74,7 +75,7 @@ tiffcp)
     '*:input TIFF file:_files -g \*.\(\#i\)' && ret=0
   ;;
 tiffdither)
-  _arguments \
+  _arguments -C \
     '-c[specify compression scheme]:compression scheme:->compress' \
     '-f[specify fill order]:fill order:(lsb2msb msb2lsb)' \
     '-r[specify rows per strip]:rows per strip:' \
@@ -102,7 +103,7 @@ tiffinfo)
     '*:input TIFF file:_files -g \*.\(\#i\)' && ret=0
   ;;
 tiffmedian)
-  _arguments \
+  _arguments -C \
     '-r[specify rows per strip]:rows per strip:' \
     '-C[specify number of colormap entries]:number of colormap entries:' \
     '-c[specify compression scheme]:compression scheme:->compress' \
@@ -135,14 +136,14 @@ fax2tiff)
     ':FAX input file:_files -g \*.\(\#i\)\(g\[34\]\|fax\)' && ret=0
   ;;
 gif2tiff)
-  _arguments \
+  _arguments -C \
     '-r[specify rows per strip]:rows per strip:' \
     '-c[specify compression scheme]:compression scheme:->compress' \
     ':input GIF file:_files -g \*.\(\#i\)gif' \
     ':output file:_files -g \*.\(\#i\)tiff' && ret=0
   ;;
 ppm2tiff)
-  _arguments \
+  _arguments -C \
     '-r[specify rows per strip]:rows per strip:' \
     '-c[specify compression scheme]:compression scheme:->compress' \
     '-R[specify resolution]:resolution:' \
@@ -150,14 +151,14 @@ ppm2tiff)
     ':output file:_files -g \*.\(\#i\)tiff' && ret=0
   ;;
 ras2tiff)
-  _arguments \
+  _arguments -C \
     '-r[specify rows per strip]:rows per strip:' \
     '-c[specify compression scheme]:compression scheme:->compress' \
     ':input raster image file:_files -g \*.\(\#i\)ras\(\|t\)' \
     ':output file:_files -g \*.\(\#i\)tiff' && ret=0
   ;;
 pal2rgb)
-  _arguments \
+  _arguments -C \
     '-C[specify number of bits for colormap entries]:bits for colormap entries:(8 16)' \
     '-p[set sample packing]:sample packing:(contig separate)' \
     '-c[specify compression scheme]:compression scheme:->compress' \
@@ -166,7 +167,7 @@ pal2rgb)
     ':output file:_files -g \*.\(\#i\)tiff' && ret=0
   ;;
 *)
-  _description expl 'picture file'
+  _description files expl 'picture file'
   _files "$expl[@]" -g "$pat" && ret=0
 esac
 
@@ -194,9 +195,13 @@ if [[ -n "$state" ]]; then
       ;;
     esac
   else
-    _description expl 'compression scheme'
-    compadd "$expl[@]" - none g4 packbits && ret=0
-    compadd "$expl[@]" -qS: - lzw zip jpeg g3 && ret=0
+    if _wanted values; then
+      while _next_label values expl 'compression scheme'; do
+        compadd "$expl[@]" - none g4 packbits && ret=0
+        compadd "$expl[@]" -qS: - lzw zip jpeg g3 && ret=0
+	(( ret )) || return 0
+      done
+    fi
   fi
 fi
 
diff --git a/Completion/User/_urls b/Completion/User/_urls
index 19f7eea3a..03e8902cb 100644
--- a/Completion/User/_urls
+++ b/Completion/User/_urls
@@ -1,65 +1,155 @@
-#autoload
+#compdef curl
 
 # Usage: _urls [-f]
 # Options:
-#  -f : complete files.
-
-# To complete URLs, you must make a URL database locally such as:
+#  -f : complete files first.
+#
+# Configuration styles used:
+#
+#  path
+#    The path to a directory containing a URL database, such as:
+#
+#      % cd ~/.zsh/urls
+#      % find . -ls
+#      ... drwxr-xr-x ... 512 Sep  3 02:46 .
+#      ... drwxr-xr-x ... 512 Sep  3 02:48 ./http
+#      ... drwxr-xr-x ... 512 Sep  3 02:52 ./http/www.zsh.org
+#      ... drwxr-xr-x ... 512 Sep  3 03:01 ./http/www.zsh.org/mla
+#      ... drwxr-xr-x ... 512 Sep  3 03:01 ./http/www.zsh.org/mla/workers
+#      ... drwxr-xr-x ... 512 Sep  3 03:01 ./http/www.zsh.org/mla/workers/1999
+#      ... -rw-r--r-- ...   0 Sep  3 03:01 ./http/www.zsh.org/mla/workers/1999/index.html
+#      ... drwxr-xr-x ... 512 Sep  3 02:48 ./http/sunsite.auc.dk
+#      ... drwxr-xr-x ... 512 Sep  3 02:48 ./http/sunsite.auc.dk/zsh
+#      ... drwxr-xr-x ... 512 Sep  3 02:47 ./bookmark
+#      ... drwxr-xr-x ... 512 Sep  3 02:48 ./bookmark/zsh
+#      ... -rw-r--r-- ...  27 Sep  3 02:47 ./bookmark/zsh/home
+#      ... -rw-r--r-- ...  20 Sep  3 02:48 ./bookmark/zsh/meta
+#      % cat bookmark/zsh/home 
+#      http://sunsite.auc.dk/zsh/
+#      % cat bookmark/zsh/meta
+#      http://www.zsh.org/
 #
-# % cd ~/.zsh/urls
-# % find . -ls
-# ... drwxr-xr-x ... 512 Sep  3 02:46 .
-# ... drwxr-xr-x ... 512 Sep  3 02:48 ./http
-# ... drwxr-xr-x ... 512 Sep  3 02:52 ./http/www.zsh.org
-# ... drwxr-xr-x ... 512 Sep  3 03:01 ./http/www.zsh.org/mla
-# ... drwxr-xr-x ... 512 Sep  3 03:01 ./http/www.zsh.org/mla/workers
-# ... drwxr-xr-x ... 512 Sep  3 03:01 ./http/www.zsh.org/mla/workers/1999
-# ... -rw-r--r-- ...   0 Sep  3 03:01 ./http/www.zsh.org/mla/workers/1999/index.html
-# ... drwxr-xr-x ... 512 Sep  3 02:48 ./http/sunsite.auc.dk
-# ... drwxr-xr-x ... 512 Sep  3 02:48 ./http/sunsite.auc.dk/zsh
-# ... drwxr-xr-x ... 512 Sep  3 02:47 ./bookmark
-# ... drwxr-xr-x ... 512 Sep  3 02:48 ./bookmark/zsh
-# ... -rw-r--r-- ...  27 Sep  3 02:47 ./bookmark/zsh/home
-# ... -rw-r--r-- ...  20 Sep  3 02:48 ./bookmark/zsh/meta
+#  local
+#    Specify a local web server as an array with three elements:
+#      <hostname> <doc root> <user area>
+#    where hostname is the name of the web server, doc root is the path to
+#    the default web pages for the server and user area is the directory
+#    name used by a user placing web pages within their home area.
+#    E.g.:
+#      zstyle ':completion:*:urls' local www /usr/local/apache/htdocs public_html
 
-local ipre scheme dirs files
+local ipre scheme host user uhosts ret=1 expl
+local urls_path localhttp
+zstyle -s ":completion:${curcontext}:urls" path urls_path ||
+    urls_path="${ZDOTDIR:-$HOME}/.zsh/urls"
+zstyle -a ":completion:${curcontext}:urls" local localhttp
+local localhttp_servername="$localhttp[1]"
+local localhttp_documentroot="$localhttp[2]"
+local localhttp_userdir="$localhttp[3]"
 
 if [[ "$1" = -f ]]; then
   shift
-  _files "$@" && return
-fi
-
-if [[ -z "$compconfig[_urls_dir]" ]]; then
-  compconfig[_urls_dir]=${ZDOTDIR:-$HOME}/.zsh/urls
+  _wanted -C -f files && _files "$@" && return
 fi
 
 ipre="$IPREFIX"
 
-if [[ -prefix [-+.a-z0-9]#: ]]; then
-  scheme="${PREFIX%%:*}"
-  compset -P "[-+.a-z0-9]#:"
-else
-  compadd -S '' http:// ftp:// bookmark:
-  return
+if ! compset -P '(#b)([-+.a-z0-9]#):' && _wanted -C argument prefixes; then
+  while _next_label prefixes expl 'URL prefix' "$@"; do
+    [[ -d $urls_path/bookmark ]] &&
+      compadd "$expl[@]" -S '' bookmark: && ret=0
+    compadd "$expl[@]" -S '' file: ftp:// gopher:// http:// && ret=0
+    (( ret )) || return 0
+  done
+  return ret
 fi
+scheme="$match[1]"
 
 case "$scheme" in
-  http) compset -P // || { compadd "$@" -S '' //; return };;
-  ftp) compset -P // || { compadd "$@" -S '' //; return };;
+  http|ftp|gopher)
+    if ! compset -P //; then
+      _wanted -C "$scheme" prefixes expl 'end of prefix' compadd "$@" -S '' //
+      return
+    fi
+  ;;
+  file)
+    if ! compset -P //; then
+      _wanted -C file files || return 1
+
+      while _next_label files expl 'local file' "$@"; do
+        if [[ -prefix / ]]; then
+	  _path_files "$expl[@]" -S '' -g '*(^/)' && ret=0
+	  _path_files "$expl[@]" -S/ -r '/' -/ && ret=0
+        elif [[ -z "$PREFIX" ]]; then
+	  compadd "$expl[@]" -S '/' -r '/' - "${PWD%/}" && ret=0
+        fi
+	(( ret )) || return 0
+      done
+      return ret
+    fi
+  ;;
+  bookmark)
+    if [[ -f "$urls_path/$scheme/${(Q)PREFIX}${(Q)SUFFIX}" &&
+	  -s "$urls_path/$scheme/${(Q)PREFIX}${(Q)SUFFIX}" ]]; then
+      _wanted -C bookmark bookmarks expl bookmarks \
+          compadd "$@" -U - \
+              "$ipre$(<"$urls_path/$scheme/${(Q)PREFIX}${(Q)SUFFIX}")" && ret=0
+    else
+      if _wanted -C bookmark files; then
+        while _next_label files expl 'bookmark'; do
+          _path_files -W "$urls_path/$scheme" "$expl[@]" -S '' -g '*(^/)' && 
+              ret=0
+          _path_files -W "$urls_path/$scheme" -S/ -r '/' -/ && ret=0
+          (( ret )) || return 0
+        done
+      fi
+    fi
+    return ret
+  ;;
 esac
 
-if [[ "$scheme" = bookmark &&
-      -f "$compconfig[_urls_dir]/$scheme/$PREFIX$SUFFIX" &&
-      -s "$compconfig[_urls_dir]/$scheme/$PREFIX$SUFFIX" ]]; then
-  compadd "$@" -QU -- "$ipre$(<"$compconfig[_urls_dir]/$scheme/$PREFIX$SUFFIX")"
-else
-  dirs=($compconfig[_urls_dir]/$scheme/$PREFIX*$SUFFIX(/:t))
-  files=($compconfig[_urls_dir]/$scheme/$PREFIX*$SUFFIX(.:t))
-  compset -P '*/'
-  compadd "$@" -Q -S '/' - $dirs
-  if [[ "$scheme" = bookmark ]]; then
-    compadd "$@" -QS '' - $files
+# Complete hosts
+if ! compset -P '(#b)([^/]#)/' && _wanted hosts; then
+  uhosts=($urls_path/$scheme/$PREFIX*$SUFFIX(/:t))
+
+  while _next_label hosts expl host "$@"; do
+    (( $#uhosts )) || _hosts -S/ && ret=0
+    [[ "$scheme" = http ]] && uhosts=($uhosts $localhttp_servername)
+    compadd "$expl[@]" -S/ - $uhosts && ret=0
+    (( ret )) || return 0
+  done
+  return ret
+fi
+host="$match[1]"
+
+# Complete part after hostname
+
+_wanted -C local files || return 1
+
+if [[ "$localhttp_servername" = "$host" ]]; then
+  if compset -P \~; then
+    if ! compset -P '(#b)([^/]#)/'; then
+      _users -S/
+      return
+    fi
+    user="$match[1]"
+    while _next_label files expl 'local file'; do
+      _path_files "$expl[@]" -W ~$user/$localhttp_userdir -g '*(^/)' && ret=0
+      _path_files "$expl[@]" -W ~$user/$localhttp_userdir -S/ -r '/' -/ && ret=0
+      (( ret )) || return 0
+    done
   else
-    compadd "$@" -Q - $files
+    while _next_label files expl 'local file'; do
+      _path_files "$expl[@]" -W $localhttp_documentroot -g '*(^/)' && ret=0
+      _path_files "$expl[@]" -W $localhttp_documentroot -S/ -r '/' -/ && ret=0
+      (( ret )) || return 0
+    done
   fi
+else
+  while _next_label files expl 'local file'; do
+    _path_files "$expl[@]" -W $urls_path/$scheme/$host -g '*(^/)' && ret=0
+    _path_files "$expl[@]" -W $urls_path/$scheme/$host -S/ -r '/' -/ && ret=0
+    (( ret )) || return 0
+  done
 fi
+return $ret
diff --git a/Completion/User/_users b/Completion/User/_users
index fc1e87e52..d04731af9 100644
--- a/Completion/User/_users
+++ b/Completion/User/_users
@@ -1,6 +1,10 @@
-#autoload
+#compdef last passwd groups
 
-local expl
+local expl users
 
-_description expl user
-compgen "$@" "$expl[@]" -u
+_wanted users || return 1
+
+zstyle -a ":completion:${curcontext}:" users users &&
+    _all_labels users expl user compadd "$@" - "$users[@]" && return 0
+
+_all_labels users expl user compadd "$@" - "${(@k)userdirs}"
diff --git a/Completion/User/_users_on b/Completion/User/_users_on
index 920688089..b19cff6e7 100644
--- a/Completion/User/_users_on
+++ b/Completion/User/_users_on
@@ -1,10 +1,12 @@
-#autoload write
+#compdef write
 
 local expl
 
+_wanted users || return 1
+
 if which users >/dev/null; then
-  _description expl users logged on
-  compadd "$@" "$expl[@]" - $(users) && return 0
+  _all_labels users expl 'users logged on' \
+      compadd "$@" - $(_call users users) && return 0
 else
   # Other methods of finding out users logged on should be added here
   return 1
diff --git a/Completion/X/_x_colormapid b/Completion/X/_x_colormapid
index 4fe6aac42..3c637c1d9 100644
--- a/Completion/X/_x_colormapid
+++ b/Completion/X/_x_colormapid
@@ -2,7 +2,7 @@
 
 local expl list desc
 
-_wanted colormapids expl 'colormap id' || return 1
+_wanted colormapids || return 1
 
 list=(${(f)"$(xprop -root -f RGB_COLOR_MAP 32xcccccccxx ': $0\n'|awk -F'[ ():]' '/^[a-zA-Z_]+\(RGB_COLOR_MAP\)/ {print $5, "--", $1}')"})
 
@@ -12,4 +12,5 @@ else
   desc=()
 fi
 
-compadd "$expl[@]" "$@" "$desc[@]" - "${(@)list%% *}" 
+_all_labels colormapids expl 'colormap id' \
+    compadd "$@" "$desc[@]" - "${(@)list%% *}" 
diff --git a/Completion/X/_x_extension b/Completion/X/_x_extension
index 967938e28..11e53fa6c 100644
--- a/Completion/X/_x_extension
+++ b/Completion/X/_x_extension
@@ -2,16 +2,18 @@
 
 local expl
 
-(( $+_xe_cache )) || _xe_cache=( "${(@)${(@f)$(xdpyinfo)}[(r)number of extensions:*,-1][2,(r)default screen number:*][1,-2]//[      ]}" )
+_wanted extensions || return 1
 
-_description expl 'X extension'
+(( $+_xe_cache )) || _xe_cache=( "${(@)${(@f)$(xdpyinfo)}[(r)number of extensions:*,-1][2,(r)default screen number:*][1,-2]//[      ]}" )
 
 if [[ "$1" = -a ]]; then
   shift
 
-  compadd "$@" "$expl[@]" -M 'm:{a-z}={A-Z} r:|-=* r:|=*' - all "$_xe_cache[@]"
+  _all_labels extensions expl 'X extensions' \
+      compadd "$@" -M 'm:{a-z}={A-Z} r:|-=* r:|=*' - all "$_xe_cache[@]"
 else
   [[ "$1" = - ]] && shift
 
-  compadd "$@" "$expl[@]" -M 'm:{a-z}={A-Z} r:|-=* r:|=*' - "$_xe_cache[@]"
+  _all_labels extensions expl 'X extensions' \
+      compadd "$@" -M 'm:{a-z}={A-Z} r:|-=* r:|=*' - "$_xe_cache[@]"
 fi
diff --git a/Completion/X/_x_font b/Completion/X/_x_font
index e0acb4014..43a713b34 100644
--- a/Completion/X/_x_font
+++ b/Completion/X/_x_font
@@ -1,3 +1,16 @@
 #autoload
 
-_message 'font'
+local expl
+
+_wanted fonts || return 1
+
+# This *has* to be improved some day...
+
+if (( ! $+_font_cache )); then
+  typeset -gU _font_cache
+
+ _font_cache=( "${(@)^${(@f)$(_call fonts xlsfonts)}%%--*}--" )
+fi
+
+_all_labels fonts expl font \
+    compadd -M 'r:|-=* r:|=*' "$@" -S '' - "$_font_cache[@]"
diff --git a/Completion/X/_x_keysym b/Completion/X/_x_keysym
index 6b031014a..f50762f7e 100644
--- a/Completion/X/_x_keysym
+++ b/Completion/X/_x_keysym
@@ -2,6 +2,8 @@
 
 local expl
 
+_wanted keysyms || return 1
+
 if (( ! $+_keysym_cache )); then
   local file
 
@@ -16,5 +18,5 @@ if (( ! $+_keysym_cache )); then
   fi
 fi
 
-_description expl 'key symbol'
-compadd "$@" "$expl[@]" -M 'm:{a-z}={A-Z} r:|-=* r:|=*' - $_keysym_cache
+_all_labels keysyms expl 'key symbol' \
+    compadd "$@" -M 'm:{a-z}={A-Z} r:|-=* r:|=*' - $_keysym_cache
diff --git a/Completion/X/_x_window b/Completion/X/_x_window
index 118c7f131..1862db9a7 100644
--- a/Completion/X/_x_window
+++ b/Completion/X/_x_window
@@ -1,19 +1,18 @@
 #autoload
 
-setopt localoptions extendedglob
-
 local list expl
 
-list=( "${(@)${(M@)${(@f)$(xwininfo -root -tree)}:#[ 	]#0x[0-9a-f]# \"*}##[ 	]#}" )
+_wanted windows || return 1
+
+list=( "${(@)${(M@)${(@f)$(_call windows xwininfo -root -tree)}:#[ 	]#0x[0-9a-f]# \"*}##[ 	]#}" )
 
 if [[ "$1" = -n ]]; then
   shift
 
-  _description expl 'window name'
-  compadd "$@" "$expl[@]" -d list - "${(@)${(@)list#*\"}%%\"*}"
+  _all_labels windows expl 'window name' \
+      compadd "$@" -d list - "${(@)${(@)list#*\"}%%\"*}"
 else
   [[ "$1" = - ]] && shift
 
-  _description expl 'window ID'
-  compadd "$@" "$expl[@]" -d list - "${(@)list%% *}"
+  _all_labels windows expl 'window ID' compadd "$@" -d list - "${(@)list%% *}"
 fi
diff --git a/Completion/X/_xmodmap b/Completion/X/_xmodmap
index 0f6514eb6..1cd461d4c 100644
--- a/Completion/X/_xmodmap
+++ b/Completion/X/_xmodmap
@@ -1,11 +1,9 @@
 #compdef xmodmap
 
-setopt localoptions extendedglob
+local curcontext="$curcontext" state line ret=1
+typeset -A opt_args
 
-local state line ret=1
-typeset -A options
-
-_x_arguments \
+_x_arguments -C \
   -{help,grammar,verbose,quiet} \
   '-n[only show what would be done]' \
   '*-e[specify expression]:expression:->expr' \
@@ -57,7 +55,7 @@ if [[ -n "$state" ]]; then
     pointer*)
       if compset -P '*=[ 	]#'; then
         compset -P '*[ 	]'
-        _description expl 'button code'
+        _description values expl 'button code'
         compadd "$expl[@]" -qS ' ' 1 2 3 4 5 default
         return
       else
@@ -84,9 +82,13 @@ if [[ -n "$state" ]]; then
     [[ "$what" = *ksym* ]] && _x_keysym "$suf[@]" && ret=0
 
   else
-    _description expl command
-    compadd "$expl[@]" -S ' ' keycode keysym clear add remove && ret=0
-    compadd "$expl[@]" -S ' = ' pointer && ret=0
+    if _wanted commands; then
+      while _next_label commands expl command; do
+        compadd "$expl[@]" -S ' ' keycode keysym clear add remove && ret=0
+        compadd "$expl[@]" -S ' = ' pointer && ret=0
+        (( ret )) || return 0
+      done
+    fi
   fi
 fi
 
diff --git a/Completion/X/_xutils b/Completion/X/_xutils
index 1818b447f..4eea8ded1 100644
--- a/Completion/X/_xutils
+++ b/Completion/X/_xutils
@@ -8,7 +8,7 @@ xdpyinfo)
   ;;
 xwininfo)
   _x_arguments \
-    -{help,int,stats,bits,events,size,wm,shape,frame,all,english,metric} \
+    -{help,int,children,tree,stats,bits,events,size,wm,shape,frame,all,english,metric} \
     '(-id -name)-root' \
     '(-id -root)-name:name: _x_window -n' \
     '(-name -root)-id:id: _x_window'
@@ -46,12 +46,33 @@ xev)
     '-rv'
   ;;
 xhost)
-  local expl type ret=1
+  local expl type ret=1 tmp
 
   if compset -P '-'; then
-    _description expl 'disallow access'
-    compadd "$expl[@]" -M 'm:{a-z}={A-Z} r:|[:.]=* r:|=*' - \
-        "${${(@M)${(@f)$(xhost)}[2,-1]:#LOCAL:*}#INET:}"
+    tmp=(${(f)"$(xhost)"})
+    shift tmp
+    tmp=(${tmp:#LOCAL:|<*>})
+    if [[ "$tmp" = *:* ]]; then
+      if compset -P '(#b)(*):'; then
+	type="$match[1]"
+	_wanted displays &&
+            while _next_label displays expl 'disallow access'; do
+	      { compadd "$expl[@]" -M 'm:{a-z}={A-Z} r:|[:.]=* r:|=*' - \
+		        ${${(M)tmp:#(#i)$type:*}#(#i)$type:} ||
+	            _hosts "$expl[@]" } && return 0
+	    done
+      else
+	_alternative \
+	    'types:name family:compadd -S: ${(L)tmp%%:*}' \
+	    'hosts:host:compadd ${(@)tmp#*:}' && ret=0
+      fi
+    else
+      _wanted displays &&
+          while _next_label displays expl 'disallow access'; do
+	    { compadd "$expl[@]" -M 'm:{a-z}={A-Z} r:|[:.]=* r:|=*' - $tmp ||
+              _hosts "$expl[@]" } && return 0
+          done
+    fi
   else
     compset -P +
 
@@ -66,9 +87,9 @@ xhost)
       krb)  _message 'Kerberos V5 principal';;
       esac
     else
-      _description expl 'name family'
-      compadd -S: - inet dnet nis krb && ret=0
-      _hosts && ret=0
+      _alternative \
+          'types:name family:compadd -S: - inet dnet nis krb' \
+	  'hosts:: _hosts' && ret=0
     fi
     return ret
   fi
@@ -120,7 +141,7 @@ xrdb)
     '(-global -all -screens)-screen' \
     '(-global -all -screen)-screens' \
     '-n[only display on stdout]' \
-    '(-nocpp)-cpp:preprocessor program:_files -g \*\(\*\)' \
+    '(-nocpp)-cpp:preprocessor program:_files -g \*\(-\*\)' \
     '(-cpp)-nocpp' \
     '(-load -override -merge -remove)-query' \
     '(-query -override -merge -remove)-load' \
@@ -131,6 +152,7 @@ xrdb)
     '-backup:backup extension:' \
     '*-D-:symbol to define:' \
     '*-U-:symbol to undefine:' \
-    '*-I-:include directory:_files -/'
+    '*-I-:include directory:_files -/' \
+    '*:defaults file:_files'
   ;;
 esac
diff --git a/Completion/X/_xwit b/Completion/X/_xwit
index e86443a32..998627869 100644
--- a/Completion/X/_xwit
+++ b/Completion/X/_xwit
@@ -16,8 +16,8 @@ _xwit_guard () {
 
 _xwit_compopts () {
   local expl
-  _description options expl option
-  compadd "$expl[@]" - ${(k)no[(R)*~0]} || compadd "$expl[@]" - ${(k)no}
+  _wanted options expl option compadd - ${(k)no[(R)*~0]} ||
+      _all_labels options expl option compadd - ${(k)no}
 }
 
 _regex_arguments _xwit_parse \
@@ -39,8 +39,8 @@ _regex_arguments _xwit_parse \
     \| "/iconmove$nul/" "$guard" "/$word/" ":_message x" "/$word/" ":_message y" \
     \| "/id$nul/" "$guard" "/$word/" ":_x_window" \
     \| "/(no|)keyrepeat$nul/" "$guard" \
-        \( "/[0-9]##$nul/" ":_message keycode" \
-	  \( "/-$nul/" "/[0-9]##$nul/" ":_message 'last keycode'" \| \) \) \# \
+        \( "/[0-9]##$nul/" ":[[ -prefix [0-9]# ]] && _message keycode" \
+	  \( "/-$nul/" "/[0-9]##$nul/" ":[[ -prefix [0-9]# ]] && _message 'last keycode'" \| \) \) \# \
     \| "/names$nul/" "$guard" "/$word/" ":_x_window -n" \# \
     \| "/[]/" ':_xwit_compopts' \
     \) \