about summary refs log tree commit diff
path: root/Completion
diff options
context:
space:
mode:
authorTanaka Akira <akr@users.sourceforge.net>1999-04-15 18:18:42 +0000
committerTanaka Akira <akr@users.sourceforge.net>1999-04-15 18:18:42 +0000
commit7a0415cfd70a02b2280d27556c6c54cef1c86e1a (patch)
tree37a88a1c4611ee37f2a3209873fc9a34a2624587 /Completion
parent904b939cbd81a542303da2c58288b95b153106f5 (diff)
downloadzsh-7a0415cfd70a02b2280d27556c6c54cef1c86e1a.tar.gz
zsh-7a0415cfd70a02b2280d27556c6c54cef1c86e1a.tar.xz
zsh-7a0415cfd70a02b2280d27556c6c54cef1c86e1a.zip
zsh-3.1.5-pws-11 zsh-3.1.5-pws-11
Diffstat (limited to 'Completion')
-rw-r--r--Completion/Base/_brace_parameter5
-rw-r--r--Completion/Base/_command_names6
-rw-r--r--Completion/Base/_condition10
-rw-r--r--Completion/Base/_default3
-rw-r--r--Completion/Base/_equal3
-rw-r--r--Completion/Base/_match_pattern6
-rw-r--r--Completion/Base/_match_test8
-rw-r--r--Completion/Base/_parameter3
-rw-r--r--Completion/Base/_precommand5
-rw-r--r--Completion/Base/_subscript5
-rw-r--r--Completion/Base/_tilde10
-rw-r--r--Completion/Base/_vars2
-rw-r--r--Completion/Builtins/_aliases2
-rw-r--r--Completion/Builtins/_arrays2
-rw-r--r--Completion/Builtins/_autoload2
-rw-r--r--Completion/Builtins/_bg_jobs2
-rw-r--r--Completion/Builtins/_bindkey6
-rw-r--r--Completion/Builtins/_builtin8
-rw-r--r--Completion/Builtins/_cd63
-rw-r--r--Completion/Builtins/_command6
-rw-r--r--Completion/Builtins/_disable10
-rw-r--r--Completion/Builtins/_echotc2
-rw-r--r--Completion/Builtins/_enable10
-rw-r--r--Completion/Builtins/_fc8
-rw-r--r--Completion/Builtins/_functions2
-rw-r--r--Completion/Builtins/_hash6
-rw-r--r--Completion/Builtins/_jobs2
-rw-r--r--Completion/Builtins/_kill6
-rw-r--r--Completion/Builtins/_limits2
-rw-r--r--Completion/Builtins/_sched2
-rw-r--r--Completion/Builtins/_set10
-rw-r--r--Completion/Builtins/_setopt7
-rw-r--r--Completion/Builtins/_source4
-rw-r--r--Completion/Builtins/_trap6
-rw-r--r--Completion/Builtins/_unhash10
-rw-r--r--Completion/Builtins/_unsetopt7
-rw-r--r--Completion/Builtins/_vars_eq2
-rw-r--r--Completion/Builtins/_wait4
-rw-r--r--Completion/Builtins/_which2
-rw-r--r--Completion/Builtins/_zftp14
-rw-r--r--Completion/Builtins/_zle6
-rw-r--r--Completion/Builtins/_zmodload12
-rw-r--r--Completion/Commands/_correct_filename6
-rw-r--r--Completion/Commands/_most_recent_file24
-rw-r--r--Completion/Core/_comp_parts25
-rw-r--r--Completion/Core/_compalso6
-rw-r--r--Completion/Core/_files7
-rw-r--r--Completion/Core/_main_complete219
-rw-r--r--Completion/Core/_multi_parts201
-rw-r--r--Completion/Core/_normal30
-rw-r--r--Completion/Core/_path_files110
-rw-r--r--Completion/README31
-rw-r--r--Completion/User/_a2ps8
-rw-r--r--Completion/User/_configure29
-rw-r--r--Completion/User/_dd4
-rw-r--r--Completion/User/_find24
-rw-r--r--Completion/User/_hosts2
-rw-r--r--Completion/User/_make2
-rw-r--r--Completion/User/_man6
-rw-r--r--Completion/User/_mh36
-rw-r--r--Completion/User/_rcs8
-rw-r--r--Completion/User/_rlogin10
-rw-r--r--Completion/User/_stty6
-rw-r--r--Completion/User/_tar68
-rw-r--r--Completion/User/_x_options2
65 files changed, 892 insertions, 263 deletions
diff --git a/Completion/Base/_brace_parameter b/Completion/Base/_brace_parameter
new file mode 100644
index 000000000..092376e78
--- /dev/null
+++ b/Completion/Base/_brace_parameter
@@ -0,0 +1,5 @@
+#defcomp -brace-parameter-
+
+# Simple but without spiffy suffix handling: compgen -v -S '} '
+
+compadd -S '} ' -r '-:?#%+=[/'  - "${(@)${${${(f)$(typeset)}%%\=*}##* }:gs/'//}"
diff --git a/Completion/Base/_command_names b/Completion/Base/_command_names
index d3b8a109a..eab314dfa 100644
--- a/Completion/Base/_command_names
+++ b/Completion/Base/_command_names
@@ -1,3 +1,7 @@
 #defcomp -command-
 
-complist -c
+local nm=$compstate[nmatches]
+
+compgen -c
+
+[[ nm -eq compstate[nmatches] ]] && _path_files -/g "*(*)"
diff --git a/Completion/Base/_condition b/Completion/Base/_condition
index 3e45e1b8f..fb6b98b1b 100644
--- a/Completion/Base/_condition
+++ b/Completion/Base/_condition
@@ -1,10 +1,12 @@
 #defcomp -condition-
 
-if [[ -current -1 -o ]]; then
-  complist -o -M 'L:|[nN][oO]= M:_= M:{A-Z}={a-z}'
-elif [[ -current -1 -nt || -current -1 -ot || -current -1 -ef ]]; then
+local prev="$words[CURRENT-1]"
+
+if [[ "$prev" = -o ]]; then
+  compgen -o -M 'L:|[nN][oO]= M:_= M:{A-Z}={a-z}'
+elif [[ "$prev" = -([no]t|ef) ]]; then
   _files
 else
   _files
-  complist -v
+  compgen -v
 fi
diff --git a/Completion/Base/_default b/Completion/Base/_default
index 8bcf14f6a..569bd6382 100644
--- a/Completion/Base/_default
+++ b/Completion/Base/_default
@@ -6,7 +6,8 @@
 # immediatly. If you want to use new style completion anyway, remove the
 # `|| return'. Also, you may want to use new style completion if the 
 # `compctl' didn't produce any matches. In that case remove the `|| return'
-# and at the line `[[ -nmatches 0 ]] || return' after `compcall'.
+# and insert the line `[[ compstate[nmatches] -eq 0 ]] || return' after
+# `compcall'.
 
 compcall || return
 
diff --git a/Completion/Base/_equal b/Completion/Base/_equal
new file mode 100644
index 000000000..f407014fe
--- /dev/null
+++ b/Completion/Base/_equal
@@ -0,0 +1,3 @@
+#defcomp -equal-
+
+compgen -am
diff --git a/Completion/Base/_match_pattern b/Completion/Base/_match_pattern
index c5debc0b9..3df115d5b 100644
--- a/Completion/Base/_match_pattern
+++ b/Completion/Base/_match_pattern
@@ -10,7 +10,7 @@
 # the match specs currently in use do.
 # In the calling function this pattern may be changed again or used only 
 # in parts. The second parameter whose name is given as the third argument
-# allows to give pattern flags liek `(#l)' that are to be used whenever
+# allows to give pattern flags like `(#l)' that are to be used whenever
 # matching is done.
 #
 # As an example, if you have global match specifications like:
@@ -20,12 +20,12 @@
 # This function would look like:
 #
 #   eval "${3}='(#l)'"
-#   [[ MATCHER -eq 2 ]] && eval "$1='${(P)2:gs/./*./:gs/-/*-/}'"
+#   [[ compstate[matcher] -eq 2 ]] && eval "$2='${(P)2:gs/./*./:gs/-/*-/}'"
 #
 # The first line makes sure that matching is done case-insensitive as
 # specified by `m:{a-z}={A-Z}'. The second line replaces dots and hyphens
 # in the given string by patterns matching any characters before them,
 # like the `r:|[.-]=* r:|=*'. To make this work, the function `_match_test'
-# would have to be changed to `(( MATCHERS <= 2 ))'
+# would have to be changed to `(( compstate[matcher] <= 2 ))'
 #
 # The default implementation of this function is empty.
diff --git a/Completion/Base/_match_test b/Completion/Base/_match_test
index e8b6e6424..7db521e81 100644
--- a/Completion/Base/_match_test
+++ b/Completion/Base/_match_test
@@ -1,9 +1,9 @@
 #autoload
 
 # This function is called at the beginning of functions that do matching in
-# shell code. It should test the value of the `MATCHER' special parameter
-# and return non-zero if the calling function should try to generate matches
-# for the global match specification in use.
+# shell code. It should test the value of `compstate[matcher]' and return
+# non-zero if the calling function should try to generate matches for the
+# global match specification in use.
 #
 # This function gets one argument, the name of the function calling it.
 #
@@ -12,4 +12,4 @@
 # match specifications and modify the function `_match_pattern' to build the
 # pattern to use in the calling function.
 
-(( MATCHER == 1 ))
+(( compstate[matcher] <= 1 ))
diff --git a/Completion/Base/_parameter b/Completion/Base/_parameter
new file mode 100644
index 000000000..2bd66ec93
--- /dev/null
+++ b/Completion/Base/_parameter
@@ -0,0 +1,3 @@
+#defcomp -parameter-
+
+compgen -v
diff --git a/Completion/Base/_precommand b/Completion/Base/_precommand
index 2cf661147..c13cd7465 100644
--- a/Completion/Base/_precommand
+++ b/Completion/Base/_precommand
@@ -1,5 +1,6 @@
 #defcomp - nohup nice eval time rusage noglob nocorrect exec
 
-[[ -position 1 -1 ]]
+shift words
+(( CURRENT-- ))
 
-_normal "$@"
+_normal
diff --git a/Completion/Base/_subscript b/Completion/Base/_subscript
index 2b827a117..d50fd8335 100644
--- a/Completion/Base/_subscript
+++ b/Completion/Base/_subscript
@@ -1,4 +1,5 @@
 #defcomp -subscript-
 
