summary refs log tree commit diff
path: root/Completion/Core
diff options
context:
space:
mode:
Diffstat (limited to 'Completion/Core')
-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
25 files changed, 1866 insertions, 976 deletions
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