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:20:19 +0000
committerTanaka Akira <akr@users.sourceforge.net>1999-04-15 18:20:19 +0000
commit04a89199d02a3ee6c4b3d89a6c782bdb0a4f1bc8 (patch)
tree2215f99f95d55660fc939a029bf965c454d080b5 /Completion
parent7a0415cfd70a02b2280d27556c6c54cef1c86e1a (diff)
downloadzsh-04a89199d02a3ee6c4b3d89a6c782bdb0a4f1bc8.tar.gz
zsh-04a89199d02a3ee6c4b3d89a6c782bdb0a4f1bc8.tar.xz
zsh-04a89199d02a3ee6c4b3d89a6c782bdb0a4f1bc8.zip
zsh-3.1.5-pws-12 zsh-3.1.5-pws-12
Diffstat (limited to 'Completion')
-rw-r--r--Completion/.distfiles3
-rw-r--r--Completion/Base/.distfiles6
-rw-r--r--Completion/Base/_command_names10
-rw-r--r--Completion/Base/_condition8
-rw-r--r--Completion/Base/_default2
-rw-r--r--Completion/Base/_long_options309
-rw-r--r--Completion/Base/_match_pattern6
-rw-r--r--Completion/Base/_subscript9
-rw-r--r--Completion/Builtins/.distfiles7
-rw-r--r--Completion/Builtins/_bindkey11
-rw-r--r--Completion/Builtins/_cd13
-rw-r--r--Completion/Builtins/_disable12
-rw-r--r--Completion/Builtins/_enable12
-rw-r--r--Completion/Builtins/_kill8
-rw-r--r--Completion/Builtins/_setopt9
-rw-r--r--Completion/Builtins/_unhash12
-rw-r--r--Completion/Builtins/_unsetopt9
-rw-r--r--Completion/Builtins/_wait8
-rw-r--r--Completion/Builtins/_zftp3
-rw-r--r--Completion/Commands/.distfiles3
-rw-r--r--Completion/Core/.distfiles5
-rw-r--r--Completion/Core/_compalso6
-rw-r--r--Completion/Core/_files11
-rw-r--r--Completion/Core/_main_complete118
-rw-r--r--Completion/Core/_normal16
-rw-r--r--Completion/Core/_path_files141
-rw-r--r--Completion/Core/_sep_parts171
-rw-r--r--Completion/Core/compdump2
-rw-r--r--Completion/Core/compinit48
-rw-r--r--Completion/README14
-rw-r--r--Completion/User/.distfiles6
-rw-r--r--Completion/User/_a2ps53
-rw-r--r--Completion/User/_configure35
-rw-r--r--Completion/User/_dd2
-rw-r--r--Completion/User/_find8
-rw-r--r--Completion/User/_man2
-rw-r--r--Completion/User/_mh14
-rw-r--r--Completion/User/_rcs1
-rw-r--r--Completion/User/_strip1
-rw-r--r--Completion/User/_tar162
-rw-r--r--Completion/User/_tar_archive20
41 files changed, 1041 insertions, 255 deletions
diff --git a/Completion/.distfiles b/Completion/.distfiles
new file mode 100644
index 000000000..c50107c61
--- /dev/null
+++ b/Completion/.distfiles
@@ -0,0 +1,3 @@
+DISTFILES_SRC='
+    .distfiles README
+'
diff --git a/Completion/Base/.distfiles b/Completion/Base/.distfiles
new file mode 100644
index 000000000..7e7635fa6
--- /dev/null
+++ b/Completion/Base/.distfiles
@@ -0,0 +1,6 @@
+DISTFILES_SRC='
+    .distfiles 
+    _brace_parameter _command_names _condition _default _equal
+    _long_options _match_pattern _match_pattern.orig _match_test _parameter
+    _precommand _redirect _subscript _tilde _vars 
+'
diff --git a/Completion/Base/_command_names b/Completion/Base/_command_names
index eab314dfa..f21af674c 100644
--- a/Completion/Base/_command_names
+++ b/Completion/Base/_command_names
@@ -1,7 +1,11 @@
 #defcomp -command-
 
-local nm=$compstate[nmatches]
+local nm=$compstate[nmatches] ret=1
 
-compgen -c
+compgen -c && ret=0
 
-[[ nm -eq compstate[nmatches] ]] && _path_files -/g "*(*)"
+if [[ nm -eq compstate[nmatches] ]]; then
+  _path_files -/g "*(*)"
+else
+  return ret
+fi
diff --git a/Completion/Base/_condition b/Completion/Base/_condition
index fb6b98b1b..db1adfd9a 100644
--- a/Completion/Base/_condition
+++ b/Completion/Base/_condition
@@ -7,6 +7,10 @@ if [[ "$prev" = -o ]]; then
 elif [[ "$prev" = -([no]t|ef) ]]; then
   _files
 else
-  _files
-  compgen -v
+  local ret=1
+
+  _files && ret=0
+  compgen -v && ret=0
+
+  return ret
 fi
diff --git a/Completion/Base/_default b/Completion/Base/_default
index 569bd6382..9ea1a09db 100644
--- a/Completion/Base/_default
+++ b/Completion/Base/_default
@@ -9,6 +9,6 @@
 # and insert the line `[[ compstate[nmatches] -eq 0 ]] || return' after
 # `compcall'.
 
-compcall || return
+compcall || return 0
 
 _files