-_compalso -math- "$@"
-[[ ${(Pt)${COMMAND}} = assoc* ]] && complist -k "( ${(kP)${COMMAND}} )"
+_compalso -math-
+[[ ${(Pt)${compstate[parameter]}} = assoc* ]] &&
+    compgen -k "( ${(kP)${compstate[parameter]}} )"
diff --git a/Completion/Base/_tilde b/Completion/Base/_tilde
new file mode 100644
index 000000000..aef575e19
--- /dev/null
+++ b/Completion/Base/_tilde
@@ -0,0 +1,10 @@
+#defcomp -tilde-
+
+# We use all named directories and user names here. If this is too slow
+# for you or if there are too many of them, you may want to use
+# `compgen -k friends -qS/' or something like that. To get all user names
+# if there are no matches in the `friends' array, add
+#   `(( compstate[nmatches] )) || compgen -nu -qS/'
+# below that.
+
+compgen -nu -qS/
diff --git a/Completion/Base/_vars b/Completion/Base/_vars
index 7153b6f38..92de51e1f 100644
--- a/Completion/Base/_vars
+++ b/Completion/Base/_vars
@@ -1,3 +1,3 @@
 #defcomp -math- getopts read unset vared
 
-complist -v
+compgen -v
diff --git a/Completion/Builtins/_aliases b/Completion/Builtins/_aliases
index 1038a726e..2ccf18439 100644
--- a/Completion/Builtins/_aliases
+++ b/Completion/Builtins/_aliases
@@ -1,3 +1,3 @@
 #defcomp unalias
 
-complist -a
+compgen -a
diff --git a/Completion/Builtins/_arrays b/Completion/Builtins/_arrays
index cbeac7118..94401f28a 100644
--- a/Completion/Builtins/_arrays
+++ b/Completion/Builtins/_arrays
@@ -1,3 +1,3 @@
 #defcomp shift
 
-complist -A
+compgen -A
diff --git a/Completion/Builtins/_autoload b/Completion/Builtins/_autoload
index 4f506baeb..d1462e09a 100644
--- a/Completion/Builtins/_autoload
+++ b/Completion/Builtins/_autoload
@@ -1,3 +1,3 @@
 #defcomp autoload
 
-complist -s '${^fpath}/*(N:t)'
+compgen -s '${^fpath}/*(N:t)'
diff --git a/Completion/Builtins/_bg_jobs b/Completion/Builtins/_bg_jobs
index 511bb8308..4abee070c 100644
--- a/Completion/Builtins/_bg_jobs
+++ b/Completion/Builtins/_bg_jobs
@@ -1,3 +1,3 @@
 #defcomp bg
 
-complist -z -P '%'
+compgen -z -P '%'
diff --git a/Completion/Builtins/_bindkey b/Completion/Builtins/_bindkey
index 8eddeb2a8..d3d019492 100644
--- a/Completion/Builtins/_bindkey
+++ b/Completion/Builtins/_bindkey
@@ -1,7 +1,7 @@
 #defcomp bindkey
 
-if [[ -mword 1 -*[DAN]* || -mcurrent -1 -*M ]]; then
-  complist -s '$(bindkey -l)'
+if [[ "$words[2]" = -*[DAN]* || "$words[CURRENT-1] = -*M ]]; then
+  compgen -s '$(bindkey -l)'
 else
-  complist -b
+  compgen -b
 fi
diff --git a/Completion/Builtins/_builtin b/Completion/Builtins/_builtin
index a967932ee..bee67fe8f 100644
--- a/Completion/Builtins/_builtin
+++ b/Completion/Builtins/_builtin
@@ -1,7 +1,9 @@
 #defcomp builtin
 
-if [[ -position 2 -1 ]]; then
-  _normal "$@"
+if (( $CURRENT > 2 )); then
+  shift words
+  (( CURRENT -- ))
+  _normal
 else
-  complist -eB
+  compgen -eB
 fi
diff --git a/Completion/Builtins/_cd b/Completion/Builtins/_cd
index f3ce67ec7..65ce7f293 100644
--- a/Completion/Builtins/_cd
+++ b/Completion/Builtins/_cd
@@ -1,3 +1,62 @@
-#defcomp cd
+#defcomp cd pushd
 
-_files -W cdpath -g '*(-/)'
+# Handling of cd.
+#  - Normally just completes directories.  Uses cdpath if that's set
+#    and the string doesn't begin with ~, /, ./ or ../.
+#  - In the second argument to cd for the form `cd old new', completes
+#    possible `new' strings by examining `old' and $PWD.
+#  - After pushd - or pushd +, completes numbers, but the listing
+#    gives you the list of directories to complete.  This turns on
+#    menu-completion and lists the possibilities automatically, otherwise
+#    it's not a lot of use.  If you don't type the + or - it will
+#    complete directories as normal.
+
+local pushdminus
+[[ -o pushdminus ]] && pushdminus=1
+
+emulate -LR zsh
+setopt extendedglob
+
+if [[ -position 3 ]]; then
+  # cd old new: look for old in $PWD and see what can replace it
+  local rep
+  # Get possible completions using word in position 2
+  rep=(${~PWD/$words[2]/*}~$PWD(-/N))
+  # Now remove all the common parts of $PWD and the completions from this
+  rep=(${${rep#${PWD%%$words[2]*}}%${PWD#*$words[2]}})
+  (( $#rep )) && compadd $rep
+elif [[ $words[1] = pu* && $PREFIX = [-+]* ]]; then
+  # pushd: just complete the numbers, but show the full directory list with
+  # numbers.
+  # For - we do the same thing, but reverse the numbering (other
+  # way round if pushdminus is set).
+  # The test is for pu* because I have an alias pu since I'm too
+  # lazy to type pushd.
+  IPREFIX=$PREFIX[1]
+  PREFIX=$PREFIX[2,-1]
+  local list lines
+  # get the list of directories with their canonical number
+  lines="$(dirs -v)"
+  # turn the lines into an array, removing the current directory
+  list=(${${(f)lines}##0*})
+  if [[ ( $IPREFIX = - && -z $pushdminus ) ||
+        ( $IPREFIX = + && -n $pushdminus ) ]]; then
+    # reverse the numbering: it counts the last one as -0, which
+    # is a little strange.
+    integer tot i
+    for (( i = 1, tot = $#list-1; tot >= 0; i++, tot-- )); do
+      list[$i]="$tot${list[$i]##[0-9]#}"
+    done
+  fi
+  # make sure -y treats this as a single string
+  lines="${(F)list}"
+  # get the array of numbers only
+  list=(${list%%[ 	]*})
+  compgen -y '$lines' -Q -k list
+  [[ -z $compstate[list] ]] && compstate[list]=list
+  [[ -n $compstate[insert] ]] && compstat[insert]=menu
+elif [[ $PREFIX != (\~|/|./|../)* && $#cdpath -ne 0 ]]; then
+  _path_files -W cdpath -/
+else
+  _path_files -/
+fi
diff --git a/Completion/Builtins/_command b/Completion/Builtins/_command
index b2812de25..47eb0d667 100644
--- a/Completion/Builtins/_command
+++ b/Completion/Builtins/_command
@@ -1,7 +1,7 @@
 #defcomp command
 
-if [[ -position 2 -1 ]]; then
-  _normal "$@"
+if [[ -position 3 -1 ]]; then
+  _normal
 else
-  complist -em
+  compgen -em
 fi
diff --git a/Completion/Builtins/_disable b/Completion/Builtins/_disable
index 063b65a7d..e3edafe2b 100644
--- a/Completion/Builtins/_disable
+++ b/Completion/Builtins/_disable
@@ -1,6 +1,8 @@
 #defcomp disable
 
-[[ -mcurrent -1 -*a* ]] && complist -ea
-[[ -mcurrent -1 -*f* ]] && complist -eF
-[[ -mcurrent -1 -*r* ]] && complist -ew
-[[ ! -mcurrent -1 -* ]] && complist -eB
+local prev="$words[CURRENT-1]"
+
+[[ "$prev" = -*a* ]] && compgen -ea
+[[ "$prev" = -*f* ]] && compgen -eF
+[[ "$prev" = -*r* ]] && compgen -ew
+[[ "$prev" != -* ]] && compgen -eB
diff --git a/Completion/Builtins/_echotc b/Completion/Builtins/_echotc
index 85ebb97ce..135cabada 100644
--- a/Completion/Builtins/_echotc
+++ b/Completion/Builtins/_echotc
@@ -1,3 +1,3 @@
 #defcomp echotc
 
-complist -k '(al dc dl do le up al bl cd ce cl cr dc dl do ho is le ma nd nl se so up)'
+compgen -k '(al dc dl do le up al bl cd ce cl cr dc dl do ho is le ma nd nl se so up)'
diff --git a/Completion/Builtins/_enable b/Completion/Builtins/_enable
index 22ff53ee7..111d1ae26 100644
--- a/Completion/Builtins/_enable
+++ b/Completion/Builtins/_enable
@@ -1,6 +1,8 @@
 #defcomp enable
 
-[[ -mcurrent -1 -*a* ]] && complist -da
-[[ -mcurrent -1 -*f* ]] && complist -dF
-[[ -mcurrent -1 -*r* ]] && complist -dw
-[[ ! -mcurrent -1 -* ]] && complist -dB
+local prev="$words[CURRENT-1]"
+
+[[ "$prev" = -*a* ]] && compgen -da
+[[ "$prev" = -*f* ]] && compgen -dF
+[[ "$prev" = -*r* ]] && compgen -dw
+[[ "$prev" != -* ]] && compgen -dB
diff --git a/Completion/Builtins/_fc b/Completion/Builtins/_fc
index f0d2c03fd..f8cf4dde8 100644
--- a/Completion/Builtins/_fc
+++ b/Completion/Builtins/_fc
@@ -1,7 +1,9 @@
 #defcomp fc
 
-if [[ -mcurrent -1 -*e ]]; then
-  complist -c
-elif [[ -mcurrent -1 -[ARWI]## ]]; then
+local prev="$words[CURRENT-1]"
+
+if [[ "$prev" = -*e ]]; then
+  compgen -c
+elif [[ "$prev" = -[ARWI]## ]]; then
   _files
 fi
diff --git a/Completion/Builtins/_functions b/Completion/Builtins/_functions
index 8a352ea08..7e3174af5 100644
--- a/Completion/Builtins/_functions
+++ b/Completion/Builtins/_functions
@@ -1,3 +1,3 @@
 #defcomp unfunction
 
-complist -F
+compgen -F
diff --git a/Completion/Builtins/_hash b/Completion/Builtins/_hash
index 171c5e2e8..8c100b801 100644
--- a/Completion/Builtins/_hash
+++ b/Completion/Builtins/_hash
@@ -1,13 +1,13 @@
 #defcomp hash
 
-if [[ -mword 1 -*d* ]]; then
+if [[ "$words[2]" = -*d* ]]; then
   if [[ -string 1 '=' ]]; then
     _path_files -g '*(-/)'
   else
-    complist -n -q -S '='
+    compgen -n -q -S '='
   fi
 elif [[ -string 1 '=' ]]; then
   _files -/g '*(*)'
 else
-  complist -m -q -S '='
+  compgen -m -q -S '='
 fi
diff --git a/Completion/Builtins/_jobs b/Completion/Builtins/_jobs
index 018883c61..8f6991de0 100644
--- a/Completion/Builtins/_jobs
+++ b/Completion/Builtins/_jobs
@@ -1,3 +1,3 @@
 #defcomp fg jobs
 
-complist -j -P '%'
+compgen -j -P '%'
diff --git a/Completion/Builtins/_kill b/Completion/Builtins/_kill
index 50796d36f..c1afa78cb 100644
--- a/Completion/Builtins/_kill
+++ b/Completion/Builtins/_kill
@@ -3,9 +3,9 @@
 local list
 
 if [[ -iprefix '-' ]]; then
-  complist -k "($signals[1,-3])"
+  compgen -k "($signals[1,-3])"
 else
-  complist -P '%' -j
+  compgen -P '%' -j
   list=("$(ps 2>/dev/null)")
-  complist -y '$list' -s '`ps 2>/dev/null | tail +2 | cut -c1-5`'
+  compgen -y '$list' -s '`ps 2>/dev/null | tail +2 | cut -c1-5`'
 fi
diff --git a/Completion/Builtins/_limits b/Completion/Builtins/_limits
index 35ccbe07e..8b0b41c71 100644
--- a/Completion/Builtins/_limits
+++ b/Completion/Builtins/_limits
@@ -1,3 +1,3 @@
 #defcomp limit unlimit
 
-complist -k "(${(j: :)${(f)$(limit)}%% *})"
+compgen -k "(${(j: :)${(f)$(limit)}%% *})"
diff --git a/Completion/Builtins/_sched b/Completion/Builtins/_sched
index 1e8ae3445..62cdbb070 100644
--- a/Completion/Builtins/_sched
+++ b/Completion/Builtins/_sched
@@ -1,3 +1,3 @@
 #defcomp sched
 
-[[ -position 2 -1 ]] && _normal "$@"
+[[ -position 3 -1 ]] && _normal
diff --git a/Completion/Builtins/_set b/Completion/Builtins/_set
index 5597025bc..959dac75d 100644
--- a/Completion/Builtins/_set
+++ b/Completion/Builtins/_set
@@ -1,7 +1,9 @@
 #defcomp set
 
-if [[ -mcurrent -1 [-+]o ]]; then
-  complist -o
-elif [[ -current -1 -A ]]; then
-  complist -A
+local prev="$words[CURRENT-1]"
+
+if [[ "$prev" = [-+]o ]]; then
+  compgen -o
+elif [[ "$prev" = -A ]]; then
+  compgen -A
 fi
diff --git a/Completion/Builtins/_setopt b/Completion/Builtins/_setopt
index 4abb3ccee..98800152f 100644
--- a/Completion/Builtins/_setopt
+++ b/Completion/Builtins/_setopt
@@ -1,7 +1,8 @@
 #defcomp setopt
 
-local nm=$NMATCHES
+local nm=$compstate[nmatches]
 
-complist -M 'L:|[nN][oO]= M:_= M:{A-Z}={a-z}' \
+compgen -M 'L:|[nN][oO]= M:_= M:{A-Z}={a-z}' \
          -s '$({ unsetopt kshoptionprint; unsetopt } 2>/dev/null)'
-[[ -nmatches nm ]] && complist -M 'L:|[nN][oO]= M:_= M:{A-Z}={a-z}' -o
+[[ compstate[nmatches] -eq nm ]] &&
+    compgen -M 'L:|[nN][oO]= M:_= M:{A-Z}={a-z}' -o
diff --git a/Completion/Builtins/_source b/Completion/Builtins/_source
index aae2c7320..1bbbf15a4 100644
--- a/Completion/Builtins/_source
+++ b/Completion/Builtins/_source
@@ -1,7 +1,7 @@
 #defcomp source
 
-if [[ -position 2 -1 ]]; then
-  _normal "$@"
+if [[ -position 3 -1 ]]; then
+  _normal
 else
   _files
 fi
diff --git a/Completion/Builtins/_trap b/Completion/Builtins/_trap
index 59e81c589..36ab1f1a8 100644
--- a/Completion/Builtins/_trap
+++ b/Completion/Builtins/_trap
@@ -1,7 +1,7 @@
 #defcomp trap
 
-if [[ -position 1 ]]; then
-  complist -c
+if [[ CURRENT -eq 2 ]]; then
+  compgen -c
 else
-  complist -k signals
+  compgen -k signals
 fi
diff --git a/Completion/Builtins/_unhash b/Completion/Builtins/_unhash
index fe40c25a2..63d61c991 100644
--- a/Completion/Builtins/_unhash
+++ b/Completion/Builtins/_unhash
@@ -1,6 +1,8 @@
 #defcomp unhash
 
-[[ -mword 1 -*d* ]] && complist -n
-[[ -mword 1 -*a* ]] && complist -a
-[[ -mword 1 -*f* ]] && complist -F
-[[ ! -mword 1 -* ]] && complist -m
+local fl="$words[2]"
+
+[[ "$fl" = -*d* ]] && compgen -n
+[[ "$fl" = -*a* ]] && compgen -a
+[[ "$fl" = -*f* ]] && compgen -F
+[[ "$fl" != -* ]] && compgen -m
diff --git a/Completion/Builtins/_unsetopt b/Completion/Builtins/_unsetopt
index 90d642b51..a5c85b1ef 100644
--- a/Completion/Builtins/_unsetopt
+++ b/Completion/Builtins/_unsetopt
@@ -1,7 +1,8 @@
 #defcomp unsetopt
 
-local nm=$NMATCHES
+local nm=$compstate[nmatches]
 
-complist -M 'L:|[nN][oO]= M:_= M:{A-Z}={a-z}' \
+compgen -M 'L:|[nN][oO]= M:_= M:{A-Z}={a-z}' \
          -s '$({ unsetopt kshoptionprint; setopt } 2>/dev/null)'
-[[ -nmatches nm ]] && complist -M 'L:|[nN][oO]= M:_= M:{A-Z}={a-z}' -o
+[[ compstate[nmatches] -eq nm ]] &&
+    compgen -M 'L:|[nN][oO]= M:_= M:{A-Z}={a-z}' -o
diff --git a/Completion/Builtins/_vars_eq b/Completion/Builtins/_vars_eq
index fcbb0148c..9488cb7f9 100644
--- a/Completion/Builtins/_vars_eq
+++ b/Completion/Builtins/_vars_eq
@@ -1,3 +1,3 @@
 #defcomp declare export integer local readonly typeset
 
-complist -v -q -S '='
+compgen -v -q -S '='
diff --git a/Completion/Builtins/_wait b/Completion/Builtins/_wait
index 29a7f6002..6e3a4c3c9 100644
--- a/Completion/Builtins/_wait
+++ b/Completion/Builtins/_wait
@@ -2,6 +2,6 @@
 
 local list
 
-complist -P '%' -j
+compgen -P '%' -j
 list=("$(ps 2>/dev/null)")
-complist -y '$list' -s '`ps 2>/dev/null | tail +2 | cut -c1-5`'
+compgen -y '$list' -s '`ps 2>/dev/null | tail +2 | cut -c1-5`'
diff --git a/Completion/Builtins/_which b/Completion/Builtins/_which
index 324256e3d..9248f9c9f 100644
--- a/Completion/Builtins/_which
+++ b/Completion/Builtins/_which
@@ -1,3 +1,3 @@
 #defcomp which whence where type
 
-complist -caF
+compgen -caF
diff --git a/Completion/Builtins/_zftp b/Completion/Builtins/_zftp
index 9be9c94db..e93021acf 100644
--- a/Completion/Builtins/_zftp
+++ b/Completion/Builtins/_zftp
@@ -9,28 +9,28 @@ _compskip=1
 
 local subcom
 
-if [[ $COMMAND = zftp ]]; then
+if [[ $words[1] = zftp ]]; then
   if [[ $CURRENT -eq 1 ]]; then
-    compadd -m open params user login type ascii binary mode put \
+    compadd open params user login type ascii binary mode put \
       putat get getat append appendat ls dir local remote mkdir rmdir
     return
   fi
-  subcom=$1
+  subcom=$words[2]
 else
-  subcom=$COMMAND
+  subcom=$words[1]
 fi
 
 case $subcom in
   *(cd|ls|dir))
    # complete remote directories; we could be smarter about hiding prefixes
    zfcd_match $PREFIX $SUFFIX
-   (( $#reply )) && compadd -m -S/ -q $reply
+   (( $#reply )) && compadd -S/ -q - $reply
    ;;
 
   *(get(|at)|gcp|delete|remote))
    # complete remote files
    zfget_match $PREFIX $SUFFIX
-   (( $#reply )) && compadd -F fignore -m $reply
+   (( $#reply )) && compadd -F fignore - $reply
    ;;
 
   *(put(|at)|pcp))
@@ -40,7 +40,7 @@ case $subcom in
 
   *(open|anon|params))
   # complete hosts:  should do cleverer stuff with user names
-  complist -k hosts
+  compgen -k hosts
   ;;
 
   *)
diff --git a/Completion/Builtins/_zle b/Completion/Builtins/_zle
index bb1102e74..0a9ad0a9e 100644
--- a/Completion/Builtins/_zle
+++ b/Completion/Builtins/_zle
@@ -1,7 +1,7 @@
 #defcomp zle
 
-if [[ -word 1 -N && -position 3 ]]; then
-  complist -F
+if [[ "$words[2]" = -N && CURRENT -eq 3 ]]; then
+  compgen -F
 else
-  complist -b
+  compgen -b
 fi
diff --git a/Completion/Builtins/_zmodload b/Completion/Builtins/_zmodload
index 112acb57c..4259adf06 100644
--- a/Completion/Builtins/_zmodload
+++ b/Completion/Builtins/_zmodload
@@ -1,9 +1,11 @@
 #defcomp zmodload
 
-if [[ -mword 1 -*(a*u|u*a)* || -mword 1 -*a* && -position 3 -1 ]]; then
-  complist -B
-elif [[ -mword 1 -*u* ]]; then
-  complist -s '$(zmodload)'
+local fl="$words[2]"
+
+if [[ "$fl" = -*(a*u|u*a)* || "$fl" = -*a* && -position 4 -1 ]]; then
+  compgen -B
+elif [[ "$fl" = -*u* ]]; then
+  compgen -s '$(zmodload)'
 else
-  complist -s '${^module_path}/*(N:t:r)'
+  compgen -s '${^module_path}/*(N:t:r)'
 fi
diff --git a/Completion/Commands/_correct_filename b/Completion/Commands/_correct_filename
index edf1c65c2..582555587 100644
--- a/Completion/Commands/_correct_filename
+++ b/Completion/Commands/_correct_filename
@@ -17,7 +17,8 @@ integer approx max_approx=6
 
 if [[ -e "$file" ]]; then
   if [[ -n $WIDGET ]]; then
-    compadd "$file"
+    compadd -U -i "$IPREFIX" "$file"
+    [[ -n "$compstate[insert]" ]] && compstate[insert]=menu
   else
     print "$file"
   fi
@@ -31,7 +32,8 @@ done
 (( $#trylist )) || return 1
 
 if [[ -n $WIDGET ]]; then
-  compadd -U "${trylist[@]}"
+  compadd -U -i "$IPREFIX" -U "${trylist[@]}"
+  [[ -n "$compstate[insert]" ]] && compstate[insert]=menu
 else
   print "${trylist[@]}"
 fi
diff --git a/Completion/Commands/_most_recent_file b/Completion/Commands/_most_recent_file
index ff5645de5..df35ecba7 100644
--- a/Completion/Commands/_most_recent_file
+++ b/Completion/Commands/_most_recent_file
@@ -1,4 +1,22 @@
 #defkeycomp complete-word \C-xm
-local file
-file=($~PREFIX*$~SUFFIX(om[1]N))
-(( $#file )) && compadd -f $file
+
+# Complete the most recent file matching the pattern on the line so
+# far: globbing is active, i.e. *.txt will be expanded to the most recent
+# file ending in .txt
+#
+# With a prefix argument, select the Nth most recent matching file;
+# negative arguments work in the opposite direction, so for example
+# `Esc - \C-x m' gets you the oldest file.
+#
+# (`Most recent' means most recently modified.)
+
+local file tilde etilde
+if [[ $PREFIX = \~*/* ]]; then
+  tilde=${PREFIX%%/*}
+  etilde=${~tilde}
+  file=($~PREFIX*$~SUFFIX(om[$NUMERIC]N))
+  file=(${file/#$etilde/$tilde})
+else
+  file=($~PREFIX*$~SUFFIX(om[$NUMERIC]N))
+fi
+(( $#file )) && compadd -U -f -Q $file
diff --git a/Completion/Core/_comp_parts b/Completion/Core/_comp_parts
index 7c24fd19d..d58669f29 100644
--- a/Completion/Core/_comp_parts
+++ b/Completion/Core/_comp_parts
@@ -21,11 +21,11 @@
 # `_match_test' and `_match_pattern' for this.
 
 local str arr sep test testarr tmparr prefix suffixes matchers autosuffix
-local matchflags opt group expl
+local matchflags opt group expl nm=$compstate[nmatches]
 
 # Test if we should use this function for the global matcher in use.
 
-_match_test _comp_parts || return
+_match_test _comp_parts || return 1
 
 # Get the options.
 
@@ -42,6 +42,7 @@ shift OPTIND-1
 # Get the string from the line.
 
 str="$PREFIX$SUFFIX"
+[[ -o globcomplete ]] && str="$str:q"
 prefix=""
 
 # Walk through the arguments to find the longest unambiguous prefix.
@@ -63,12 +64,14 @@ while [[ $# -gt 1 ]]; do
   test="${str%%${sep}*}"
   matchflags=""
   _match_pattern _comp_parts test matchflags
+  [[ -n "$_comp_correct" ]] && matchflags="$matchflags(#a$_comp_correct)"
   test="${matchflags}${test}"
   testarr=( "${(@M)${(@P)arr}:#${~test}*}" )
+  testarr=( "${(@)testarr:#}" )
 
   # If there are no matches we give up. If there is more than one
   # match, this is the part we will complete.
-  (( $#testarr )) || return
+  (( $#testarr )) || return 1
   [[ $#testarr -gt 1 ]] && break
 
   # Only one match, add it to the prefix and skip over it in `str',
@@ -89,11 +92,13 @@ if [[ $# -le 1 || "$str" != *${2}* ]]; then
   matchflags=""
   test="$str"
   _match_pattern _comp_parts test matchflags
+  [[ -n "$_comp_correct" ]] && matchflags="$matchflags(#a$_comp_correct)"
   test="${matchflags}${test}"
   testarr=( "${(@M)${(@P)arr}:#${~test}*}" )
+  testarr=( "${(@)testarr:#}" )
 fi
 
-[[ $#testarr -eq 0 || ${#testarr[1]} -eq 0 ]] && return
+[[ $#testarr -eq 0 || ${#testarr[1]} -eq 0 ]] && return 1
 
 # Now we build the suffixes to give to the completion code.
 shift
@@ -114,6 +119,7 @@ while [[ $# -gt 0 && "$str" == *${1}* ]]; do
   fi
   matchflags=""
   _match_pattern _comp_parts test matchflags
+  [[ -n "$_comp_correct" ]] && matchflags="$matchflags(#a$_comp_correct)"
   test="${matchflags}${test}"
 
   # We incrementally add suffixes by appending to them the seperators
@@ -124,7 +130,9 @@ while [[ $# -gt 0 && "$str" == *${1}* ]]; do
     tmparr=( ${=arr[2,-2]} )
     arr=tmparr
   fi
-  suffixes=("${^suffixes[@]}${1}${(@M)^${(@P)arr}:#${~test}*}")
+  tmparr=( "${(@M)${(@P)arr}:#${~test}*}" )
+  tmparr=( "${(@)testarr:#}" )
+  suffixes=("${^suffixes[@]}${1}$^tmparr")
 
   # We want the completion code to generate the most specific suffix
   # for us, so we collect matching specifications that allow partial
@@ -143,5 +151,10 @@ done
 
 # Add the matches for each of the suffixes.
 for i in "$suffixes[@]"; do
-  compadd "$group[@]" "$expl[@]" "$matchers[@]" "$autosuffix[@]" -p "$prefix" -s "$i" - "$testarr[@]"
+  compadd -U "$group[@]" "$expl[@]" "$matchers[@]" "$autosuffix[@]" \
+          -i "$IPREFIX" -p "$prefix" -s "$i" - "$testarr[@]"
 done
+
+# This sets the return value to indicate that we added matches (or not).
+
+[[ nm -ne compstate[nmatches] ]]
diff --git a/Completion/Core/_compalso b/Completion/Core/_compalso
index 23a40e2d0..6ff6cf0bf 100644
--- a/Completion/Core/_compalso
+++ b/Completion/Core/_compalso
@@ -4,10 +4,10 @@
 # It is used to include completions for another command or special context
 # into the list generated by the calling function.
 # For example the function for `-subscript-' could call this as in
-# `_compalso -math- "$@"' to get the completions that would be generated
-# for a mathematical context.
+# `_compalso -math-' to get the completions that would be generated for a
+# mathematical context.
 
 local tmp
 
 tmp="$_comps[$1]"
-[[ -z "$tmp" ]] || "$tmp" "$@"
+[[ -z "$tmp" ]] || "$tmp"
diff --git a/Completion/Core/_files b/Completion/Core/_files
index d2cce35e7..471824bfe 100644
--- a/Completion/Core/_files
+++ b/Completion/Core/_files
@@ -3,11 +3,12 @@
 # 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 nm=$NMATCHES
+local nm=$compstate[nmatches] ret
 
 _path_files "$@"
+ret=$?
 
-if [[ $# -ne 0 && -nmatches nm ]]; then
+if [[ $# -ne 0 && compstate[nmatches] -eq nm ]]; then
   local opt opts
 
   # We didn't get any matches for those types of files described by
@@ -23,4 +24,6 @@ if [[ $# -ne 0 && -nmatches nm ]]; then
   done
 
   _path_files "$opts[@]"
+else
+  return $ret
 fi
diff --git a/Completion/Core/_main_complete b/Completion/Core/_main_complete
index c7f5a5a96..34c5a3d3c 100644
--- a/Completion/Core/_main_complete
+++ b/Completion/Core/_main_complete
@@ -2,47 +2,198 @@
 
 # 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.
+#
+# This code will automatically try to correct the string on the
+# line based on the strings generated for the context if the
+# parameter `COMPCORRECT' is set and normal completion didn't yield
+# any matches. These corrected strings will be shown in a list and
+# one can cycle through them as in a menucompletion. To use this 
+# feature, `COMPCORRECT' 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
+# `COMPCORRECT' will be used. E.g. with `COMPCORRECT=2n' two errors
+# will be accepted, but if the user gives another number with the
+# numeric argument, this will be prefered. Also, with `COMPCORRECT=0n',
+# normally no automatic correction will be tried, but if a numeric
+# argument is given, automatic correction will be used. 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.
+# If the parameter `CCORIG' is set (independent of the value), the
+# line will first be left unchanged and consecutive TABs cycle through 
+# the list.
+# When using automatic correction, one can also set the parameter
+# `CCPROMPT' to a string that will be shown when multiple
+# correction results are displayed and the code starts cycling
+# through them (this string is used with the `-X' option and thus may
+# contain the control sequences `%n', `%B',...).
 
-local comp name
+local comp name _comp_correct comax
 
 setopt localoptions nullglob rcexpandparam globdots
-unsetopt markdirs globsubst shwordsplit nounset
-
-# 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
-  "$comp" "$@"
-  if (( $+_compskip )); then
-    unset _compskip
-    return
-  fi
+unsetopt markdirs globsubst shwordsplit nounset ksharrays
+
+# Special completion contexts after `~' and `='.
+
+if [[ -iprefix '=' ]]; then
+  compstate[context]=equal
+elif [[ "$PREFIX$SUFFIX" != */* && -iprefix '~' ]]; then
+  compstate[context]=tilde
 fi
 
-# For arguments we use the `_normal function.
+# This is not an endless loop.
 
-if [[ $CONTEXT == argument || $CONTEXT == command ]]; then
-  _normal "$@"
-else
-  # Let's see if we have a special completion definition for the other
-  # possible contexts.
+while true; do
 
-  comp=''
+  # 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.
 
-  case $CONTEXT in
-  redirect)  comp="$_comps[-redirect-]";;
-  math)      comp="$_comps[-math-]";;
-  subscript) comp="$_comps[-subscript-]";;
-  value)     comp="$_comps[-value-]";;
-  condition) comp="$_comps[-condition-]";;
-  esac
+  comp="$_comps[-first-]"
+  if [[ ! -z "$comp" ]]; then
+    "$comp"
+    if (( $+_compskip )); then
+      unset _compskip
+      return
+    fi
+  fi
 