diff --git a/Completion/Base/_long_options b/Completion/Base/_long_options
new file mode 100644
index 000000000..a5d92632c
--- /dev/null
+++ b/Completion/Base/_long_options
@@ -0,0 +1,309 @@
+#autoload
+
+# This function tries to automatically complete long option names. For 
+# this it invokes the command from the line with the `--help' option
+# and then parses the output to find possible option names. For
+# options that get an argument after a `=', the function also tries to 
+# automatically find out what should be complete as the argument.
+# The possible completions for option-arguments can be described with
+# the arguments to this function. This is done by giving pairs of
+# patterns and actions as consecutive arguments. The actions specify
+# what should be done to complete arguemts of those options that match 
+# the pattern. The action may be a list of words in brackets or in
+# parentheses, separated by spaces. A list in brackets denotes
+# possible values for an optional argument, a list in parentheses
+# gives words to complete for mandatory arguments. If the action does
+# not start with a bracket or parentheses, it should be the name of a
+# command (probably with arguments) that should be invoked to complete 
+# after the equal sign. E.g.:
+#
+#  _long_options '*\*'     '(yes no)' \
+#                '*=FILE*' '_files' \
+#                '*=DIR*'  '_files -/'
+#
+# This makes `yes' and `no' be completed as the argument of options
+# whose description ends in a star, file names for options that
+# contain the substring `=FILE' in the description, and paths for
+# options whose description contains `=DIR'. Note the last two
+# patterns are not needed since this function always completes files
+# for option descriptions containing `=FILE' and paths for option
+# descriptions that contain `=DIR' or `=PATH'. These builtin patterns
+# can be overridden by patterns given as arguments, though.
+#
+# This function also accepts the `-X', `-J', and `-V' options which
+# are given to `compadd'. Finally, it accepts the option `-t'. If this 
+# is given, completion is only done on words starting with two hyphens.
+
+local opt expl group test i name action ret=1 tmp suffix
+
+setopt extendedglob
+
+# Get the options.
+
+group=()
+expl=()
+if [[ $1 = -*~--* ]]; then
+  while getopts "J:V:X:t" opt; do
+    case "$opt" in
+      [JV]) group=("-$opt" "$OPTARG");;
+      X)    expl=(-X "$OPTARG");;
+      t)    test=yes;;
+    esac
+  done
+  shift OPTIND-1
+fi
+
+# Test if we are completing after `--' if we were asked to do so.
+
+[[ -n "$test" && "$PREFIX" != --* ]] && return 1
+
+# We cache the information about options and the command name, see if
+# we can use the cache.
+
+if [[ "$words[1]" = (.|..)/* ]]; then
+  tmp="$PWD/$words[1]"
+else
+  tmp="$words[1]"
+fi
+
+if [[ "$tmp" != $_lo_cache_cmd ]]; then
+
+  # No, store the new command name and clear the old parameters.
+
+  _lo_cache_cmd="$tmp"
+  (( $+_lo_cache_actions )) && unset "$_lo_cache_names[@]" _lo_cache_actions _lo_cache_names
+
+  local opts pattern anum=1 tmpo str
+
+  # Now get the long option names by calling the command with `--help'.
+  # The parameter expansion trickery first gets the lines as separate
+  # array elements. Then we select all lines whose first non-blank
+  # character is a hyphen. Since some commands document more than one
+  # option per line, separated by commas, we convert commas int
+  # newlines and then split the result again at newlines after joining 
+  # the old array elements with newlines between them. Then we select
+  # those elements that start with two hyphens, remove anything up to
+  # those hyphens and anything from the space or comma after the
+  # option up to the end. Finally all elements with option strings
+  # that contain uppercase letters are removed.
+
+  opts=("--${(@)^${(@)${(@)${(@M)${(@ps:\n:j:\n:)${(@)${(@M)${(@f)$("$words[1]" --help)}:#[ 	]#-*}//,/
+}}:#[ 	]#--*}#*--}%%[, ]*}:#(*-[A-Z]*|)}")
+
+  # The interpretation of the options is completely table driven. We
+  # use the positional parameters we were given and a few standard
+  # ones. Then we loop through this table.
+
+  set -- "$@" '*=FILE*' '_files' '*=(DIR|PATH)*' '_files -/' '*' ''
+
+  while [[ $# -gt 1 ]]; do
+
+    # First, we get the pattern and the action to use and take them
+    # from the positional parameters.
+
+    pattern="$1"
+    action="$2"
+    shift 2
+
+    # We get all options matching the pattern and take them from the
+    # list we have built. If no option matches the pattern, we
+    # continue with the next.
+
+    tmp=("${(@M)opts:##$~pattern}")
+    opts=("${(@)opts:##$~pattern}")
+
+    (( $#tmp )) || continue
+
+    # Now we collect the options for the pattern in an array. We also
+    # check if the options take an argument after a `=', and if this
+    # argument is optional. The name of the array built contains
+    # `_arg_' for mandatory arguments, `_optarg_' for optional
+    # arguments, and `_simple_' for options that don't get an
+    # argument. In `_lo_cache_names' we save the names of these
+    # arrays and in `_lo_cache_actions' the associated actions.
+
+    # If the action is a list of words in brackets, this denotes
+    # options that get an optional argument. If the action is a list
+    # of words in parentheses, the option has to get an argument.
+    # In both cases we just build the array name to use.
+
+    if [[ "$action[1]" = '[' ]]; then
+      name="_lo_cache_optarg_$anum"
+    elif [[ "$action[1]" = '(' ]]; then
+      name="_lo_cache_arg_$anum"
+    else
+
+      # If there are option strings with a `[=', we take make these
+      # get an optional argument...
+
+      tmpo=("${(@M)tmp:#*\[\=*}")
+      if (( $#tmpo )); then
+
+        # ...by removing them from the option list and storing them in 
+	# an array.
+
+        tmp=("${(@)tmp:#*\[\=*}")
+        tmpo=("${(@)${(@)tmpo%%\=*}//[^a-z0-9-]}")
+        _lo_cache_names[anum]="_lo_cache_optarg_$anum"
+        _lo_cache_actions[anum]="$action"
+        eval "_lo_cache_optarg_${anum}=(\"\$tmpo[@]\")"
+	(( anum++ ))
+      fi
+
+      # Now we do the same for option strings containing `=', these
+      # are options getting an argument.
+
+      tmpo=("${(@M)tmp:#*\=*}")
+      if (( $#tmpo )); then
+        tmp=("${(@)tmp:#*\=*}")
+        tmpo=("${(@)${(@)tmpo%%\=*}//[^a-z0-9-]}")
+        _lo_cache_names[anum]="_lo_cache_arg_$anum"
+        _lo_cache_actions[anum]="$action"
+        eval "_lo_cache_arg_${anum}=(\"\$tmpo[@]\")"
+	(( anum++ ))
+      fi
+
+      # The name for the options without arguments, if any.
+
+      name="_lo_cache_simple_$anum"
+    fi
+    # Now filter out any option strings we don't like and stuff them
+    # in an array, if there are still some.
+
+    tmp=("${(@)${(@)tmp%%\=*}//[^a-z0-9-]}")
+    if (( $#tmp )); then
+      _lo_cache_names[anum]="$name"
+      _lo_cache_actions[anum]="$action"
+      eval "${name}=(\"\$tmp[@]\")"
+      (( anum++ ))
+    fi
+  done
+fi
+
+# We get the string from the line and and see if it already contains a 
+# equal sign.
+
+str="$PREFIX$SUFFIX"
+
+if [[ "$str" = *\=* ]]; then
+
+  # It contains a `=', now we ignore anything up to it, but first save 
+  # the old contents of the special parameters we change.
+
+  local oipre opre osuf pre parto parta pat patflags anum=1
+
+  oipre="$IPREFIX"
+  opre="$PREFIX"
+  osuf="$SUFFIX"
+
+  pre="${str%%\=*}"
+  IPREFIX="${IPREFIX}${pre}="
+  PREFIX="${str#*\=}"
+  SUFFIX=""
+
+  # We will check if the arrays contain an option matching what's on
+  # the line. To do this good, we build a pattern.
+
+  [[ -n "$_comp_correct" && $#pre -le _comp_correct ]] && return 1
+
+  pat="${pre}*"
+  patflags=''
+  _match_pattern _long_options pat patflags
+  [[ -n "$_comp_correct" ]] && patflags="$patflags(#a$_comp_correct)"
+
+  # Then we walk through the array names. For each array we test if it 
+  # contains the option string. If so, we `invoke' the action stored
+  # with the name. If the action is a list of words, we just add them, 
+  # otherwise we invoke the command or function named.
+
+  for name in "$_lo_cache_names[@]"; do
+    action="$_lo_cache_actions[anum]"
+    if (( ${(@)${(@P)name}[(I)$pre]} )); then
+      if [[ "$action[1]" = (\[|\() ]]; then
+        compadd - ${=action[2,-2]}
+      elif (( $#action )); then
+        $=action
+      fi
+
+      # We found the option string, return.
+
+      return
+    fi
+
+    # The array did not contain the full option string, see if it
+    # contains a string matching the string from the line.
+    # If there is one, we store the option string in `parto' and the
+    # element from `_lo_actions' in `parta'. If we find more than one
+    # such option or if we already had one, we set `parto' to `-'.
+
+    tmp=("${(@M)${(@P)name}:#${~pat}}")
+    if [[ $#tmp -eq 1 ]]; then
+      if [[ -z "$parto" ]]; then
+        parto="$tmp[1]"
+	parta="$action"
+      else
+        parto=-
+      fi
+    elif (( $#tmp )); then
+      parto=-
+    fi
+    (( anum++ ))
+  done
+
+  # If we found only one matching option, we accept it and immediatly
+  # try to complete the string after the `='.
+
+  if [[ -n "$parto" && "$parto" != - ]]; then
+    IPREFIX="${parto}="
+
+    if (( $#parta )); then
+      if [[ "$parta[1]" = (\[|\() ]]; then
+        compadd - ${=parta[2,-2]}
+      else
+        $=parta
+      fi
+    else
+      compadd -S '' - "$PREFIX"
+    fi
+    return
+  fi
+
+  # The option string was not found, restore the special parameters.
+
+  IPREFIX="$oipre"
+  PREFIX="$opre"
+  SUFFIX="$osuf"
+fi
+
+# The string on the line did not contain a `=', or we couldn't
+# complete the option string since there were more than one matching
+# what's on the line. So we just ad the option string as possible
+# matches, giving the string from the `=' on as a suffix.
+
+if [[ "$str" = *\=* ]]; then
+  str="=${str#*\=}"
+  PREFIX="${PREFIX%%\=*}"
+  suffix=()
+else
+  str=""
+  suffix=('-S=')
+fi
+
+anum=1
+for name in "$_lo_cache_names[@]"; do
+  action="$_lo_cache_actions[anum]"
+
+  if [[ "$name" = *_optarg_* ]]; then
+    compadd -M 'r:|-=* r:|=*' -Qq "$suffix[@]" -s "$str" - \
+            "${(@P)name}" && ret=0
+  elif [[ "$name" = *_arg_* ]]; then
+    compadd -M 'r:|-=* r:|=*' -Q "$suffix[@]" -s "$str" - \
+            "${(@P)name}" && ret=0
+  elif [[ -z "$str" ]]; then
+    compadd -M 'r:|-=* r:|=*' -Q - \
+            "${(@P)name}" && ret=0
+  fi
+  (( anum++ ))
+done
+
+return ret
diff --git a/Completion/Base/_match_pattern b/Completion/Base/_match_pattern
index 3df115d5b..91930a571 100644
--- a/Completion/Base/_match_pattern
+++ b/Completion/Base/_match_pattern
@@ -28,4 +28,10 @@
 # like the `r:|[.-]=* r:|=*'. To make this work, the function `_match_test'
 # would have to be changed to `(( compstate[matcher] <= 2 ))'
 #
+# When automatic correction is used (see the file `_main_complete'), you
+# probably don't want to set matching flags here as that may make the
+# results slightly unpredictable. For this, change the line above to:
+#
+#   [[ compstate[matcher] -lt 0 ]] && eval "${3}='(#l)'"
+#
 # The default implementation of this function is empty.
diff --git a/Completion/Base/_subscript b/Completion/Base/_subscript
index d50fd8335..670739a9a 100644
--- a/Completion/Base/_subscript
+++ b/Completion/Base/_subscript
@@ -1,5 +1,10 @@
 #defcomp -subscript-
 
-_compalso -math-
+local ret=1
+
+_compalso -math- && ret=0
+
 [[ ${(Pt)${compstate[parameter]}} = assoc* ]] &&
-    compgen -k "( ${(kP)${compstate[parameter]}} )"
+  compgen -k "( ${(kP)${compstate[parameter]}} )" && ret=0
+
+return ret
diff --git a/Completion/Builtins/.distfiles b/Completion/Builtins/.distfiles
new file mode 100644
index 000000000..97906e91f
--- /dev/null
+++ b/Completion/Builtins/.distfiles
@@ -0,0 +1,7 @@
+DISTFILES_SRC='
+    .distfiles
+    _aliases _arrays _autoload _bg_jobs _bindkey _builtin _cd _command
+    _dirs _disable _echotc _enable _fc _functions _hash _jobs _kill
+    _limits _sched _set _setopt _source _trap _unhash _unsetopt _vars_eq
+    _wait _which _zftp _zle _zmodload 
+'
diff --git a/Completion/Builtins/_bindkey b/Completion/Builtins/_bindkey
index d3d019492..6fca200ba 100644
--- a/Completion/Builtins/_bindkey
+++ b/Completion/Builtins/_bindkey
@@ -1,7 +1,14 @@
 #defcomp bindkey
 
-if [[ "$words[2]" = -*[DAN]* || "$words[CURRENT-1] = -*M ]]; then
+# Normally, this completes names of zle widgets, whether the builtin ones
+# or ones defined by the user.  Note that a - allows a wildcard before it,
+# so h-b-s-b will complete to history-beginning-search-backward.  You
+# can alter this by removing the -M ... from the second compgen.
+#
+# Where appropriate, will complete keymaps instead of widgets.
+
+if [[ "$words[2]" = -*[DAN]* || "$words[CURRENT-1]" = -*M ]]; then
   compgen -s '$(bindkey -l)'
 else
-  compgen -b
+  compgen -b -M 'r:|-=* r:|=*'
 fi
diff --git a/Completion/Builtins/_cd b/Completion/Builtins/_cd
index 65ce7f293..9a58effe0 100644
--- a/Completion/Builtins/_cd
+++ b/Completion/Builtins/_cd
@@ -24,7 +24,7 @@ if [[ -position 3 ]]; then
   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
+  (( ! $#rep )) || compadd $rep
 elif [[ $words[1] = pu* && $PREFIX = [-+]* ]]; then
   # pushd: just complete the numbers, but show the full directory list with
   # numbers.
@@ -34,7 +34,8 @@ elif [[ $words[1] = pu* && $PREFIX = [-+]* ]]; then
   # lazy to type pushd.
   IPREFIX=$PREFIX[1]
   PREFIX=$PREFIX[2,-1]
-  local list lines
+  local list lines ret=1
+
   # get the list of directories with their canonical number
   lines="$(dirs -v)"
   # turn the lines into an array, removing the current directory
@@ -52,9 +53,11 @@ elif [[ $words[1] = pu* && $PREFIX = [-+]* ]]; then
   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
+  compgen -y '$lines' -Q -k list && ret=0
+  [[ -z $compstate[list] ]] && compstate[list]=list && ret=0
+  [[ -n $compstate[insert] ]] && compstat[insert]=menu && ret=0
+
+  return ret
 elif [[ $PREFIX != (\~|/|./|../)* && $#cdpath -ne 0 ]]; then
   _path_files -W cdpath -/
 else
diff --git a/Completion/Builtins/_disable b/Completion/Builtins/_disable
index e3edafe2b..27db5c18f 100644
--- a/Completion/Builtins/_disable
+++ b/Completion/Builtins/_disable
@@ -1,8 +1,10 @@
 #defcomp disable
 
-local prev="$words[CURRENT-1]"
+local prev="$words[CURRENT-1]" ret=1
 
-[[ "$prev" = -*a* ]] && compgen -ea
-[[ "$prev" = -*f* ]] && compgen -eF
-[[ "$prev" = -*r* ]] && compgen -ew
-[[ "$prev" != -* ]] && compgen -eB
+[[ "$prev" = -*a* ]] && compgen -ea && ret=0
+[[ "$prev" = -*f* ]] && compgen -eF && ret=0
+[[ "$prev" = -*r* ]] && compgen -ew && ret=0
+[[ "$prev" != -* ]]  && compgen -eB && ret=0
+
+return ret
diff --git a/Completion/Builtins/_enable b/Completion/Builtins/_enable
index 111d1ae26..1baa09ed6 100644
--- a/Completion/Builtins/_enable
+++ b/Completion/Builtins/_enable
@@ -1,8 +1,10 @@
 #defcomp enable
 
-local prev="$words[CURRENT-1]"
+local prev="$words[CURRENT-1]" ret=1
 
-[[ "$prev" = -*a* ]] && compgen -da
-[[ "$prev" = -*f* ]] && compgen -dF
-[[ "$prev" = -*r* ]] && compgen -dw
-[[ "$prev" != -* ]] && compgen -dB
+[[ "$prev" = -*a* ]] && compgen -da && ret=0
+[[ "$prev" = -*f* ]] && compgen -dF && ret=0
+[[ "$prev" = -*r* ]] && compgen -dw && ret=0
+[[ "$prev" != -* ]]  && compgen -dB && ret=0
+
+return ret
diff --git a/Completion/Builtins/_kill b/Completion/Builtins/_kill
index c1afa78cb..36a23ccb2 100644
--- a/Completion/Builtins/_kill
+++ b/Completion/Builtins/_kill
@@ -5,7 +5,11 @@ local list
 if [[ -iprefix '-' ]]; then
   compgen -k "($signals[1,-3])"
 else
-  compgen -P '%' -j
+  local ret=1
+
+  compgen -P '%' -j && ret=0
   list=("$(ps 2>/dev/null)")
-  compgen -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`' && ret=0
+
+  return ret
 fi
diff --git a/Completion/Builtins/_setopt b/Completion/Builtins/_setopt
index 98800152f..b458cb2b0 100644
--- a/Completion/Builtins/_setopt
+++ b/Completion/Builtins/_setopt
@@ -1,8 +1,11 @@
 #defcomp setopt
 
-local nm=$compstate[nmatches]
+local nm=$compstate[nmatches] ret=1
 
 compgen -M 'L:|[nN][oO]= M:_= M:{A-Z}={a-z}' \
-         -s '$({ unsetopt kshoptionprint; unsetopt } 2>/dev/null)'
+         -s '$({ unsetopt kshoptionprint; unsetopt } 2>/dev/null)' && ret=0
+
 [[ compstate[nmatches] -eq nm ]] &&
-    compgen -M 'L:|[nN][oO]= M:_= M:{A-Z}={a-z}' -o
+    compgen -M 'L:|[nN][oO]= M:_= M:{A-Z}={a-z}' -o && ret=0
+
+return ret
diff --git a/Completion/Builtins/_unhash b/Completion/Builtins/_unhash
index 63d61c991..a9050cb49 100644
--- a/Completion/Builtins/_unhash
+++ b/Completion/Builtins/_unhash
@@ -1,8 +1,10 @@
 #defcomp unhash
 
-local fl="$words[2]"
+local fl="$words[2]" ret=1
 
-[[ "$fl" = -*d* ]] && compgen -n
-[[ "$fl" = -*a* ]] && compgen -a
-[[ "$fl" = -*f* ]] && compgen -F
-[[ "$fl" != -* ]] && compgen -m
+[[ "$fl" = -*d* ]] && compgen -n && ret=0
+[[ "$fl" = -*a* ]] && compgen -a && ret=0
+[[ "$fl" = -*f* ]] && compgen -F && ret=0
+[[ "$fl" != -* ]]  && compgen -m && ret=0
+
+return ret
diff --git a/Completion/Builtins/_unsetopt b/Completion/Builtins/_unsetopt
index a5c85b1ef..1194e28a7 100644
--- a/Completion/Builtins/_unsetopt
+++ b/Completion/Builtins/_unsetopt
@@ -1,8 +1,11 @@
 #defcomp unsetopt
 
-local nm=$compstate[nmatches]
+local nm=$compstate[nmatches] ret=1
 
 compgen -M 'L:|[nN][oO]= M:_= M:{A-Z}={a-z}' \
-         -s '$({ unsetopt kshoptionprint; setopt } 2>/dev/null)'
+         -s '$({ unsetopt kshoptionprint; setopt } 2>/dev/null)' && ret=0
+
 [[ compstate[nmatches] -eq nm ]] &&
-    compgen -M 'L:|[nN][oO]= M:_= M:{A-Z}={a-z}' -o
+    compgen -M 'L:|[nN][oO]= M:_= M:{A-Z}={a-z}' -o && ret=0
+
+return ret
diff --git a/Completion/Builtins/_wait b/Completion/Builtins/_wait
index 6e3a4c3c9..9281a5cc2 100644
--- a/Completion/Builtins/_wait
+++ b/Completion/Builtins/_wait
@@ -1,7 +1,9 @@
 #defcomp wait
 
-local list
+local list ret=1
 
-compgen -P '%' -j
+compgen -P '%' -j && ret=0
 list=("$(ps 2>/dev/null)")
-compgen -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`' && ret=0
+
+return ret
diff --git a/Completion/Builtins/_zftp b/Completion/Builtins/_zftp
index e93021acf..178d9d9e3 100644
--- a/Completion/Builtins/_zftp
+++ b/Completion/Builtins/_zftp
@@ -45,6 +45,7 @@ case $subcom in
 
   *)
   # dunno... try ordinary completion after all.
-  unset _compskip   
+  unset _compskip
+  return 1
   ;;
 esac
diff --git a/Completion/Commands/.distfiles b/Completion/Commands/.distfiles
new file mode 100644
index 000000000..f79d69704
--- /dev/null
+++ b/Completion/Commands/.distfiles
@@ -0,0 +1,3 @@
+DISTFILES_SRC='
+    .distfiles _correct_filename _most_recent_file 
+'
diff --git a/Completion/Core/.distfiles b/Completion/Core/.distfiles
new file mode 100644
index 000000000..ddf2a707e
--- /dev/null
+++ b/Completion/Core/.distfiles
@@ -0,0 +1,5 @@
+DISTFILES_SRC='
+    .distfiles
+    _compalso _files _main_complete _multi_parts _normal _path_files
+    _sep_parts compdump compinit
+'
diff --git a/Completion/Core/_compalso b/Completion/Core/_compalso
index 6ff6cf0bf..52fb08f05 100644
--- a/Completion/Core/_compalso
+++ b/Completion/Core/_compalso
@@ -7,7 +7,9 @@
 # `_compalso -math-' to get the completions that would be generated for a
 # mathematical context.
 
-local tmp
+local tmp ret=1
 
 tmp="$_comps[$1]"
-[[ -z "$tmp" ]] || "$tmp"
+[[ -z "$tmp" ]] || "$tmp" && ret=0
+
+return ret
diff --git a/Completion/Core/_files b/Completion/Core/_files
index 471824bfe..506ddbc8e 100644
--- a/Completion/Core/_files
+++ b/Completion/Core/_files
@@ -3,10 +3,9 @@
 # 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=$compstate[nmatches] ret
+local nm=$compstate[nmatches] ret=1
 
-_path_files "$@"
-ret=$?
+_path_files "$@" && ret=0
 
 if [[ $# -ne 0 && compstate[nmatches] -eq nm ]]; then
   local opt opts
@@ -23,7 +22,7 @@ if [[ $# -ne 0 && compstate[nmatches] -eq nm ]]; then
     [[ "$opt" = [PSWFJVX] ]] && opts=("$opts[@]" "-$opt" "$OPTARG")
   done
 
-  _path_files "$opts[@]"
-else
-  return $ret
+  _path_files "$opts[@]" && ret=0
 fi
+
+return ret
diff --git a/Completion/Core/_main_complete b/Completion/Core/_main_complete
index 34c5a3d3c..3571b712c 100644
--- a/Completion/Core/_main_complete
+++ b/Completion/Core/_main_complete
@@ -3,36 +3,47 @@
 # The main loop of the completion code. This is what is called when 
 # completion is attempted from the command line.
 #
-# 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
+# This code will automatically try to correct the string on the line
+# based on the strings generated for the context if
+# `compconfig[correct]' 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,
+#`compconfig[correct]' 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 _comp_correct comax
-
-setopt localoptions nullglob rcexpandparam globdots
+# `compconfig[correct]' will be used. E.g. with `compconfig[correct]=2n'
+# two errors will be accepted, but if the user gives another number
+# with the numeric argument, this will be prefered. Also, with
+# `compconfig[correct]=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. 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.
+# The value of `compconfig[correct_orig]' 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 apear 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 immediatly). Also, if the value of
+# `compconfig[correct_orig]' 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.
+# Finally, `compconfig[correct_prompt]' may 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.
+
+local comp name _comp_correct _correct_prompt comax
+
+setopt localoptions nullglob rcexpandparam
 unsetopt markdirs globsubst shwordsplit nounset ksharrays
 
 # Special completion contexts after `~' and `='.
@@ -91,25 +102,30 @@ while true; do
 
   # Use automatic correction?
 
-  if (( $+COMPCORRECT )); then
+  if (( $+compconfig[correct] )); 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 [[ -n "$_comp_correct" &&
+            ( "$compconfig[correct_orig]" = *always* ||
+	      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 [[ "$compconfig[correct_orig]" = *last* ]]; then
+	  builtin compadd -V _correct_orig -nQ - "$PREFIX$SUFFIX"
+        elif [[ -n "$compconfig[correct_orig]" ]]; then
+	  builtin compadd -nQ - "$PREFIX$SUFFIX"
+	fi
 
 	# If you always want to see the list of possible corrections,
 	# set `compstate[list]=list' here.
+
+	compstate[force_list]=list
       fi
       # Since we have matches, we don't want to try again.
+
       break
     fi
 
@@ -117,25 +133,33 @@ while true; do
 
     if [[ -n "$_comp_correct" ]]; then
 
-      # Yes, give up if we reached the maximum number of tries,
-      # otherwise increment our counter.
+      # Yes, give up if we reached the maximum number of tries or the
+      # string from the line is too short, otherwise increment our 
+      # counter.
 
-      [[ _comp_correct -eq comax ]] && break
+      [[ _comp_correct -eq comax ||
+         "${#${:-$PREFIX$SUFFIX}}" -le _comp_correct+1 ]] && break
       (( _comp_correct++ ))
 
+      _correct_prompt="${compconfig[correct_prompt]//\%e/$_comp_correct}"
+
     elif [[ compstate[matcher] -eq compstate[total_matchers] ]]; then
 
+      # We don't try correction if the string is too short.
+
+      [[ "${#${:-$PREFIX$SUFFIX}}" -le 1 ]] && return
+
       # 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
+      if [[ "$compconfig[correct]" = *[nN]* && NUMERIC -ne 1 ]]; then
         # Prefer the numeric argument if that has a sensible value.
         comax="$NUMERIC"
       else
-        comax="${COMPCORRECT//[^0-9]}"
+        comax="${compconfig[correct]//[^0-9]}"
       fi
-      # If the number of errors to accept is to small, give up.
+      # If the number of errors to accept is too small, give up.
 
       [[ "$comax" -lt 1 ]] && break
 
@@ -145,25 +169,31 @@ while true; do
       # ignored prefix).
 
       compadd() {
+        [[ "$*" != *-([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 (( $+CCPROMPT )); then
-	  builtin compadd -X "$CCPROMPT" -J _correct "$@"
+	if [[ -n "$_correct_prompt" ]]; then
+	  builtin compadd -X "$_correct_prompt" -J _correct "$@"
 	else
 	  builtin compadd -J _correct "$@"
 	fi
       }
       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 (( $+CCPROMPT )); then
-	  builtin compgen "$@" -X "$CCPROMPT" -J _correct
+	if [[ -n "$_correct_prompt" ]]; then
+	  builtin compgen "$@" -X "$_correct_prompt" -J _correct
 	else
 	  builtin compgen "$@" -J _correct
 	fi
@@ -179,6 +209,8 @@ while true; do
       _comp_correct=1
       compstate[matcher]=-1
 
+      _correct_prompt="${compconfig[correct_prompt]//\%e/$_comp_correct}"
+
       # We also need to set `extendedglob' and to make the completion
       # code behave as if globcomplete were set.
 
diff --git a/Completion/Core/_normal b/Completion/Core/_normal
index f56849194..98337eae5 100644
--- a/Completion/Core/_normal
+++ b/Completion/Core/_normal
@@ -1,6 +1,6 @@
 #autoload
 
-local comp command cmd1 cmd2 pat val name i ret
+local comp command cmd1 cmd2 pat val name i ret=1
 
 # 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.
@@ -9,8 +9,9 @@ local comp command cmd1 cmd2 pat val name i ret
 command="$words[1]"
 if [[ CURRENT -eq 1 ]]; then
   comp="$_comps[-command-]"
-  [[ -z "$comp" ]] || "$comp"
-  return
+  [[ -z "$comp" ]] || "$comp" && ret=0
+
+  return ret
 elif [[ "$command[1]" == '=' ]]; then
   eval cmd1\=$command
   cmd2="$command[2,-1]"
@@ -28,11 +29,10 @@ for i in "$_patcomps[@]"; do
   pat="${i% *}"
   val="${i#* }"
   if [[ "$cmd1" == $~pat || "$cmd2" == $~pat ]]; then
-    "$val"
-    ret=$?
+    "$val" && ret=0
     if (( $+_compskip )); then
       unset _compskip
-      return $ret
+      return ret
     fi
   fi
 done
@@ -53,4 +53,6 @@ if [[ -z "$comp" ]]; then
   name=-default-
   comp="$_comps[-default-]"
 fi
-[[ -z "$comp" ]] || "$comp"
+[[ -z "$comp" ]] || "$comp" && ret=0
+
+return ret
diff --git a/Completion/Core/_path_files b/Completion/Core/_path_files
index 3c03c0c61..535ba537c 100644
--- a/Completion/Core/_path_files
+++ b/Completion/Core/_path_files
@@ -2,13 +2,15 @@
 
 # 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 `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
-# are treated like files with one of the suffixes in the `fignore' array
-# in normal completion.
+# `-V <group>', `-W paths', `-X explanation', `-P prefix', `-S suffix',
+# `-q', `-r remove-chars', `-R remove-func', and `-F <ignore>'. All but 
+# the last have the same syntax and meaning as for `compgen' or
+# `compadd', respectively. 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'.
 
@@ -20,9 +22,10 @@ _match_test _path_files || return 1
 
 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 orig ostr nm=$compstate[nmatches]
+local addpfx addsfx expl orig ostr nm=$compstate[nmatches] menu remsfx patlast
+local origflags mflags
 
-setopt localoptions nullglob rcexpandparam globdots extendedglob
+setopt localoptions nullglob rcexpandparam extendedglob
 unsetopt markdirs globsubst shwordsplit nounset
 
 prepaths=('')
@@ -33,16 +36,21 @@ gopt=''
 pats=()
 addpfx=()
 addsfx=()
+remsfx=()
 expl=()
 
 # Get the options.
 
-while getopts "P:S:W:F:J:V:X:f/g:" opt; do
+while getopts "P:S:qr:R:W:F:J:V:X:f/g:" opt; do
   case "$opt" in
   P)     addpfx=(-P "$OPTARG")
          ;;
   S)     addsfx=(-S "$OPTARG")
          ;;
+  q)     tmp1=yes
+         ;;
+  [rR])  remsfx=("-$opt" "$OPTARG")
+         ;;
   W)     tmp1="$OPTARG"
          if [[ "$tmp1[1]" = '(' ]]; then
            prepaths=( ${^=tmp1[2,-2]}/ )
@@ -76,6 +84,8 @@ while getopts "P:S:W:F:J:V:X:f/g:" opt; do
   esac
 done
 
+[[ -n "$tmp1" && $#addsfx -ne 0 ]] && addsfx[1]=-qS
+
 # If we were given no file selection option, we behave as if we were given
 # a `-f'.
 
@@ -89,19 +99,25 @@ if [[ "$sopt" = - ]]; then
 fi
 
 # str holds the whole string from the command line with a `*' between
-# the prefix and the suffix.
+# the prefix and the suffix. Then we see if we will do menucompletion.
 
-if [[ -o globcomplete ]]; then
+if [[ $#compstate[pattern_match] -ne 0 ]]; then
   str="${PREFIX}*${SUFFIX}"
 else
   str="${PREFIX:q}*${SUFFIX:q}"
+  [[ "$str" = \\\~* ]] && str="$str[2,-1]"
 fi
 orig="${PREFIX}${SUFFIX}"
 
+[[ $compstate[insert] = *menu || -n "$_comp_correct" ||
+   ( $#compstate[pattern_match] -ne 0 &&
+     "$orig" != "${orig:q}" ) ]] && menu=yes
+
+
 # We will first try normal completion called with `compgen', but only if we
-# weren't given a `-F' option.
+# weren't given a `-F', `-r', or `-R' option.
 
-if (( ! $#ignore )); then
+if [[ $#ignore -eq 0 && $#remsfx -eq 0 && -z "$_comp_correct" ]]; 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.
@@ -124,11 +140,11 @@ if (( ! $#ignore )); then
   # If this generated any matches, we don't want to do in-path completion.
 
   [[ compstate[nmatches] -eq nm ]] || return 0
+fi
 
-  # No `-F' option, so we want to use `fignore'.
+# No `-F' option, so we want to use `fignore'.
 
-  ignore=(-F fignore)
-fi
+(( $#ignore )) || ignore=(-F fignore)
 
 # Now let's have a closer look at the string to complete.
 
@@ -176,6 +192,7 @@ fi
 patstr="$str"
 matchflags=""
 _match_pattern _path_files patstr matchflags
+origflags="$matchflags"
 [[ -n "$_comp_correct" ]] && matchflags="$matchflags(#a$_comp_correct)"
 
 # We almost expect the pattern to have changed `..' into `*.*.', `/.' into
@@ -185,13 +202,40 @@ _match_pattern _path_files patstr matchflags
 
 patstr="$patstr:gs-/-*/-:gs/*.*./../:gs-/*.-/.-:gs/**/*/:gs-.*/-./-"
 
+# We take the last pathname component from the pattern and store it in
+# `patlast', replacing `*'s in it with patterns that match any character
+# but not slashes. Later we will generate matches using `patstr' with the
+# patterns we were given (like `*.c') appended to it, producing all matching
+# files. These filenames are then compared to `patlast' and all names not
+# matching that will be removed. All this is needed to be able to correctly
+# support `completeinword' as otherwise we would have something like `a*x'
+# from the line (the `*' was inserted above) and appending the `-g' pattern
+# `*.tex' would yield `a*x*.tex' which is not what we want.
+
+if [[ "$patstr" = */* ]]; then
+  if [[ -n "$_comp_correct" && "${#orig##*/}" -le _comp_correct ]]; then
+    patlast="*/${origflags}${${patstr##*/}//\*/[^/]#}"
+  else
+    patlast="*/${matchflags}${${patstr##*/}//\*/[^/]#}"
+  fi
+  patstr="${patstr%/*}/"
+else
+  if [[ -n "$_comp_correct" && "$#orig" -le _comp_correct ]]; then
+    patlast="${origflags}${patstr//\*/[^/]#}"
+  else
+    patlast="${matchflags}${patstr//\*/[^/]#}"
+  fi
+  patstr=""
+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 `orig' and added
 # to `donepath'.
 
 while [[ "$orig" = */* ]] do
-  tmp1=( ${~matchflags}$realpath$donepath${orig%%/*}/${~patstr#*/}$^pats )
+  tmp1=( $realpath$donepath${orig%%/*}/${~matchflags}${~patstr#*/}$^pats )
+  tmp1=("${(@M)tmp1:#$~patlast}")
   [[ $#tmp1 -gt 0 && -e "$realpath$donepath${orig%%/*}" ]] || break
   donepath="$donepath${orig%%/*}/"
   orig="${orig#*/}"
@@ -217,8 +261,13 @@ for prepath in "$prepaths[@]"; do
     # we get the globbing matches for the pathname component currently
     # handled.
 
+    if [[ -n "$_comp_correct" && "${#ostr%%/*}" -le _comp_correct ]]; then
+      mflags="$origflags"
+    else
+      mflags="$matchflags"
+    fi
     rest="${str#*/}"
-    tmp1="${prepath}${realpath}${testpath}${~matchflags}${str%%/*}(-/)"
+    tmp1="${prepath}${realpath}${testpath}${~mflags}${str%%/*}(-/)"
     tmp1=( $~tmp1 )
 
     if [[ $#tmp1 -eq 0 ]]; then
@@ -240,12 +289,19 @@ for prepath in "$prepaths[@]"; do
       suffixes=( $rest$^pats )
       suffixes=( "${(@)suffixes:gs.**.*.}" )
 
+      if [[ -n "$_comp_correct" && "${#ostr#*/}" -le _comp_correct ]]; then
+        mflags="$origflags"
+      else
+        mflags="$matchflags"
+      fi
+
       # 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=( ${~i}/${~mflags}${~suffixes} )
+        tmp2=("${(@M)tmp2:#$~patlast}")
         [[ $#tmp2 -ne 0 ]] && collect=( $collect $i )
       done
 
@@ -255,9 +311,6 @@ for prepath in "$prepaths[@]"; do
       # 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
@@ -270,6 +323,7 @@ for prepath in "$prepaths[@]"; do
 	# Now produce all matching pathnames in `collect'.
 
         collect=( ${~collect}/${~matchflags}${~suffixes} )
+	collect=("${(@M)collect:#$~patlast}")
 
 	# And then remove the common path prefix from all these matches.
 
@@ -282,15 +336,16 @@ for prepath in "$prepaths[@]"; do
 	# these are file names and that `fignore' should be used as usual
 	# (the `-f' and `-F' options).
 
-	if [[ $compstate[insert] = *menu ]]; then
+	if [[ -n "$menu" ]]; then
           compadd -QU "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" \
-                  -i "$IPREFIX" -p "${linepath:q}${testpath:q}" -S "/${ostr#*/}" \
+                  -i "$IPREFIX" -p "$linepath${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%%/*}"
+            compadd -QU "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" \
+	            -i "$IPREFIX" -p "$linepath${testpath:q}" -s "/${${i#*/}:q}" \
+		    -M 'r:|/=*' -W "$tmp1" -f "$ignore[@]" - "${${i%%/*}:q}"
           done
 	fi
 
@@ -299,12 +354,27 @@ for prepath in "$prepaths[@]"; do
 
 	continue 2
       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.
 
       tmp1=( "$collect[1]" )
+    elif [[ -n "$_comp_correct" && "$mflags" = "$matchflags" ]]; then
+
+      # If we got only one match with auto-correction and if we get none
+      # without correction, stop now.
+
+      tmp2="${prepath}${realpath}${testpath}${~origflags}${str%%/*}(-/)"
+      tmp2=( $~tmp2 )
+
+      if [[ $#tmp1 -ne $#tmp2 ]]; then
+        compadd -QU "$addpfx[@]" -S '' "$group[@]" "$expl[@]" \
+                -i "$IPREFIX" -p "$linepath${testpath:q}" -s "/${ostr#*/}" \
+		- "${${tmp1#${prepath}${realpath}${testpath}}:q}"
+        continue 2
+      fi
     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.
@@ -320,10 +390,17 @@ for prepath in "$prepaths[@]"; do
   # no path suffix, the `-W' we are currently handling, all the matches we
   # can produce in this directory, if any.
 
+  if [[ -n "$_comp_correct" && "${#ostr#*/}" -le _comp_correct ]]; then
+    mflags="$origflags"
+  else
+    mflags="$matchflags"
+  fi
   tmp1="$prepath$realpath$testpath"
   suffixes=( $str$^pats )
   suffixes=( "${(@)suffixes:gs.**.*.}" )
   tmp2=( ${~tmp1}${~matchflags}${~suffixes} )
+  tmp2=("${(@M)tmp2:#$~patlast}")
+
   if [[ $#tmp2 -eq 0 ]]; then
     # No match, insert the expanded path and add the original tail.
 
@@ -334,11 +411,11 @@ for prepath in "$prepaths[@]"; do
     [[ "$linepath$testpath$ostr" = "$PREFIX$SUFFIX" ]] && return 1
 
     compadd -QU -S '' "$group[@]" "$expl[@]" \
-            -i "$IPREFIX" -f - "${linepath:q}${testpath:q}$ostr"
+            -i "$IPREFIX" -f - "$linepath${testpath:q}$ostr"
   else
-    compadd -U "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" \
-            -i "$IPREFIX" -p "$linepath$testpath" -f "$ignore[@]" \
-	    -W "$prepath$realpath$testpath" - "${(@)tmp2#$tmp1}"
+    compadd -QU "$addpfx[@]" "$addsfx[@]" "$remsfx[@]" "$group[@]" "$expl[@]" \
+            -i "$IPREFIX" -p "$linepath${testpath:q}" -f "$ignore[@]" \
+	    -W "$prepath$realpath$testpath" - "${(@)${(@)tmp2#$tmp1}:q}"
   fi
 done
 
diff --git a/Completion/Core/_sep_parts b/Completion/Core/_sep_parts
new file mode 100644
index 000000000..c1cda2b9a
--- /dev/null
+++ b/Completion/Core/_sep_parts
@@ -0,0 +1,171 @@
+#autoload
+
+# This function can be used to separately complete parts of strings
+# where each part may be one of a set of matches and different parts
+# have different sets.
+# Arguments are alternatingly arrays and separator strings. Arrays may
+# be given by name or literally as words separated by white space in
+# parentheses, e.g.:
+#
+#  _sep_parts '(foo bar)' @ hosts
+#
+# This will make this function complete the strings in the array
+# `friends'. If the string on the line contains a `@', the substring
+# after it will be completed from the array `hosts'. Of course more
+# arrays may be given, each preceded by another separator string.
+#
+# This function understands the `-J group', `-V group', and
+# `-X explanation' options.
+#
+# This function does part of the matching itself and calls the functions
+# `_match_test' and `_match_pattern' for this.
+
+local str arr sep test testarr tmparr prefix suffixes matchers autosuffix
+local matchflags opt group expl nm=$compstate[nmatches]
+
+# Test if we should use this function for the global matcher in use.
+
+_match_test _sep_parts || return 1
+
+# 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 string from the line.
+
+str="$PREFIX$SUFFIX"
+[[ $#compstate[pattern_match] -ne 0 ]] || str="$str:q"
+prefix=""
+
+# Walk through the arguments to find the longest unambiguous prefix.
+
+while [[ $# -gt 1 ]]; do
+  # Get the next array and separator.
+  arr="$1"
+  sep="$2"
+
+  if [[ "$arr[1]" == '(' ]]; then
+    tmparr=( ${=arr[2,-2]} )
+    arr=tmparr
+  fi
+  # Is the separator on the line?
+  [[ "$str" != *${sep}* ]] && break
+
+  # Build a pattern matching the possible matches and get all these
+  # matches in an array.
+
+  test="${str%%${sep}*}"
+  [[ -n "$_comp_correct" && $#test -le _comp_correct ]] && return 1
+
+  matchflags=""
+  _match_pattern _sep_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 1
+  [[ $#testarr -gt 1 ]] && break
+
+  # Only one match, add it to the prefix and skip over it in `str',
+  # continuing with the next array and separator.
+  prefix="${prefix}${testarr[1]}${sep}"
+  str="${str#*${sep}}"
+  shift 2
+done
+
+# Get the array to work upon.
+arr="$1"
+if [[ "$arr[1]" == '(' ]]; then
+  tmparr=( ${=arr[2,-2]} )
+  arr=tmparr
+fi
+if [[ $# -le 1 || "$str" != *${2}* ]]; then
+  # No more separators, build the matches.
+
+  test="$str"
+  [[ -n "$_comp_correct" && $#test -le _comp_correct ]] && return 1
+
+  matchflags=""
+  _match_pattern _sep_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 1
+
+# Now we build the suffixes to give to the completion code.
+shift
+matchers=()
+suffixes=("")
+autosuffix=()
+
+while [[ $# -gt 0 && "$str" == *${1}* ]]; do
+  # Remove anything up to the the suffix.
+  str="${str#*${1}}"
+
+  # Again, we get the string from the line up to the next separator
+  # and build a pattern from it.
+  if [[ $# -gt 2 ]]; then
+    test="${str%%${3}*}"
+  else
+    test="$str"
+  fi
+
+  [[ -n "$_comp_correct" && $#test -le _comp_correct ]] && return 1
+
+  matchflags=""
+  _match_pattern _sep_parts test matchflags
+  [[ -n "$_comp_correct" ]] && matchflags="$matchflags(#a$_comp_correct)"
+  test="${matchflags}${test}"
+
+  # We incrementally add suffixes by appending to them the seperators
+  # and the strings from the next array that match the pattern we built.
+
+  arr="$2"
+  if [[ "$arr[1]" == '(' ]]; then
+    tmparr=( ${=arr[2,-2]} )
+    arr=tmparr
+  fi
+  tmparr=( "${(@M)${(@P)arr}:#${~test}*}" )
+  tmparr=( "${(@)tmparr:#}" )
+  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
+  # word matching before the separators on the fly.
+  matchers=("$matchers[@]" "r:|${1:q}=*")
+  shift 2
+done
+
+# If we were given at least one more separator we make the completion
+# code offer it by appending it as a autoremovable suffix.
+(( $# )) && autosuffix=(-qS "$1")
+
+# If we have collected matching specifications, we build an array
+# from it that can be used as arguments to `compadd'.
+[[ $#matchers -gt 0 ]] && matchers=(-M "$matchers")
+
+# Add the matches for each of the suffixes.
+for i in "$suffixes[@]"; do
+  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/compdump b/Completion/Core/compdump
index 8be096f50..5fdee8c7a 100644
--- a/Completion/Core/compdump
+++ b/Completion/Core/compdump
@@ -15,7 +15,7 @@
 # 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}
+_d_file=${compconfig[dump_file]-${0:h}/compinit.dump}
 
 typeset -U _d_files
 _d_files=( ${^~fpath}/_*~*~(N:t) )
diff --git a/Completion/Core/compinit b/Completion/Core/compinit
index ec5867838..31d011565 100644
--- a/Completion/Core/compinit
+++ b/Completion/Core/compinit
@@ -37,18 +37,24 @@
 # 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.
+# 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 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.
-#
+
 # If we got the `-d'-flag, we will automatically dump the new state (at
 # the end).
+# If we were given an argument, this will be taken as the name of the
+# file in which to store the dump.
 
 if [[ "$1" = -d ]]; then
   _i_autodump=1
+  shift
 else
   _i_autodump=0
 fi
@@ -59,6 +65,18 @@ fi
 typeset -A _comps
 _patcomps=()
 
+# This is the associative array used for configuration.
+
+typeset -A compconfig
+
+# Standard initialisation for `compconfig'.
+
+(( $# )) && compconfig[dump_file]="$1"
+[[ -z "$compconfig[dump_file]" ]] && compconfig[dump_file]="$0.dump"
+
+compconfig[correct_prompt]='correct to:'
+
+
 # This function is used to register or delete completion functions. For
 # registering completion functions, it is invoked with the name of the
 # function as it's first argument (after the options). The other
@@ -197,11 +215,25 @@ compdef() {
   fi
 }
 
-# Now we automatically make the definition files autoloaded.
+# Functional interface to configuration. This takes its arguments
+# and sets the according values in `compconfig'.
+# Arguments may be `foo=bar' to set key `foo' to `bar' or `baz' to
+# set key `baz' to the empty string.
 
-# First we get the name of a dump file if this will be used.
+compconf() {
+  local i name
 
-: ${COMPDUMP:=$0.dump}
+  for i; do
+    if [[ "$i" = *\=* ]]; then
+      name="${i%%\=*}"
+      compconfig[$name]="${i#*\=}"
+    else
+      compconfig[$i]=''
+    fi
+  done
+}
+
+# Now we automatically make the definition files autoloaded.
 
 if [[ ! -o extendedglob ]]; then
   _i_noextglob=yes
@@ -215,10 +247,10 @@ _i_done=''
 
 # If we have a dump file, load it.
 
-if [[ -f "$COMPDUMP" ]]; then
-  read -rA _i_line < "$COMPDUMP"
+if [[ -f "$compconfig[dump_file]" ]]; then
+  read -rA _i_line < "$compconfig[dump_file]"
   if [[ _i_autodump -eq 1 && $_i_line[2] -eq $#_i_files ]]; then
-    builtin . "$COMPDUMP"
+    builtin . "$compconfig[dump_file]"
     _i_done=yes
   fi
   unset _i_line
diff --git a/Completion/README b/Completion/README
index 43ffcbcc2..f95e67699 100644
--- a/Completion/README
+++ b/Completion/README
@@ -9,9 +9,12 @@ Core/compinit.  It is recommnded that you use the -d option, which outputs
 a file containing the necessary variables, bindkeys etc., making later
 loading much faster.  For example,
   [[ -f ~/completion/compinit ]] && . ~/completion/compinit -d
+The name of the file to use may be given as an extra argument.
+
 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. For information about how to configure the code,
+see the comment at the top of Core/_main_complete.
 
 The subdirectories contain:
 
@@ -27,7 +30,7 @@ Core:
     This dumps the completions status for faster initialisation.  The
     easiest way of doing this is to use the -d option to compinit rather
     than calling compdump directly.
-  _comp_parts
+  _sep_parts
     Utility used for completing words with multiple separate parts, such as
     `<user>@<host>'
   _multi_parts
@@ -67,10 +70,15 @@ Base:
     This handles completion of command arguments when no special function
     exists.  Usually this means completing files, but you can modify this
     as you wish.
+  _long_options
+    This handles options beginning with `--', as in many GNU commands.
+    The command must accept the --help option to list the possible options.
+    __long_options can also take arguments to help it decide what to
+    complete as the value of the option.
   _match_pattern
   _match_test
     These are used by Base/_path_files (and hence also Base/_files)
-    and Base/_comp_parts for file completion with control over
+    and Base/_sep_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.
diff --git a/Completion/User/.distfiles b/Completion/User/.distfiles
new file mode 100644
index 000000000..ee0017035
--- /dev/null
+++ b/Completion/User/.distfiles
@@ -0,0 +1,6 @@
+DISTFILES_SRC='
+    .distfiles
+    _a2ps _compress _configure _dd _dvi _find _gunzip _gzip _hosts
+    _make _man _mh _pdf _ps _rcs _rlogin _strip _stty _tar _tar_archive
+    _tex _uncompress _x_options _xfig 
+'
diff --git a/Completion/User/_a2ps b/Completion/User/_a2ps
index 600b58872..9923ae20d 100644
--- a/Completion/User/_a2ps
+++ b/Completion/User/_a2ps
@@ -1,22 +1,39 @@
 #defcomp a2ps
 
-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)'
+# This is for the GNU version of a2ps.
 
-  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)'
-  compgen -qS= -k '(--margin --header --underlay --left-title
-                     --right-title --left-footer --footer --right-footer
-		     --pages --pretty-print)'
-  compgen -k '(--landscape --portrait --catman --no-header)'
-else
-  _files -F fignore -g "*~*.ps"
+if [[ "$words[1]" != "$_a2ps_cache_cmd" ]]; then
+  local descr
+
+  _a2ps_cache_cmd="$words[1]"
+
+  descr=( "${(@)${(f@)$($words[1] --list=features)//
+ /	}:#}" )
+
+  _a2ps_cache_values=(
+      "${descr[(r)Known style sheets*]#*	}"
+      "${descr[(r)Known encodings*]#*	}"
+      "${descr[(r)Known media*]#*	}"
+      "${descr[(r)Known prologues*]#*	}"
+      "${descr[(r)Known PostScript Printer Descriptions*]#*	}"
+      "${descr[(r)Known output destination*]#*	}"
+      "${descr[(r)Known user options*]#*	}"
+      "${descr[(r)Known Variables*]#*	}"
+  )
 fi
+
+_long_options -t '*\*'                '(yes no)' \
+                 '*=DIRECTION'        '(rows columns)' \
+                 '*=TYPE'             '(r n nr rn any)' \
+		 '--highlight-level*' '(none normal heavy)' \
+		 '--version-control*' '(none off t numbered nil 
+		                        existing never simple)' \
+	         '--pretty-print*'    "[${_a2ps_cache_values[1]}]" \
+	         '--encoding*'        "(${_a2ps_cache_values[2]})" \
+	         '--medium*'          "[${_a2ps_cache_values[3]}]" \
+	         '--prologue*'        "[${_a2ps_cache_values[4]}]" \
+	         '--ppd*'             "[${_a2ps_cache_values[5]}]" \
+	         '--printer*'         "[${_a2ps_cache_values[6]}]" \
+	         '--user-option*'     "[${_a2ps_cache_values[7]}]" \
+	         '--variable*'        "[${_a2ps_cache_values[8]}]" ||
+    _files -F fignore -g '*~*.(ps|PS|eps|EPS)'
diff --git a/Completion/User/_configure b/Completion/User/_configure
index 050701fac..7559852e8 100644
--- a/Completion/User/_configure
+++ b/Completion/User/_configure
@@ -1,35 +1,4 @@
 #defcomp configure
 
-setopt localoptions extendedglob
-
-if [[ $PREFIX = *=* ]]; then
-  # Complete filenames after e.g. --prefix=
-  IPREFIX=${PREFIX%%=*}=
-  PREFIX=${PREFIX#*=}
-  compgen -f
-else
-  # Generate a list of options from configure --help
-  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
+_long_options '*=(E|)PREFIX*' '_files -/' \
+              '*=PROGRAM*'    '_command_names'
diff --git a/Completion/User/_dd b/Completion/User/_dd
index 86a47b1ab..63ae40f50 100644
--- a/Completion/User/_dd
+++ b/Completion/User/_dd
@@ -5,7 +5,7 @@ if [[ -iprefix conv= ]]; then
   # test alone will have that effect.
   [[ -string , ]]
   compgen -S, -q \
-  -k '(ascii ebcdic ibm block unblock lcase ucase swab noerror sync)'
+      -k '(ascii ebcdic ibm block unblock lcase ucase swab noerror sync)'
 elif [[ -iprefix 'if=' || -iprefix 'of=' ]]; then
   _files
 else
diff --git a/Completion/User/_find b/Completion/User/_find
index 8fcdafb83..cb637fc26 100644
--- a/Completion/User/_find
+++ b/Completion/User/_find
@@ -10,8 +10,12 @@ elif [[ -iprefix - ]]; then
     {i,}{l,}name {no,}{user,group} path perm regex size true uid used \
     exec {f,}print{f,0,} ok prune ls'
 elif [[ -position 2 ]]; then
-  compgen -g '. ..'
-  _files -g '(-/)'
+  local ret=1
+
+  compgen -g '. ..' && ret=0
+  _files -g '(-/)' && ret=0
+
+  return ret
 elif [[ "$prev" = -((a|c|)newer|fprint(|0|f)) ]]; then
   _files
 elif [[ "$prev" = -fstype ]]; then
diff --git a/Completion/User/_man b/Completion/User/_man
index 67d59f24a..cd1badc4d 100644
--- a/Completion/User/_man
+++ b/Completion/User/_man
@@ -1,7 +1,9 @@
 #defcomp man
+
 setopt localoptions rcexpandparam
 
 local rep
+
 if [[ $words[2] = (<->*|ln) ]]; then
   rep=( $manpath/(man|cat)${words[2]}/$PREFIX*$SUFFIX.<->*(N:t:r) )
 else
diff --git a/Completion/User/_mh b/Completion/User/_mh
index 7e8575123..c6c018220 100644
--- a/Completion/User/_mh
+++ b/Completion/User/_mh
@@ -4,6 +4,7 @@
 # Alter the following two to your own mh directory and the directory
 # where standard mh library files live.  (It works anyway, but this
 # will save a little time.)
+
 local mymhdir=~/Mail
 local mhlib=/usr/lib/mh
 
@@ -25,6 +26,7 @@ if [[ -iprefix - ]]; then
 elif [[ -iprefix '+' || -iprefix '@' || "$prev" = -draftfolder ]]; then
   # Complete folder names.
   local mhpath
+
   if [[ $IPREFIX != '@' ]]; then
     [[ $IPREFIX = '+' ]] || IPREFIX=+
     mhpath=$mymhdir
@@ -53,7 +55,8 @@ elif [[ "$prev" = -[rw]cache ]]; then
   compadd public private never ask
 else
   # Generate sequences.
-  local foldnam folddir f
+  local foldnam folddir f ret
+
   for f in $argv; do
     [[ $f = [@+]* ]] && foldnam=$f
   done
@@ -66,7 +69,10 @@ else
     # leaving foldnam empty works here
   fi
 
-  compgen -s '$(mark $foldnam 2>/dev/null | awk -F: '\''{ print $1 }'\'')'
-  compadd reply next cur prev first last all unseen
-  compgen -W folddir -g '<->'
+  compgen -s '$(mark $foldnam 2>/dev/null | awk -F: '\''{ print $1 }'\'')' &&
+      ret=0
+  compadd reply next cur prev first last all unseen && ret=0
+  compgen -W folddir -g '<->' && ret=0
+
+  return ret
 fi
diff --git a/Completion/User/_rcs b/Completion/User/_rcs
index 5a751605c..5e53cb4da 100644
--- a/Completion/User/_rcs
+++ b/Completion/User/_rcs
@@ -6,6 +6,7 @@ local nm=$compstate[nmatches]
 
 if [[ $compstate[nmatches] -eq nm && -d RCS && $words[1] != ci ]]; then
   local rep
+
   rep=(RCS/$PREFIX*$SUFFIX,v(:t:s/\,v//))
   (( $#rep )) && compadd - $rep
 fi
diff --git a/Completion/User/_strip b/Completion/User/_strip
index 6962ac455..541c901ad 100644
--- a/Completion/User/_strip
+++ b/Completion/User/_strip
@@ -1,2 +1,3 @@
 #defcomp strip
+
 _files -g '*(*)'
diff --git a/Completion/User/_tar b/Completion/User/_tar
index 84c490f1e..d11ee76c8 100644
--- a/Completion/User/_tar
+++ b/Completion/User/_tar
@@ -1,69 +1,125 @@
 #defcomp tar
 
 # 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.
+#  - Tries to collect tar commands from second position, single letter
+#    option, and long options.
 #  - `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).
+#  - Uses the function `_tar_archive' to complete archive files.
+#  - Tries to find out if compressed archives should be used.
+#  - 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.
+#    tar itself (GNU tar)
 #  - Things like --directory=... are also completed correctly.
 
 emulate -LR zsh
 setopt extendedglob
 
-local nm=$NMATCHES tcmd="$words[2]" tf="$words[3]"
+local _tar_cmd tf tmp del
 
-if [[ $PREFIX = *=* ]]; then
-  # For GNU tar arguments like --directory=
-  IPREFIX=${PREFIX%%\=*}=
-  PREFIX=${PREFIX#*=}
-  if [[ $IPREFIX = --directory* ]]; then
-    _path_files -/
-  else
-    _files
+# First we collect in `_tar_cmd' single letter options describing what
+# should be done with the archive and if it is compressed. This
+# collected from options arguments that start with only one hyphen,
+# from some of the possible long options, and from the second word if
+# that does not start with a hyphen.
+
+tmp=("${(@M)words:#-[^-]*}")
+_tar_cmd="${(j::)tmp#-}"
+
+(( $words[(I)--(un|)gzip] ))     && _tar_cmd="z$_tar_cmd"
+(( $words[(I)--(un|)compress] )) && _tar_cmd="Z$_tar_cmd"
+(( $words[(I)--list] ))          && _tar_cmd="t$_tar_cmd"
+(( $words[(I)--(extract|get)] )) && _tar_cmd="x$_tar_cmd"
+(( $words[(I)--create] ))        && _tar_cmd="c$_tar_cmd"
+
+# Other ways of finding out what we're doing:  first
+# look in the first argument if it's not an option
+if [[ "$words[2]" = *[txcdruA]*~-* ]]; then
+  _tar_cmd="$words[2]$_tar_cmd"
+elif [[ $_tar_cmd != *[txcdruA]* && CURRENT -gt 2 ]]; then
+  # look for more obscure long options: these aren't all handled.
+  (( $words[(I)--(diff|compare)] )) && _tar_cmd="d$_tar_cmd"
+  (( $words[(I)--append] )) && _tar_cmd="r$_tar_cmd"
+  (( $words[(I)--update] )) && _tar_cmd="u$_tar_cmd"
+  (( $words[(I)--(con|)catenate] )) && _tar_cmd="A$_tar_cmd"
+  (( $words[(I)--delete] )) && del=1
+fi
+
+# Next, we try to find the archive name and store it in `tf'. The name 
+# is searched after a `--file=' long option, in the third word if the
+# second one didn't start with a hyphen but contained a `f', and after 
+# an option argument starting with only one hyphen and containing a `f'.
+
+tmp="$words[(I)--file=*]"
+if (( tmp )); then
+  tf="${words[tmp][8,-1]}"
+  _tar_cmd="f$_tar_cmd"
+elif [[ "$words[2]" != -* && "$words[2]" = *f* ]]; then
+  tf="$words[3]"
+  _tar_cmd="f$_tar_cmd"
+else
+  tmp="${words[(I)-*f*~--*]}"
+  if (( tmp )); then
+    tf="$words[tmp+1]"
+    _tar_cmd="f$_tar_cmd"
   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.
+fi
+
+# Now we complete...
+
+if [[ "$PREFIX" = --* ]]; then
+
+  # ...long options after `--'.
+
+  _long_options '--owner*'          "_tilde" \
+                '*=(PROG|COMMAND)*' "_command_names" \
+		'*=ARCHIVE*'        "_tar_archive" \
+		'*=CONTROL*'        "[t numbered nil existing never simple]"
+
+elif [[ ( CURRENT -gt 2 && "$words[CURRENT-1]" = -*f* &&
+          "$words[CURRENT-1]" != --* ) ||
+        ( CURRENT -eq 3 && "$words[2]" = *f* && "$words[2]" != -* ) ]]; then
+
+  # ...archive files if we think they are wanted here.
+
+  _tar_archive
+
+elif [[ ( "$_tar_cmd" = *[xt]* || -n $del ) && -n "$tf" ]]; then
+
+  # ...and files from the archive if we found an archive name and tar
+  # commands. 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
+  if [[ $_tar_cmd = *z* ]]; then
+    largs=-tzf
+  elif [[ $_tar_cmd = *Z* ]]; then
+    largs=-tZf
+  else
+    # Some random compression program e.g. bzip2
+    tmp="${words[(r)--use-comp*]}"
+    [[ -n $tmp ]] && largs=($tmp -tf)
+  fi
+
+  if [[ $tf != $_tar_cache_name ]]; then
+    _tar_cache_list=("${(@f)$($words[1] $largs $tf)}")
+    _tar_cache_name=$tf
+  fi
+
+  _multi_parts / _tar_cache_list
+else
+  
+  # See if we should use a path prefix.  We have to use eval as the dir can
+  # be any unevaluated thing which appears on the command line, including a
+  # parameter.
+  tmp=${words[(r)--dir[a-z]#=*]}
+  if [[ -n $tmp ]]; then
+    eval "tmp=(${tmp#*=})"
+    _path_files -W tmp
+  else
+    _files
   fi
-  _multi_parts / tar_cache_list
-elif [[ "$tcmd" = *c*f* && $CURRENT -ge 4 ]] then
-  _files
-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/_tar_archive b/Completion/User/_tar_archive
new file mode 100644
index 000000000..58e436c4d
--- /dev/null
+++ b/Completion/User/_tar_archive
@@ -0,0 +1,20 @@
+#autoload
+
+# This is used to generate filenames usable as a tar archive. This may
+# get one argument, a collection of tar option characters that may be
+# used to find out what kind of filename is needed. If no argument is
+# given but the parameter `_tar_cmd' is set, that is used.
+# If your version of `tar' supports this you may want to complete
+# things like `host:file' or `user@host:file' here.
+
+[[ $# -eq 0 && $+_tar_cmd -ne 0 ]] && set "$_tar_cmd"
+
+if [[ "$1" = *[tx]* ]]; then
+  if [[ "$1" = *[zZ]* ]]; then
+    _files -g '*.((tar|TAR).(gz|GZ|Z)|.tgz)'
+  else
+    _files -g '*.(tar|TAR)'
+  fi
+else
+  _files
+fi