-  # If not, we use default completion, if any.
+  # For arguments and command names we use the `_normal' function.
 
-  [[ -z "$comp" ]] && comp="$_comps[-default-]"
-  [[ -z "$comp" ]] || "$comp" "$@"
-fi
+  if [[ "$compstate[context]" = command ]]; then
+    _normal
+  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
+
+    # If not, we use default completion, if any.
+
+    [[ -z "$comp" ]] && comp="$_comps[-default-]"
+    [[ -z "$comp" ]] || "$comp"
+  fi
+
+  # Use automatic correction?
+
+  if (( $+COMPCORRECT )); then
+
+    # Do we have matches?
+    if (( compstate[nmatches] )); then
+
+      # Yes, were they added using correction? (More than one match?)
+
+      if [[ -n "$_comp_correct" && compstate[nmatches] -gt 1 ]]; then
+
+        # If we got more than one string from correction, we add the 
+	# original string as a possible match, let it not be shown in
+	# the list, and probably display the `CCPROMPT'.
+
+        (( $+CCORIG )) && builtin compadd -nQ - "$PREFIX$SUFFIX"
+
+	# If you always want to see the list of possible corrections,
+	# set `compstate[list]=list' here.
+      fi
+      # Since we have matches, we don't want to try again.
+      break
+    fi
+
+    # No matches, so let's see if we already tried correction.
+
+    if [[ -n "$_comp_correct" ]]; then
+
+      # Yes, give up if we reached the maximum number of tries,
+      # otherwise increment our counter.
+
+      [[ _comp_correct -eq comax ]] && break
+      (( _comp_correct++ ))
+
+    elif [[ compstate[matcher] -eq compstate[total_matchers] ]]; then
+
+      # No matches and no correction tried yet, but we just tried the
+      # last global match specification, so let's see if we should use
+      # correction now. First, get the maximum number of errors.
+
+      if [[ "$COMPCORRECT" = *[nN]* && NUMERIC -ne 1 ]]; then
+        # Prefer the numeric argument if that has a sensible value.
+        comax="$NUMERIC"
+      else
+        comax="${COMPCORRECT//[^0-9]}"
+      fi
+      # If the number of errors to accept is to small, give up.
+
+      [[ "$comax" -lt 1 ]] && break
+
+      # 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
+      # ignored prefix).
+
+      compadd() {
+        if [[ "$PREFIX" = \~*/* ]]; then
+	  PREFIX="${PREFIX%%/*}/(#a${_comp_correct})${PREFIX#*/}"
+	else
+          PREFIX="(#a${_comp_correct})$PREFIX"
+	fi
+	if (( $+CCPROMPT )); then
+	  builtin compadd -X "$CCPROMPT" -J _correct "$@"
+	else
+	  builtin compadd -J _correct "$@"
+	fi
+      }
+      compgen() {
+        if [[ "$PREFIX" = \~*/* ]]; then
+	  PREFIX="${PREFIX%%/*}/(#a${_comp_correct})${PREFIX#*/}"
+	else
+          PREFIX="(#a${_comp_correct})$PREFIX"
+	fi
+	if (( $+CCPROMPT )); then
+	  builtin compgen "$@" -X "$CCPROMPT" -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
+
+      # We also need to set `extendedglob' and to make the completion
+      # code behave as if globcomplete were set.
+
+      setopt extendedglob
+      compstate[pattern_match]=yes
+    else
+      # We are still trying global match specifications...
+      break
+    fi
+  else
+    # No automatic correction to try, just give up.
+    break
+  fi
+done
+
+# If we added wrapper functions, remove them.
+
+[[ -n "$_comp_correct" ]] && unfunction compadd compgen
diff --git a/Completion/Core/_multi_parts b/Completion/Core/_multi_parts
new file mode 100644
index 000000000..1f51d2f6d
--- /dev/null
+++ b/Completion/Core/_multi_parts
@@ -0,0 +1,201 @@
+#autoload
+
+# This gets two arguments, a separator (which should be only one
+# character) and an array. As usual, the array may be given by it's
+# name or literal as in `(foo bar baz)' (words separated by spaces in
+# parentheses).
+# The parts of words from the array that are separated by the
+# separator character are then completed independently.
+
+local sep matches patstr orig matchflags pref i tmp1 tmp2 nm
+local group expl
+
+_match_test _multi_parts || return 1
+
+# Save the current number of matches to be able to return if we added
+# matches or not.
+
+nm=$compstate[nmatches]
+
+# Get the options.
+
+group=()
+expl=()
+while getopts "J:V:X:" opt; do
+  case "$opt" in
+  [JV]) group=("-$opt" "$OPTARG");;
+  X)    expl=(-X "$OPTARG");;
+  esac
+done
+shift OPTIND-1
+
+# Get the arguments, first the separator, then the array. The array is 
+# stored in `matches'. Further on this array will always contain those 
+# words from the original array that still match everything we have
+# tried to match while we walk through the string from the line.
+
+sep="$1"
+if [[ "${2[1]}" = '(' ]]; then
+  matches=( ${2[2,-2]} )
+else
+  matches=( "${(@P)2}" )
+fi
+
+# Now build the pattern from what we have on the line. We also save
+# the original string in `orig'. The `eval' is used to replace our
+# separator character by `*<sep>'.
+
+if [[ -o globcomplete ]]; then
+  patstr="${PREFIX}*${SUFFIX}*"
+else
+  patstr="${PREFIX:q}*${SUFFIX:q}*"
+fi
+orig="${PREFIX}${SUFFIX}"
+
+matchflags=""
+_match_pattern _path_files patstr matchflags
+[[ -n "$_comp_correct" ]] && matchflags="$matchflags(#a$_comp_correct)"
+
+patstr="${${patstr//$sep/*$sep}//\*##/*}"
+#eval patstr\="\$patstr:gs-${sep}-\*${sep}-:gs/\*\*/\*/"
+
+# First we will skip over those parts of the matches for which we have 
+# exact substrings on the line. In `pref' we will build the
+# unambiguous prefix string.
+
+pref=''
+while [[ "$orig" = *${sep}* ]] do
+
+  # First build the pattern to use, then collect all strings from
+  # `matches' that match the prefix we have and the exact substring in 
+  # the array `tmp1'.
+
+  pat="${${${patstr#*${sep}}%${sep}*}//\*/[^${sep}]#}${patstr##*${sep}}"
+  tmp1=( "${(@M)matches:#${~matchflags}${orig%%${sep}*}${sep}${~pat}}" )
+
+  # If there are no words matching the exact substring, stop.
+
+  (( $#tmp1 )) || break
+
+  # Otherwise add the part to the prefix, remove it from the matches
+  # (which will also remove all words not matching the string at all), 
+  # and set `patstr' and `orig' to the next component.
+
+  pref="$pref${orig%%${sep}*}${sep}"
+  matches=( "${(@)${(@)matches#${orig%%${sep}*}${sep}}:#}" )
+  orig="${orig#*${sep}}"
+  patstr="${patstr#*${sep}}"
+done
+
+# Now we get all the words that still match in `tmp1'.
+
+if [[ "$patstr" = *${sep}* ]]; then
+  tmp1="${patstr%${sep}*}${sep}"
+  pat="${tmp1//\*/[^${sep}]#}${patstr##*${sep}}"
+else
+  pat="$patstr"
+fi
+tmp1=( "${(@M)matches:#${~matchflags}${~pat}}" )
+
+if (( $#tmp1 )); then
+
+  # There are words that are matched, put them int `matches' and then
+  # move all unambiguous components from the beginning into `pref'.
+
+  matches=( "$tmp1[@]" )
+  while [[ "$matches[1]" = *${sep}* ]]; do
+
+    # We just take the first component of the first match and see if
+    # there are other matches with a different prefix (these are
+    # collected in `tmp2'). If there are any, we give up.
+
+    tmp1="${matches[1]%%${sep}*}${sep}"
+    tmp2=( "${(@)matches:#${tmp1}*}" )
+    (( $#tmp2 )) && break
+
+    # All matches have the same prefix, but it into `pref' and remove
+    # it from the matches.
+
+    pref="$pref$tmp1"
+    matches=( "${(@)${(@)matches#$tmp1}:#}" )
+
+    if [[ "$orig" = *${sep}* ]]; then
+      orig="${orig#*${sep}}"
+    else
+      orig=''
+    fi
+  done
+
+  # Now we can tell the completion code about the things we
+  # found. Strings that have a separator will be added with a suffix.
+
+  if [[ -z "$orig" && "$PREFIX$SUFFIX" != "$pref$orig" ]]; then
+    compadd -QU  "$group[@]" "$expl[@]" -i "$IPREFIX" -S '' - "${pref}${orig}"
+  elif [[ $compstate[insert] = *menu ]]; then
+    for i in "$matches[@]" ; do
+      if [[ "$i" = *${sep}* ]]; then
+        compadd -U "$group[@]" "$expl[@]" -i "$IPREFIX" \
+	        -p "$pref" -qS "$sep" - "${i%%${sep}*}"
+      else
+        compadd -U "$group[@]" "$expl[@]" -i "$IPREFIX" \
+	        -p "$pref" - "${i%%${sep}*}"
+      fi
+    done
+  else
+    for i in "$matches[@]" ; do
+      if [[ "$i" = *${sep}* ]]; then
+        compadd -U -i "$IPREFIX" -p "$pref" -s "${sep}${i#*${sep}}" \
+	        "$group[@]" "$expl[@]" -M "r:|${sep}=*" - "${i%%${sep}*}"
+      else
+        compadd -U "$group[@]" "$expl[@]" -i "$IPREFIX" -p "$pref" - "$i"
+      fi
+    done
+  fi
+elif [[ "$patstr" = *${sep}* ]]; then
+
+  # We had no words matching the string from the line. But we want to
+  # be friendly and at least expand the prefix as far as we can. So we 
+  # will loop through the rest of the string from the line and test
+  # the components one by one.
+
+  while [[ "$patstr" = *${sep}* ]]; do
+
+    # First we get all words matching at least this component in
+    # `tmp1'. If there are none, we give up.
+
+    tmp1=( "${(@M)matches:#${~matchflags}${~patstr%%${sep}*}${sep}*}" )
+    (( $#tmp1 )) || break
+
+    # Then we check if there are words that have a different prefix.
+
+    tmp2=( "${(@)tmp1:#${tmp1[1]%%${sep}*}${sep}*}" )
+    if (( $#tmp2 )); then
+
+      # There are words with another prefix, so we have found an
+      # ambiguous component. So we just give all possible prefixes to
+      # the completion code together with our prefix and the rest of
+      # the string from the line as the suffix.
+
+      compadd -U "$group[@]" "$expl[@]" -S '' -i "$IPREFIX" -p "$pref" \
+              -s "${sep}${orig#*${sep}}" - "${(@)matches%%${sep}*}"
+      return 0
+    fi
+
+    # All words have the same prefix, so add it to `pref' again and
+    # try the next component.
+
+    pref="$pref${tmp1[1]%%${sep}*}${sep}"
+    matches=( "${(@)matches#${tmp1[1]%%${sep}*}${sep}}" )
+    orig="${orig#*${sep}}"
+    patstr="${patstr#*${sep}}"
+  done
+
+  # Finally, add the unambiguous prefix and the rest of the string
+  # from the line.
+
+  compadd -U "$group[@]" "$expl[@]" -S '' -i "$IPREFIX" -p "$pref" - "$orig"
+fi
+
+# This sets the return value to indicate that we added matches (or not).
+
+[[ nm -ne compstate[nmatches] ]]
diff --git a/Completion/Core/_normal b/Completion/Core/_normal
index 19da6d79b..f56849194 100644
--- a/Completion/Core/_normal
+++ b/Completion/Core/_normal
@@ -1,24 +1,25 @@
 #autoload
 
-local comp cmd1 cmd2 pat val name
+local comp command cmd1 cmd2 pat val name i ret
 
 # Completing in command position? If not we set up `cmd1' and `cmd2' as
 # two strings we have search in the completion definition arrays (e.g.
 # a path and the last path name component).
 
-if [[ $CONTEXT == command ]]; then
+command="$words[1]"
+if [[ CURRENT -eq 1 ]]; then
   comp="$_comps[-command-]"
-  [[ -z "$comp" ]] || "$comp" "$@"
+  [[ -z "$comp" ]] || "$comp"
   return
-elif [[ "$COMMAND[1]" == '=' ]]; then
-  eval cmd1\=$COMMAND
-  cmd2="$COMMAND[2,-1]"
-elif [[ "$COMMAND" == */* ]]; then
-  cmd1="$COMMAND"
-  cmd2="${COMMAND:t}"
+elif [[ "$command[1]" == '=' ]]; then
+  eval cmd1\=$command
+  cmd2="$command[2,-1]"
+elif [[ "$command" == */* ]]; then
+  cmd1="$command"
+  cmd2="${command:t}"
 else
-  cmd1="$COMMAND"
-  eval cmd2=$(whence -p $COMMAND)
+  cmd1="$command"
+  eval cmd2=$(whence -p $command)
 fi
 
 # See if there are any matching pattern completions.
@@ -27,10 +28,11 @@ for i in "$_patcomps[@]"; do
   pat="${i% *}"
   val="${i#* }"
   if [[ "$cmd1" == $~pat || "$cmd2" == $~pat ]]; then
-    "$val" "$@"
+    "$val"
+    ret=$?
     if (( $+_compskip )); then
       unset _compskip
-      return
+      return $ret
     fi
   fi
 done
@@ -51,4 +53,4 @@ if [[ -z "$comp" ]]; then
   name=-default-
   comp="$_comps[-default-]"
 fi
-[[ -z "$comp" ]] || "$comp" "$@"
+[[ -z "$comp" ]] || "$comp"
diff --git a/Completion/Core/_path_files b/Completion/Core/_path_files
index 83b6e8a09..3c03c0c61 100644
--- a/Completion/Core/_path_files
+++ b/Completion/Core/_path_files
@@ -3,7 +3,7 @@
 # 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
+# the last have the same syntax and meaning as for `compgen'. 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
@@ -14,13 +14,13 @@
 
 # First see if we should generate matches for the global matcher in use.
 
-_match_test _path_files || return
+_match_test _path_files || return 1
 
 # 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
+local addpfx addsfx expl orig ostr nm=$compstate[nmatches]
 
 setopt localoptions nullglob rcexpandparam globdots extendedglob
 unsetopt markdirs globsubst shwordsplit nounset
@@ -91,14 +91,14 @@ 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.
-
-[[ "$str" = \\\~* ]] && str="$str[2,-1]"
+if [[ -o globcomplete ]]; then
+  str="${PREFIX}*${SUFFIX}"
+else
+  str="${PREFIX:q}*${SUFFIX:q}"
+fi
+orig="${PREFIX}${SUFFIX}"
 
-# We will first try normal completion called with `complist', but only if we
+# We will first try normal completion called with `compgen', but only if we
 # weren't given a `-F' option.
 
 if (( ! $#ignore )); then
@@ -112,18 +112,18 @@ if (( ! $#ignore )); then
     tmp1=(-W "( $prepaths )")
   fi
 
-  # Now call complist.
+  # Now call compgen.
 
-  nm=$NMATCHES
+  nm=$compstate[nmatches]
   if [[ -z "$gopt" ]]; then
-    complist "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" "$tmp1[@]" $sopt
+    compgen "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" "$tmp1[@]" $sopt
   else
-    complist "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" "$tmp1[@]" $sopt -g "$pats"
+    compgen "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" "$tmp1[@]" $sopt -g "$pats"
   fi
 
   # If this generated any matches, we don't want to do in-path completion.
 
-  [[ -nmatches nm ]] || return
+  [[ compstate[nmatches] -eq nm ]] || return 0
 
   # No `-F' option, so we want to use `fignore'.
 
@@ -142,14 +142,16 @@ if [[ "$str[1]" = \~ ]]; then
   
   linepath="${str%%/*}/"
   eval realpath\=$linepath
+  [[ "$realpath" = "$linepath" ]] && return 1
   str="${str#*/}"
+  orig="${orig#*/}"
   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
@@ -158,6 +160,7 @@ else
     # Also, we don't use the paths from `-W'.
 
     str="$str[2,-1]"
+    orig="$orig[2,-1]"
     donepath='/'
     prepaths=( '' )
   else
@@ -169,28 +172,31 @@ else
   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'.
-
-while [[ "$str" = */* ]] do
-  [[ -e "$realpath$donepath${str%%/*}" ]] || break
-  donepath="$donepath${str%%/*}/"
-  str="${str#*/}"
-done
-
 # Now build the glob pattern by calling `_match_pattern'.
 patstr="$str"
 matchflags=""
 _match_pattern _path_files patstr matchflags
+[[ -n "$_comp_correct" ]] && matchflags="$matchflags(#a$_comp_correct)"
 
 # 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.
 
-patstr="$patstr:gs-/-*/-:gs/*.*.//:gs-/*.-/.-:gs/**/*/"
+patstr="$patstr:gs-/-*/-:gs/*.*./../:gs-/*.-/.-:gs/**/*/:gs-.*/-./-"
+
+# 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 `orig' and added
+# to `donepath'.
+
+while [[ "$orig" = */* ]] do
+  tmp1=( ${~matchflags}$realpath$donepath${orig%%/*}/${~patstr#*/}$^pats )
+  [[ $#tmp1 -gt 0 && -e "$realpath$donepath${orig%%/*}" ]] || break
+  donepath="$donepath${orig%%/*}/"
+  orig="${orig#*/}"
+  patstr="${patstr#*/}"
+done
 
 # 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'
@@ -199,6 +205,9 @@ patstr="$patstr:gs-/-*/-:gs/*.*.//:gs-/*.-/.-:gs/**/*/"
 for prepath in "$prepaths[@]"; do
   str="$patstr"
   testpath="$donepath"
+  ostr="$orig"
+
+  [[ -z "$prepath" || "$prepath[-1]" = / ]] || prepath="${prepath}/"
 
   # The second loop tests the components of the path in `str' to get the
   # possible matches.
@@ -235,16 +244,20 @@ for prepath in "$prepaths[@]"; do
       # the suffixes we just built are used to produce possible matches
       # via globbing.
 
-      for i in $tmp1; do
+      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.
+      # has a possible sub-path matching what's on the line, we add the
+      # matches found in `tmp1' and otherwise give up and continue with the
+      # next `-W' path.
 
       if [[ $#collect -eq 0 ]]; then
+        compadd -QU "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" \
+                -i "$IPREFIX" -p "${linepath:q}${testpath:q}" -S "/${ostr#*/}" \
+		-W "$tmp1" -f "$ignore[@]" - "${(@)tmp1:q}"
         continue 2
       elif [[ $#collect -ne 1 ]]; then
         # If we have more than one possible match, this means that the
@@ -269,9 +282,17 @@ for prepath in "$prepaths[@]"; do
 	# these are file names and that `fignore' should be used as usual
 	# (the `-f' and `-F' options).
 
-        for i in $collect; do
-          compadd "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" -p "$linepath$testpath" -W "$tmp1" -s "/${i#*/}" -f "$ignore[@]" - "${i%%/*}"
-        done
+	if [[ $compstate[insert] = *menu ]]; then
+          compadd -QU "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" \
+                  -i "$IPREFIX" -p "${linepath:q}${testpath:q}" -S "/${ostr#*/}" \
+		  -W "$tmp1" -f "$ignore[@]" - "${(@)${(@)collect%%/*}:q}"
+	else
+          for i in $collect; do
+            compadd -U "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" \
+	            -i "$IPREFIX" -p "$linepath$testpath" -s "/${i#*/}" \
+		    -M 'r:|/=*' -W "$tmp1" -f "$ignore[@]" - "${i%%/*}"
+          done
+	fi
 
 	# We have just finished handling all the matches from above, so we
 	# can continue with the next `-W' path.
@@ -291,6 +312,7 @@ for prepath in "$prepaths[@]"; do
     tmp1="$tmp1[1]"
     testpath="$testpath${tmp1##*/}/"
     str="$rest"
+    ostr="${ostr#*/}"
   done
 
   # We are here if all pathname components except the last one (which is still
@@ -302,10 +324,24 @@ for prepath in "$prepaths[@]"; do
   suffixes=( $str$^pats )
   suffixes=( "${(@)suffixes:gs.**.*.}" )
   tmp2=( ${~tmp1}${~matchflags}${~suffixes} )
-  if [[ $#tmp2 -eq 0 && "$sopt" = */* ]]; then
+  if [[ $#tmp2 -eq 0 ]]; then
+    # No match, insert the expanded path and add the original tail.
+
     [[ "$testpath[-1]" = / ]] && testpath="$testpath[1,-2]"
-    compadd "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" -f - "$linepath$testpath"
+    [[ -n "$ostr" && -n "$linepath$testpath" ]] && ostr="/$ostr"
+
+    # But only if something changed.
+    [[ "$linepath$testpath$ostr" = "$PREFIX$SUFFIX" ]] && return 1
+
+    compadd -QU -S '' "$group[@]" "$expl[@]" \
+            -i "$IPREFIX" -f - "${linepath:q}${testpath:q}$ostr"
   else
-    compadd "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" -p "$linepath$testpath" -W "$prepath$realpath$testpath" -f "$ignore[@]" - ${(@)tmp2#$tmp1}
+    compadd -U "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" \
+            -i "$IPREFIX" -p "$linepath$testpath" -f "$ignore[@]" \
+	    -W "$prepath$realpath$testpath" - "${(@)tmp2#$tmp1}"
   fi
 done
+
+# This sets the return value to indicate that we added matches (or not).
+
+[[ nm -ne compstate[nmatches] ]]
diff --git a/Completion/README b/Completion/README
index ac2accfca..43ffcbcc2 100644
--- a/Completion/README
+++ b/Completion/README
@@ -11,14 +11,15 @@ loading much faster.  For example,
   [[ -f ~/completion/compinit ]] && . ~/completion/compinit -d
 This will rebind any keys which do completion to use the new system.
 For more detailed instructions, including how to add new completions, see
-the top of Core/compinit .
+the top of Core/compinit.
 
 The subdirectories contain:
 
 Core:
   The basic functions and files to be sourced.  You will certainly need
-  these, and will most likely not feel like altering them (or, in some
-  cases, even reading them, unless you are a shell wizard).  The files are:
+  these, and will most likely not want to alter them --- if you do, it
+  would probably help to give your version a different name.  The files
+  are:
   compinit
     As already described, this is not a function, but is sourced once
     (with the `source' or `.' commands) to set up the completion system.
@@ -29,6 +30,9 @@ Core:
   _comp_parts
     Utility used for completing words with multiple separate parts, such as
     `<user>@<host>'
+  _multi_parts
+    Utility for completion parts of words given a separator character and 
+    a list of words.
   _compalso
     Utility for calling a function to add additional completions to an
     already existing set.
@@ -46,7 +50,7 @@ Core:
     it is wider than just command+argument.)
   _path_files
     The function usually called to complete filenames and directories.  It
-    replaces the standard -f and -/ options for the basic completion
+    replaces the standard -f, -g and -/ options for the basic completion
     commands:  it can do various extra tricks, such as expanding a whole
     path at once, e.g. F/C/C/_p<TAB> -> Functions/Completion/Core/_path_files
 Base:
@@ -65,22 +69,29 @@ Base:
     as you wish.
   _match_pattern
   _match_test
-    These are used by Base/_path_files (and hence also Base/_files) for
-    file completion with control over matching (whether to complete
-    case-insensitively, or to allow insertion before `.', etc.)  See
-    _match_test for instructions.  Note _path_files expects these files
-    to be present.
+    These are used by Base/_path_files (and hence also Base/_files)
+    and Base/_comp_parts for file completion with control over
+    matching (whether to complete case-insensitively, or to allow
+    insertion before `.', etc.)  See _match_test for instructions.
+    Note _path_files expects these files to be present.
   _precommand
     Allows completion when the first word on the line has to be ignored,
     for example `noglob ...' should ignore the noglob and just complete
     as if it wasn't there.  Add other such commands to the top line.
   _redirect
-    Completes after `<' or `<': this version calls _files.
+    Completes after `<' or `>': this version calls _files.
   _subscript
     For completion in subscripts of parameters, e.g $foo[...].
   _vars
     Completion for commands which need variables (so this could also be in
     the Builtins directory), but also in math environments such as ((...)).
+  _tilde
+    Completion after `~', defaults to user names and named directories.
+  _equal
+    Completion after `=', normally command and alias names are used.
+  _parameter
+  _brace_parameter
+    For completion inside parameter expansions ($... and ${...).
 Builtins:
   Define completions for various shell builtins.  The top line of each file
   says which builtins they apply to; in many cases you can guess from the
diff --git a/Completion/User/_a2ps b/Completion/User/_a2ps
index 9aa9d3d99..600b58872 100644
--- a/Completion/User/_a2ps
+++ b/Completion/User/_a2ps
@@ -1,22 +1,22 @@
 #defcomp a2ps
 
-if [[ -prefix -- ]]; then
+if [[ "$PREFIX[1,2]" = -- ]]; then
   _comp_parts '(--borders --compact --truncate-lines --interpret
                 --print-anyway --delegate)' '=' '(yes no)'
   _comp_parts '(--major)' '=' '(rows columns)'
   _comp_parts '(--end-of-line)' '=' '(r n nr rn any)'
 
-  complist -S= -k '(--medium --columns --rows --line-numbers
+  compgen -S= -k '(--medium --columns --rows --line-numbers
                     --font-size --lines-per-page --chars-per-line
  		    --tabsize --non-printable-format --encoding
 		    --title --stdin --prologue --highlight-level
 		    --strip-level --output --version-control --suffix
 		    --printer --copies --sides --page-prefeed
 		    --no-page-prefeed)'
-  complist -qS= -k '(--margin --header --underlay --left-title
+  compgen -qS= -k '(--margin --header --underlay --left-title
                      --right-title --left-footer --footer --right-footer
 		     --pages --pretty-print)'
-  complist -k '(--landscape --portrait --catman --no-header)'
+  compgen -k '(--landscape --portrait --catman --no-header)'
 else
   _files -F fignore -g "*~*.ps"
 fi
diff --git a/Completion/User/_configure b/Completion/User/_configure
index de8d5fba5..050701fac 100644
--- a/Completion/User/_configure
+++ b/Completion/User/_configure
@@ -1,12 +1,35 @@
 #defcomp configure
 
+setopt localoptions extendedglob
+
 if [[ $PREFIX = *=* ]]; then
   # Complete filenames after e.g. --prefix=
   IPREFIX=${PREFIX%%=*}=
   PREFIX=${PREFIX#*=}
-  complist -f
+  compgen -f
 else
   # Generate a list of options from configure --help
-  complist -s '$($COMMAND --help |
-  sed -n -e '\''s/^ *\(--[-a-z0-9]*\)[    =,].*$/\1/p'\'')'
+  local -a pars
+  local i
+  pars=($($words[1] --help | awk '$1 ~ /--[a-z]*.*/ {print $1}'))
+  for i in $pars
+  do
+    case $i in
+      (--(((en|dis)able-FEATURE)|(with(out|)-PACKAGE))*)
+        : Skip standard help output
+      ;;
+      --enable)
+        : Skip standard help output
+      ;;
+      --*\[=* )
+        compadd -M 'r:|-=* r:|=*' -q -S = -- ${i%%\[=*}
+      ;;
+      --*=* )
+        compadd -M 'r:|-=* r:|=*' -S = -- ${i%%=*}
+      ;;
+      * )
+        compadd -M 'r:|-=* r:|=*' -- $i
+      ;;
+    esac
+  done
 fi
diff --git a/Completion/User/_dd b/Completion/User/_dd
index 2458541ea..86a47b1ab 100644
--- a/Completion/User/_dd
+++ b/Completion/User/_dd
@@ -4,10 +4,10 @@ if [[ -iprefix conv= ]]; then
   # If there's a comma present, ignore up to the last one.  The
   # test alone will have that effect.
   [[ -string , ]]
-  complist -S, -q \
+  compgen -S, -q \
   -k '(ascii ebcdic ibm block unblock lcase ucase swab noerror sync)'
 elif [[ -iprefix 'if=' || -iprefix 'of=' ]]; then
   _files
 else
-  complist -S '=' -k '(if of ibs obs bs cbs skip files seek count conv)'
+  compgen -S '=' -k '(if of ibs obs bs cbs skip files seek count conv)'
 fi
diff --git a/Completion/User/_find b/Completion/User/_find
index ca4f79908..8fcdafb83 100644
--- a/Completion/User/_find
+++ b/Completion/User/_find
@@ -1,21 +1,23 @@
 #defcomp find
 
+local prev="$words[CURRENT-1]"
+
 if [[ -mbetween -(ok|exec) \\\; ]]; then
-  _normal "$@"
+  _normal
 elif [[ -iprefix - ]]; then
-  complist -s 'daystart {max,min,}depth follow noleaf version xdev \
+  compgen -s 'daystart {max,min,}depth follow noleaf version xdev \
     {a,c,}newer {a,c,m}{min,time} empty false {fs,x,}type gid inum links \
     {i,}{l,}name {no,}{user,group} path perm regex size true uid used \
     exec {f,}print{f,0,} ok prune ls'
-elif [[ -position 1 ]]; then
-  complist -g '. ..'
+elif [[ -position 2 ]]; then
+  compgen -g '. ..'
   _files -g '(-/)'
-elif [[ -mcurrent -1 -((a|c|)newer|fprint(|0|f)) ]]; then
+elif [[ "$prev" = -((a|c|)newer|fprint(|0|f)) ]]; then
   _files
-elif [[ -current -1 -fstype ]]; then
-  complist -k '(ufs 4.2 4.3 nfs tmp mfs S51K S52K)'
-elif [[ -current -1 -group ]]; then
-  complist -k groups
-elif [[ -current -1 -user ]]; then
-  complist -u
+elif [[ "$prev" = -fstype ]]; then
+  compgen -k '(ufs 4.2 4.3 nfs tmp mfs S51K S52K)'
+elif [[ "$prev" = -group ]]; then
+  compgen -k groups
+elif [[ "$prev" = -user ]]; then
+  compgen -u
 fi
diff --git a/Completion/User/_hosts b/Completion/User/_hosts
index 3acc327ac..eb418c5b3 100644
--- a/Completion/User/_hosts
+++ b/Completion/User/_hosts
@@ -1,3 +1,3 @@
 #defcomp ftp ncftp ping rwho rup xping traceroute nslookup
 
-complist -k hosts
+compgen -k hosts
diff --git a/Completion/User/_make b/Completion/User/_make
index d576b0308..24d2cf3f5 100644
--- a/Completion/User/_make
+++ b/Completion/User/_make
@@ -1,3 +1,3 @@
 #defcomp make gmake pmake
 
-complist -s "\$(awk '/^[a-zA-Z0-9][^/ 	]+:/ {print \$1}' FS=: [mM]akefile)"
+compgen -s "\$(awk '/^[a-zA-Z0-9][^/ 	]+:/ {print \$1}' FS=: [mM]akefile)"
diff --git a/Completion/User/_man b/Completion/User/_man
index 8204fba0b..67d59f24a 100644
--- a/Completion/User/_man
+++ b/Completion/User/_man
@@ -2,10 +2,10 @@
 setopt localoptions rcexpandparam
 
 local rep
-if [[ $2 = (<->*|ln) ]]; then
-  rep=( $manpath/(man|cat)$2/$PREFIX*$SUFFIX.<->*(N:t:r) )
+if [[ $words[2] = (<->*|ln) ]]; then
+  rep=( $manpath/(man|cat)${words[2]}/$PREFIX*$SUFFIX.<->*(N:t:r) )
 else
   rep=( $manpath/(man|cat)*/$PREFIX*$SUFFIX.<->*(N:t:r) )
 fi
 
-(( $#rep )) && compadd -m $rep
+(( $#rep )) && compadd - $rep
diff --git a/Completion/User/_mh b/Completion/User/_mh
index 67ce49fd2..7e8575123 100644
--- a/Completion/User/_mh
+++ b/Completion/User/_mh
@@ -1,4 +1,4 @@
-#defcomp folder comp inc mark refile repl scan show next prev rmm pick whom mhn mhpath mhpatch
+#defcomp folder folders comp inc mark refile repl scan show next prev rmm pick whom mhn mhpath
 
 # Completion for all possible MH commands.
 # Alter the following two to your own mh directory and the directory
@@ -7,6 +7,8 @@
 local mymhdir=~/Mail
 local mhlib=/usr/lib/mh
 
+local prev="$words[CURRENT-1]"
+
 # To be on the safe side, check this exists and if not, get it anyway.
 [[ -d $mymhdir ]] || mymhdir=$(mhpath +)
 
@@ -14,13 +16,13 @@ if [[ -iprefix - ]]; then
   # get list of options, which MH commands can generate themselves
   # awk is just too icky to use for this, sorry.  send me one if
   # you come up with it.
-  compadd -m $($COMMAND -help | perl -ne 'if (/^\s*-\(?(\S+)/) {
+  compadd - $($words[1] -help | perl -ne 'if (/^\s*-\(?(\S+)/) {
     $n = $1;
     $n =~ s/\)//g;
     print $n =~ s/^\[([a-z]+)\]// ? "$n\n$1$n\n" : "$n\n";
   }')
   return
-elif [[ -iprefix '+' || -iprefix '@' || -current -1 -draftfolder ]]; then
+elif [[ -iprefix '+' || -iprefix '@' || "$prev" = -draftfolder ]]; then
   # Complete folder names.
   local mhpath
   if [[ $IPREFIX != '@' ]]; then
@@ -31,12 +33,12 @@ elif [[ -iprefix '+' || -iprefix '@' || -current -1 -draftfolder ]]; then
   fi
 
   # painless, or what?
-  complist -W mhpath -/
-elif [[ -mcurrent -1 -(editor|(whatnow|rmm|show|more)proc) ]]; then
-  complist -c
-elif [[ -current -1 -file ]]; then
-  complist -f
-elif [[ -mcurrent -1 -(form|audit|filter) ]]; then
+  _path_files -W mhpath -/
+elif [[ "$prev" = -(editor|(whatnow|rmm|show|more)proc) ]]; then
+  compgen -c
+elif [[ "$prev" = -file ]]; then
+  compgen -f
+elif [[ "$prev" = -(form|audit|filter) ]]; then
   # Need some MH template file, which may be in our own MH directory
   # or with the standard library.
   local mhfpath
@@ -44,11 +46,11 @@ elif [[ -mcurrent -1 -(form|audit|filter) ]]; then
   [[ -d $mhlib ]] || { mhlib=$(mhparam mhlproc); mhlib=$mhlib:h; }
   mhfpath=($mymhdir $mhlib)
 
-  complist -W mhfpath -g '*(.)'
-elif [[ -mcurrent -1 -(no|)cc ]]; then
-  compadd -m all to cc me
-elif [[ -mcurrent -1 -[rw]cache ]]; then
-  compadd -m public private never ask
+  compgen -W mhfpath -g '*(.)'
+elif [[ "$prev" = -(no|)cc ]]; then
+  compadd all to cc me
+elif [[ "$prev" = -[rw]cache ]]; then
+  compadd public private never ask
 else
   # Generate sequences.
   local foldnam folddir f
@@ -64,7 +66,7 @@ else
     # leaving foldnam empty works here
   fi
 
-  complist -s '$(mark $foldnam | awk -F: '\''{ print $1 }'\'')'
-  compadd -m reply next cur prev first last all unseen
-  complist -W folddir -g '<->'
+  compgen -s '$(mark $foldnam 2>/dev/null | awk -F: '\''{ print $1 }'\'')'
+  compadd reply next cur prev first last all unseen
+  compgen -W folddir -g '<->'
 fi
diff --git a/Completion/User/_rcs b/Completion/User/_rcs
index 537db6278..5a751605c 100644
--- a/Completion/User/_rcs
+++ b/Completion/User/_rcs
@@ -1,9 +1,11 @@
 #defcomp co ci rcs
 
-[[ $COMMAND = ci || $COMMAND = rcs ]] && _files
+local nm=$compstate[nmatches]
 
-if [[ $NMATCHES -eq 0 && -d RCS && $COMMAND != ci ]]; then
+[[ $words[1] = ci || $words[1] = rcs ]] && _files
+
+if [[ $compstate[nmatches] -eq nm && -d RCS && $words[1] != ci ]]; then
   local rep
   rep=(RCS/$PREFIX*$SUFFIX,v(:t:s/\,v//))
-  (( $#rep )) && compadd -m $rep
+  (( $#rep )) && compadd - $rep
 fi
diff --git a/Completion/User/_rlogin b/Completion/User/_rlogin
index e36554f23..5d6daef9b 100644
--- a/Completion/User/_rlogin
+++ b/Completion/User/_rlogin
@@ -1,9 +1,9 @@
 #defcomp rlogin rsh ssh
 
-if [[ -position 1 ]]; then
-  complist -k hosts
-elif [[ -position 2 ]]; then
-  complist -k '(-l)'
+if [[ CURRENT -eq 2 ]]; then
+  compgen -k hosts
+elif [[ CURRENT -eq 3 ]]; then
+  compgen -k '(-l)'
 else
-  complist -u
+  compgen -u
 fi
diff --git a/Completion/User/_stty b/Completion/User/_stty
index 6b54b5007..d32d6bdff 100644
--- a/Completion/User/_stty
+++ b/Completion/User/_stty
@@ -1,12 +1,12 @@
 #defcomp stty
 
-if [[ -mcurrent -1 \
+if [[ "$words[CURRENT-1]" = \
   (*erase|discard|status|dsusp|intr|kill|lnext|quit|reprint|start|s*p) ]]
 then
-     compadd -m -Q '^-' '^h' '^?' '^c' '^u'
+     compadd -Q '^-' '^h' '^?' '^c' '^u'
 else
   [[ -string '-' || -string '+' ]]
-  compadd -m rows columns intr quit erase kill eof eol \
+  compadd rows columns intr quit erase kill eof eol \
     eol2 start stop susp dsusp reprint discard werase lnext \
     parenb parodd cs8 cstopb hupcl cread clocal parext \
     ignbrk brkint ignpar parmrk inpck istrip inlcr igncr icrnl iuclc \
diff --git a/Completion/User/_tar b/Completion/User/_tar
index 91767e44d..84c490f1e 100644
--- a/Completion/User/_tar
+++ b/Completion/User/_tar
@@ -1,11 +1,69 @@
 #defcomp tar
 
-local nm=$NMATCHES tf="$2"
+# Tar completion.  Features:
+#  - Assumes tar commands are in second position, tar archive is in third
+#    e.g. tar xvzf zsh-3.0.5.tar.gz ...
+#    Could search better.  Send me the patch.
+#  - `tar' can be called anything, will use the correct name
+#  - Preferentially completes *.tar and *.TAR files in third position
+#  - unless z or Z appears in the commands, in which case prefer *.tar.gz
+#    and similar (GNU tar).
+#  - From fourth position on, if command is x or t, completes files inside
+#    archive.  This is supposed to look pretty much as if the files are
+#    in an ordinary directory hierarchy.  Handles extraction from compressed
+#    archives (GNU tar).
+#  - Anywhere -- appears, gets a list of long options to complete from
+#    tar itself (GNU tar); this needs perl.  If you have GNU tar but not
+#    perl:  your system manager is weird.
+#  - Things like --directory=... are also completed correctly.
 
-if [[ ( -mword 1 *t*f* || -mword 1 *x*f* ) && -position 3 100000 ]]; then
-  complist -k "( $(tar tf $tf) )"
-elif [[ -mword 1 *c*f* && -position 3 100000 ]]; then
+emulate -LR zsh
+setopt extendedglob
+
+local nm=$NMATCHES tcmd="$words[2]" tf="$words[3]"
+
+if [[ $PREFIX = *=* ]]; then
+  # For GNU tar arguments like --directory=
+  IPREFIX=${PREFIX%%\=*}=
+  PREFIX=${PREFIX#*=}
+  if [[ $IPREFIX = --directory* ]]; then
+    _path_files -/
+  else
+    _files
+  fi
+elif [[ $PREFIX = --* ]]; then
+  # gnu tar, generate completions from --help
+  # ones followed by = get that as a suffix
+  local -a ownlist eqlist
+  local comp
+  $words[1] --help |
+  perl -ne 'while (/--[^[\s,='\'']+=?/g) { print "$&\n"; }' |
+  while read comp; do
+    if [[ $comp = *= ]]; then
+      eqlist[$#eqlist+1]=${comp%=}
+    else
+      ownlist[$#ownlist+1]=$comp
+    fi
+  done
+  compgen -S '=' -k eqlist
+  compgen -k ownlist
+elif [[ "$tcmd" = *[tx]*f* && $CURRENT -ge 4 ]] then
+  # Listing or extracting a particular file.  We run `tar t...'
+  # on the file, keeping the list of filenames cached, plus the
+  # name of the tarfile so we know if it changes.
+  local largs=-tf
+
+  [[ $words[2] = *z* ]] && largs=-tzf
+  [[ $words[2] = *Z* ]] && largs=-tZf
+  if [[ $tf != $tar_cache_name ]]; then
+    tar_cache_list=("${(@f)$($words[1] $largs $tf)}")
+    tar_cache_name=$tf
+  fi
+  _multi_parts / tar_cache_list
+elif [[ "$tcmd" = *c*f* && $CURRENT -ge 4 ]] then
   _files
-elif [[ -mcurrent -1 *f* && -position 2 ]]; then
+elif [[ "$tcmd" = *[zZ]*f* && $CURRENT -eq 3 ]] then
+  _files -g '*.((tar|TAR).(gz|Z)|.tgz)'
+elif [[ "$tcmd" = *f* && $CURRENT -eq 3 ]] then
   _files -g '*.(tar|TAR)'
 fi
diff --git a/Completion/User/_x_options b/Completion/User/_x_options
index cc469286d..3190ee377 100644
--- a/Completion/User/_x_options
+++ b/Completion/User/_x_options
@@ -2,4 +2,4 @@
 
 # A simple pattern completion, just as an example.
 
-complist -J options -k '(-display -name -xrm)'
+compgen -J options -k '(-display -name -xrm)'