about summary refs log tree commit diff
diff options
context:
space:
mode:
authorSven Wischnowsky <wischnow@users.sourceforge.net>2000-04-11 07:57:56 +0000
committerSven Wischnowsky <wischnow@users.sourceforge.net>2000-04-11 07:57:56 +0000
commitfac3086d9782e73dcaf1aa65fd36a0b63a374719 (patch)
tree7bab35e2787ca17f02ec932dffae1bfff2ffcfe3
parent37012f06a7e5e8a64614dbf9032c77cff1bcfcfb (diff)
downloadzsh-fac3086d9782e73dcaf1aa65fd36a0b63a374719.tar.gz
zsh-fac3086d9782e73dcaf1aa65fd36a0b63a374719.tar.xz
zsh-fac3086d9782e73dcaf1aa65fd36a0b63a374719.zip
_wanted now tests both tags and labels; change places where _wanted was called without a command; allow multiple patterns per string in file-patterns; update _next_tags to work with labels (10632)
-rw-r--r--ChangeLog33
-rw-r--r--Completion/Base/_brace_parameter6
-rw-r--r--Completion/Base/_condition59
-rw-r--r--Completion/Base/_default2
-rw-r--r--Completion/Base/_describe45
-rw-r--r--Completion/Base/_first25
-rw-r--r--Completion/Base/_jobs6
-rw-r--r--Completion/Base/_values2
-rw-r--r--Completion/Builtins/_compdef16
-rw-r--r--Completion/Builtins/_hash19
-rw-r--r--Completion/Builtins/_pids4
-rw-r--r--Completion/Builtins/_popd4
-rw-r--r--Completion/Builtins/_sched4
-rw-r--r--Completion/Builtins/_signals9
-rw-r--r--Completion/Builtins/_vars12
-rw-r--r--Completion/Builtins/_zcompile3
-rw-r--r--Completion/Builtins/_zftp15
-rw-r--r--Completion/Builtins/_zpty6
-rw-r--r--Completion/Builtins/_zstyle26
-rw-r--r--Completion/Commands/_next_tags168
-rw-r--r--Completion/Core/_all_labels30
-rw-r--r--Completion/Core/_files59
-rw-r--r--Completion/Core/_next_label5
-rw-r--r--Completion/Core/_requested1
-rw-r--r--Completion/Core/_wanted19
-rw-r--r--Completion/Debian/_apt2
-rw-r--r--Completion/Debian/_deb_packages58
-rw-r--r--Completion/User/_cvs1190
-rw-r--r--Completion/User/_gdb5
-rw-r--r--Completion/User/_gprof60
-rw-r--r--Completion/User/_groups4
-rw-r--r--Completion/User/_lp35
-rw-r--r--Completion/User/_mh15
-rw-r--r--Completion/User/_mount2
-rw-r--r--Completion/User/_netscape24
-rw-r--r--Completion/User/_nslookup52
-rw-r--r--Completion/User/_rlogin8
-rw-r--r--Completion/User/_socket49
-rw-r--r--Completion/User/_tiff6
-rw-r--r--Completion/User/_urls91
-rw-r--r--Completion/User/_users6
-rw-r--r--Completion/User/_users_on6
-rw-r--r--Completion/User/_whois61
-rw-r--r--Completion/X/_x_colormapid4
-rw-r--r--Completion/X/_x_display2
-rw-r--r--Completion/X/_x_extension6
-rw-r--r--Completion/X/_x_font4
-rw-r--r--Completion/X/_x_keysym4
-rw-r--r--Completion/X/_x_window6
-rw-r--r--Completion/X/_xmodmap6
-rw-r--r--Completion/X/_xutils24
-rw-r--r--Completion/X/_xwit2
-rw-r--r--Doc/Zsh/compsys.yo56
-rw-r--r--Etc/completion-style-guide19
-rw-r--r--Functions/Zftp/zfcd_match2
-rw-r--r--Functions/Zftp/zfget_match4
-rw-r--r--Src/Zle/computil.c10
57 files changed, 1312 insertions, 1089 deletions
diff --git a/ChangeLog b/ChangeLog
index c130ef4f8..22a31359c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,36 @@
+2000-04-11  Sven Wischnowsky <wischnow@informatik.hu-berlin.de>
+
+	* 10632: Completion/Base/_brace_parameter, Completion/Base/_condition,
+ 	Completion/Base/_default, Completion/Base/_describe,
+ 	Completion/Base/_first, Completion/Base/_jobs,
+ 	Completion/Base/_values, Completion/Builtins/_compdef,
+ 	Completion/Builtins/_hash, Completion/Builtins/_pids,
+ 	Completion/Builtins/_popd, Completion/Builtins/_sched,
+ 	Completion/Builtins/_signals, Completion/Builtins/_vars,
+ 	Completion/Builtins/_zcompile, Completion/Builtins/_zftp,
+ 	Completion/Builtins/_zpty, Completion/Builtins/_zstyle,
+ 	Completion/Commands/_next_tags, Completion/Core/_all_labels,
+ 	Completion/Core/_files, Completion/Core/_next_label,
+ 	Completion/Core/_requested, Completion/Core/_wanted,
+ 	Completion/Debian/_apt, Completion/Debian/_deb_packages,
+ 	Completion/User/_cvs, Completion/User/_gdb,
+ 	Completion/User/_gprof, Completion/User/_groups,
+ 	Completion/User/_lp, Completion/User/_mh, Completion/User/_mount,
+ 	Completion/User/_netscape, Completion/User/_nslookup,
+ 	Completion/User/_rlogin, Completion/User/_socket,
+ 	Completion/User/_tiff, Completion/User/_urls,
+ 	Completion/User/_users, Completion/User/_users_on,
+ 	Completion/User/_whois, Completion/X/_x_colormapid,
+ 	Completion/X/_x_display, Completion/X/_x_extension,
+ 	Completion/X/_x_font, Completion/X/_x_keysym,
+ 	Completion/X/_x_window, Completion/X/_xmodmap,
+ 	Completion/X/_xutils, Completion/X/_xwit, Doc/Zsh/compsys.yo,
+ 	Etc/completion-style-guide, Functions/Zftp/zfcd_match,
+ 	Functions/Zftp/zfget_match, Src/Zle/computil.c: _wanted now tests
+ 	both tags and labels; change places where _wanted was called
+ 	without a command; allow multiple patterns per string in
+ 	file-patterns; update _next_tags to work with labels
+	
 2000-04-10  Bart Schaefer  <schaefer@brasslantern.com>
 
 	* 10628: Doc/Zsh/compsys.yo, Completion/User/_make: Check for
diff --git a/Completion/Base/_brace_parameter b/Completion/Base/_brace_parameter
index 092376e78..fde6d4f0f 100644
--- a/Completion/Base/_brace_parameter
+++ b/Completion/Base/_brace_parameter
@@ -1,5 +1,3 @@
-#defcomp -brace-parameter-
+#compdef -brace-parameter-
 
-# Simple but without spiffy suffix handling: compgen -v -S '} '
-
-compadd -S '} ' -r '-:?#%+=[/'  - "${(@)${${${(f)$(typeset)}%%\=*}##* }:gs/'//}"
+_parameters -e
diff --git a/Completion/Base/_condition b/Completion/Base/_condition
index 3e45e1b8f..b6a4eff7a 100644
--- a/Completion/Base/_condition
+++ b/Completion/Base/_condition
@@ -1,10 +1,55 @@
-#defcomp -condition-
+#compdef -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
-  _files
+local prev="$words[CURRENT-1]" ret=1
+
+if [[ "$prev" = -o ]]; then
+  _tags -C -o options && _options
+elif [[ "$prev" = -([a-hkprsuwxLOGSN]|[no]t|ef) ]]; then
+  _tags -C "$prev" files && _files
 else
-  _files
-  complist -v
+  if [[ "$PREFIX" = -* ]] ||
+     ! zstyle -T ":completion:${curcontext}:options" prefix-needed; then
+
+    if [[ "$prev" = (\[\[|\|\||\&\&|\!|\() ]]; then
+      _describe -o 'condition code' \
+                '( -a:existing\ file
+	           -b:block\ special\ file
+	           -c:character\ special\ file
+	           -d:directory
+	           -e:existing\ file
+	           -f:regular\ file
+	           -g:setgid\ bit
+	           -h:symbolic\ link
+	           -k:sticky\ bit
+	           -n:non-empty\ string
+	           -o:option
+	           -p:named\ pipe
+	           -r:readable\ file
+	           -s:non-empty\ file
+	           -t:terminal\ file\ descriptor
+	           -u:setuid\ bit
+	           -w:writable\ file
+	           -x:executable\ file
+	           -z:empty\ string
+	           -L:symbolic\ link
+	           -O:own\ file
+	           -G:group-owned\ file
+	           -S:socket
+	           -N:unread\ file)' && ret=0
+    else
+      _describe -o 'condition code' \
+	        '( -nt:newer\ than
+	           -ot:older\ than
+	           -ef:same\ file
+	           -eq:numerically\ equal
+	           -ne:numerically\ not\ equal
+	           -lt:numerically\ less\ than
+	           -le:numerically\ less\ then\ or\ equal
+	           -lt:numerically\ greater\ than
+	           -le:numerically\ greater\ then\ or\ equal)' && ret=0
+    fi
+  fi
+  _alternative 'files:: _files' 'parameters:: _parameters' && ret=0
+
+  return ret
 fi
diff --git a/Completion/Base/_default b/Completion/Base/_default
index fd5869e2e..e5091a544 100644
--- a/Completion/Base/_default
+++ b/Completion/Base/_default
@@ -12,8 +12,6 @@ if { zstyle -s ":completion:${curcontext}:" use-compctl ctl ||
   compcall "$opt[@]" || return 0
 fi
 
-_wanted files || return 1
-
 _files && return 0
 
 # magicequalsubst allows arguments like <any-old-stuff>=~/foo to do
diff --git a/Completion/Base/_describe b/Completion/Base/_describe
index 6e6f4f4a9..ca2d3e4cf 100644
--- a/Completion/Base/_describe
+++ b/Completion/Base/_describe
@@ -14,8 +14,6 @@ fi
 
 # Do the tests. `showd' is set if the descriptions should be shown.
 
-_wanted "$_type" || return 1
-
 zstyle -T ":completion:${curcontext}:$_type" verbose && _showd=yes
 
 _descr="$1"
@@ -24,30 +22,35 @@ shift
 [[ "$_type" = options ]] &&
     zstyle -t ":completion:${curcontext}:options" prefix-hidden && _hide=yes
 
-while _next_label "$_type" _expl "$_descr"; do
+_tags "$_type"
+while _tags; do
+  while _next_label "$_type" _expl "$_descr"; do
 
-  if [[ -n "$_showd" ]]; then
-    compdescribe -I ' -- ' "$@"
-  else
-    compdescribe -i "$@"
-  fi
+    if [[ -n "$_showd" ]]; then
+      compdescribe -I ' -- ' "$@"
+    else
+      compdescribe -i "$@"
+    fi
 
-  while compdescribe -g _args _tmpd _tmpmd _tmps _tmpms; do
+    while compdescribe -g _args _tmpd _tmpmd _tmps _tmpms; do
 
-    # See if we should remove the option prefix characters.
+      # See if we should remove the option prefix characters.
 
-    if [[ -n "$_hide" ]]; then
-      if [[ "$PREFIX" = --* ]]; then
-        _tmpd=( "${(@)_tmpd#--}" )
-        _tmps=( "${(@)_tmps#--}" )
-      elif [[ "$PREFIX" = [-+]* ]]; then
-        _tmpd=( "${(@)_tmpd#[-+]}" )
-        _tmps=( "${(@)_tmps#[-+]}" )
+      if [[ -n "$_hide" ]]; then
+        if [[ "$PREFIX" = --* ]]; then
+          _tmpd=( "${(@)_tmpd#--}" )
+          _tmps=( "${(@)_tmps#--}" )
+        elif [[ "$PREFIX" = [-+]* ]]; then
+          _tmpd=( "${(@)_tmpd#[-+]}" )
+          _tmps=( "${(@)_tmps#[-+]}" )
+        fi
       fi
-    fi
 
-    compadd "$_args[@]" "$_expl[@]" -ld _tmpd - "$_tmpmd[@]" && _ret=0
-    compadd "$_args[@]" "$_expl[@]" -d _tmps  - "$_tmpms[@]" && _ret=0
+      compadd "$_args[@]" "$_expl[@]" -ld _tmpd - "$_tmpmd[@]" && _ret=0
+      compadd "$_args[@]" "$_expl[@]" -d _tmps  - "$_tmpms[@]" && _ret=0
+    done
   done
+  (( _ret )) || return 0
 done
-return _ret
+
+return 1
diff --git a/Completion/Base/_first b/Completion/Base/_first
index d9e7ee82c..93602f307 100644
--- a/Completion/Base/_first
+++ b/Completion/Base/_first
@@ -35,28 +35,35 @@
 # and hitting TAB.
 #
 #     if [[ "$PREFIX" = *,, ]]; then
-#       local max i=1
+#       local max i=1 expl opt
 #     
 #       PREFIX="$PREFIX[1,-2]"
 #       # If a numeric prefix is given, we use it as the number of
 #       # lines (multiplied by ten below) in the history to search.
-#       if [[ NUMERIC -gt 1 ]]; then
+#       if [[ ${NUMERIC:-1} -gt 1 ]]; then
 #         max=$NUMERIC
-#         NUMERIC=1
+#         unset NUMERIC
 #       else
 #         # The default is to search the last 100 lines.
 #         max=10
 #       fi
-#       # We first search in the last ten lines, then in the last
-#       # twenty lines, and so on...
+#       # We first search in the last ten words, then in the last
+#       # twenty words, and so on...
 #       while [[ i -le max ]]; do
-#         if compgen -X "%Bhistory ($n):%b" -Q -H $(( i*10 )) ''; then
+#         if zstyle -t ":completion:${curcontext}:history-words" sort; then
+#           opt=-J
+#         else
+#           opt=-V
+#         fi
+#         if _wanted "$opt" history-words expl "history ($n)" \
+#                compadd "$expl[@]" -Q - \
+#                    "${(@)${(@)historywords:#[\$'\"]*}[1,i*10]}"; then
 #           # We have found at least one matching word, so we switch
 #           # on menu-completion and make sure that no other
-#           # completion function is called by setting _comp_skip.
+#           # completion function is called by setting _compskip.
 #           compstate[insert]=menu
-#           _comp_skip=1
-#           return
+#           _compskip=all
+#           return 0
 #         fi
 #         (( i++ ))
 #       done
diff --git a/Completion/Base/_jobs b/Completion/Base/_jobs
index 45983ad16..359cf0905 100644
--- a/Completion/Base/_jobs
+++ b/Completion/Base/_jobs
@@ -2,8 +2,6 @@
 
 local expl disp jobs job jids pfx='%' desc how expls
 
-_wanted jobs || return 1
-
 if [[ "$1" = -t ]]; then
   zstyle -T ":completion:${curcontext}:jobs" prefix-needed &&
       [[ "$PREFIX" != %* && compstate[nmatches] -ne 0 ]] && return 1
@@ -79,7 +77,7 @@ else
 fi
 
 if [[ -n "$desc" ]]; then
-  _all_labels jobs expl "$expls" compadd "$@" -ld disp - "%$^jobs[@]"
+  _wanted jobs expl "$expls" compadd "$@" -ld disp - "%$^jobs[@]"
 else
-  _all_labels jobs expl "$expls" compadd "$@" - "%$^jobs[@]"
+  _wanted jobs expl "$expls" compadd "$@" - "%$^jobs[@]"
 fi
diff --git a/Completion/Base/_values b/Completion/Base/_values
index eff7b94ce..39c8df201 100644
--- a/Completion/Base/_values
+++ b/Completion/Base/_values
@@ -18,7 +18,7 @@ if compvalues -i "$@"; then
 
   if ! compvalues -D descr action; then
 
-    _wanted values || return 1
+    _tags values || return 1
 
     curcontext="${oldcontext%:*}:values"
 
diff --git a/Completion/Builtins/_compdef b/Completion/Builtins/_compdef
index d47a560c9..6287810e5 100644
--- a/Completion/Builtins/_compdef
+++ b/Completion/Builtins/_compdef
@@ -19,15 +19,13 @@ case $state in
     _wanted commands expl 'completed command' compadd - ${(k)_comps}
   ;;
   cfun)
-    if _wanted functions; then
-      list=( ${^fpath:/.}/_(|*[^~])(N:t) )
-      if zstyle -T ":completion:${curcontext}:functions" prefix-hidden; then
-        disp=( ${list[@]#_} )
-        _all_labels functions expl 'completion function' \
-            compadd -d disp - "$list[@]"
-      else
-        _all_labels functions expl 'completion function' compadd - "$list[@]"
-      fi
+    list=( ${^fpath:/.}/_(|*[^~])(N:t) )
+    if zstyle -T ":completion:${curcontext}:functions" prefix-hidden; then
+      disp=( ${list[@]#_} )
+      _wanted functions expl 'completion function' \
+          compadd -d disp - "$list[@]"
+    else
+      _wanted functions expl 'completion function' compadd - "$list[@]"
     fi
   ;;
   style)
diff --git a/Completion/Builtins/_hash b/Completion/Builtins/_hash
index 171c5e2e8..c577fc4d7 100644
--- a/Completion/Builtins/_hash
+++ b/Completion/Builtins/_hash
@@ -1,13 +1,16 @@
-#defcomp hash
+#compdef hash
 
-if [[ -mword 1 -*d* ]]; then
-  if [[ -string 1 '=' ]]; then
-    _path_files -g '*(-/)'
+local expl
+
+if [[ "$words[2]" = -*d* ]]; then
+  if compset -P 1 '*='; then
+    _wanted -C -d-value files expl directories _path_files -/
   else
-    complist -n -q -S '='
+    _wanted -C -d named-directories expl 'named directory' \
+        compadd -q -S '=' - "${(@k)nameddirs}"
   fi
-elif [[ -string 1 '=' ]]; then
-  _files -/g '*(*)'
+elif compset -P 1 '*='; then
+  _wanted -C value values expl 'executable file' _files "$expl[@]" -g '*(-*)'
 else
-  complist -m -q -S '='
+  _wanted -C name commands expl command compadd -q -S '=' - "${(@k)commands}"
 fi
diff --git a/Completion/Builtins/_pids b/Completion/Builtins/_pids
index 7dec90e7d..1d02f5530 100644
--- a/Completion/Builtins/_pids
+++ b/Completion/Builtins/_pids
@@ -5,7 +5,7 @@
 
 local out list expl match desc listargs args
 
-_wanted processes || return 1
+_tags processes || return 1
 
 if [[ "$1" = -m ]]; then
   match="${2}*"
@@ -29,6 +29,6 @@ else
   desc=()
 fi
 
-_all_labels processes expl 'process ID' \
+_wanted processes expl 'process ID' \
     compadd "$@" "$desc[@]" - \
         ${${${(M)${(f)"${out}"}[2,-1]:#[ 	]#${PREFIX}[0-9]#${SUFFIX}[ 	]#*${~match}}## #}%% *}
diff --git a/Completion/Builtins/_popd b/Completion/Builtins/_popd
index 2a3413253..19b773173 100644
--- a/Completion/Builtins/_popd
+++ b/Completion/Builtins/_popd
@@ -12,8 +12,6 @@ local expl list lines revlines disp
 ! zstyle -T ":completion:${curcontext}:directory-stack" prefix-needed ||
     [[ $PREFIX = [-+]* ]] || return 1
 
-_wanted directory-stack || return 1
-
 if zstyle -T ":completion:${curcontext}:directory-stack" verbose; then
   # get the list of directories with their canonical number
   # and turn the lines into an array, removing the current directory
@@ -39,5 +37,5 @@ else
   disp=()
 fi
 
-_all_labels -V directory-stack expl 'directory stack' \
+_wanted -V directory-stack expl 'directory stack' \
     compadd "$@" "$disp[@]" -Q - "$list[@]"
diff --git a/Completion/Builtins/_sched b/Completion/Builtins/_sched
index 98ecb3642..82b8a7c91 100644
--- a/Completion/Builtins/_sched
+++ b/Completion/Builtins/_sched
@@ -4,15 +4,13 @@ local expl lines disp
 
 if [[ CURRENT -eq 2 ]]; then
   if compset -P -; then
-    _wanted -C - jobs || return 1
-
     lines=(${(f)"$(sched)"})
     if zstyle -T ":completion:${curcontext}:jobs" verbose; then
       disp=( -ld lines )
     else
       disp=()
     fi
-    [[ -z $lines ]] || _all_labels jobs expl 'scheduled jobs' \
+    [[ -z $lines ]] || _wanted jobs expl 'scheduled jobs' \
                            compadd "$disp[@]" - {1..$#lines}
     return
   else
diff --git a/Completion/Builtins/_signals b/Completion/Builtins/_signals
index aa95a8499..447d9d16c 100644
--- a/Completion/Builtins/_signals
+++ b/Completion/Builtins/_signals
@@ -20,10 +20,9 @@ done
 
 [[ "$1" = -(|-) ]] && shift
 
-if _wanted signals &&
-       { [[ -z "$minus" ]] ||
-         ! zstyle -T ":completion:${curcontext}:signals" prefix-needed ||
-         [[ "$PREFIX" = -* ]] } ; then
+if [[ -z "$minus" ]] ||
+   ! zstyle -T ":completion:${curcontext}:signals" prefix-needed ||
+   [[ "$PREFIX" = -* ]]; then
   local disp tmp
 
   if zstyle -t ":completion:${curcontext}:signals" prefix-hidden; then
@@ -32,7 +31,7 @@ if _wanted signals &&
   else
     disp=()
   fi
-  _all_labels signals expl signal \
+  _wanted signals expl signal \
       compadd "$@" "$disp[@]" -M 'm:{a-z}={A-Z}' - \
               "${minus}${(@)^signals[1,last]}"
 fi
diff --git a/Completion/Builtins/_vars b/Completion/Builtins/_vars
index 43cdf5d2c..711a0a1f2 100644
--- a/Completion/Builtins/_vars
+++ b/Completion/Builtins/_vars
@@ -1,8 +1,8 @@
 #compdef getopts read unset vared
 
 # This will handle completion of keys of associative arrays, e.g. at
-# `vared compconfig[<TAB>'.  However, in this version the [ must be
-# added by hand.
+# `vared foo[<TAB>'.  However, in this version the [ must be added
+# by hand.
 
 if [[ $PREFIX = *\[* ]]; then
   local var=${PREFIX%%\[*}
@@ -16,13 +16,9 @@ if [[ $PREFIX = *\[* ]]; then
   if [[ ${(tP)var} = assoc* ]]; then
     local expl
 
-    _tags subscript association-keys || return 1
-
-    _description expl 'association key'
-    compadd "$expl[@]" $addclose - ${(kP)var}
+    _wanted -C subscript association-keys expl 'association key' \
+        compadd $addclose - ${(kP)var}
   fi
 else
-  _tags any parameters || return 1
-
   _parameters
 fi
diff --git a/Completion/Builtins/_zcompile b/Completion/Builtins/_zcompile
index 5ec6f96ce..c82226dc2 100644
--- a/Completion/Builtins/_zcompile
+++ b/Completion/Builtins/_zcompile
@@ -18,5 +18,6 @@ _arguments -s \
 if (( $+opt_args[-c] )); then
   _wanted functions expl 'function to write' compadd - ${(k)functions}
 else
-  _wanted file expl 'zsh source file' _files
+  _description files expl 'zsh source file'
+  _files "$expl[@]"
 fi
diff --git a/Completion/Builtins/_zftp b/Completion/Builtins/_zftp
index 0d6530dfc..610af2607 100644
--- a/Completion/Builtins/_zftp
+++ b/Completion/Builtins/_zftp
@@ -28,35 +28,34 @@ fi
 case $subcom in
   *(cd|ls|dir))
     # complete remote directories
-    _wanted directories && zfcd_match $PREFIX $SUFFIX
+    _tags directories && zfcd_match $PREFIX $SUFFIX
     ;;
 
   *(get(|at)|gcp|delete|remote))
     # complete remote files
-    _wanted files && zfget_match $PREFIX $SUFFIX
+    _tags files && zfget_match $PREFIX $SUFFIX
     ;;
 
   *(put(|at)|pcp))
     # complete local files
-    _wanted files && _files
+    _files
     ;;
 
   *(open|anon|params))
     # complete hosts:  should do cleverer stuff with user names
-    _wanted hosts && _hosts
+    _hosts
     ;;
 
   *(goto|mark))
     # complete bookmarks.  First decide if ncftp mode is go.
-    _wanted bookmarks || return 1
     if [[ $words[2] = -*n* ]]; then
       if [[ -f ~/.ncftp/bookmarks ]]; then
-        _all_labels bookmarks expl bookmark \
+        _wanted bookmarks expl bookmark \
             compadd - $(awk -F, 'NR > 2 { print $1 }' ~/.ncftp/bookmarks)
       fi
     else
       if [[ -f ${ZFTP_BMFILE:=${ZDOTDIR:-$HOME}/.zfbkmarks} ]]; then
-        _all_labels bookmarks expl bookmark \
+        _wanted bookmarks expl bookmark \
             compadd - $(awk '{print $1}' $ZFTP_BMFILE)
       fi
     fi
@@ -72,7 +71,7 @@ case $subcom in
     # complete arguments like sess1:file1 sess2:file2
     if [[ $PREFIX = *:* ]]; then
       # complete file in the given session
-      _wanted files || return 1
+      _tags files || return 1
       local sess=${PREFIX%%:*} oldsess=$ZFTP_SESSION
       compset -p $(( $#sess + 1 ))
       [[ -n $sess ]] && zftp session $sess
diff --git a/Completion/Builtins/_zpty b/Completion/Builtins/_zpty
index d8c77ff2e..ac631baf4 100644
--- a/Completion/Builtins/_zpty
+++ b/Completion/Builtins/_zpty
@@ -11,13 +11,13 @@ _arguments -C -s \
   '(-e -b -d -w -r)-L[list defined commands as calls]' \
   '(-r)*::args:_normal'
 
-if [[ $state = name ]] && _wanted names; then
+if [[ $state = name ]]; then
   list=( ${${(f)"$(zpty)"}#*\) } )
   names=( ${list%%:*} )
   if zstyle -T ":completion:${curcontext}" verbose; then
     zformat -a list ' --' ${${(f)"$(zpty)"}#*\) }
-    _all_labels names expl 'zpty command names' compadd -d list - "$names[@]"
+    _wanted names expl 'zpty command names' compadd -d list - "$names[@]"
   else
-    _all_labels names expl 'zpty command names' compadd - "$names[@]"
+    _wanted names expl 'zpty command names' compadd - "$names[@]"
   fi
 fi
diff --git a/Completion/Builtins/_zstyle b/Completion/Builtins/_zstyle
index b4e151d78..b19303300 100644
--- a/Completion/Builtins/_zstyle
+++ b/Completion/Builtins/_zstyle
@@ -96,20 +96,18 @@ while [[ -n $state ]]; do
 
   case "$ostate" in
     contexts)
-      if _wanted contexts; then
-        if [[ $PREFIX != :*: ]]; then
-	  _all_labels contexts expl context compadd -P : -S : completion zftp
-        elif [[ $PREFIX = :completion:* ]]; then
-          mesg=''
-          case "$PREFIX" in
-          :completion:[^:]#) mesg=function ;;
-          :completion:[^:]#:[^:]#) mesg=completer ;;
-          :completion:[^:]#:[^:]#:[^:]#) mesg='command or context' ;;
-          :completion:[^:]#:[^:]#:[^:]#:[^:]#) mesg=argument ;;
-          :completion:[^:]#:[^:]#:[^:]#:[^:]#:[^:]#) mesg=tag ;;
-	  esac
-	  [[ -n "$mesg" ]] && _message "$mesg"
-        fi
+      if [[ $PREFIX != :*: ]]; then
+	_wanted contexts expl context compadd -P : -S : completion zftp
+      elif [[ $PREFIX = :completion:* ]] && _tags contexts; then
+        mesg=''
+        case "$PREFIX" in
+        :completion:[^:]#) mesg=function ;;
+        :completion:[^:]#:[^:]#) mesg=completer ;;
+        :completion:[^:]#:[^:]#:[^:]#) mesg='command or context' ;;
+        :completion:[^:]#:[^:]#:[^:]#:[^:]#) mesg=argument ;;
+        :completion:[^:]#:[^:]#:[^:]#:[^:]#:[^:]#) mesg=tag ;;
+	esac
+	[[ -n "$mesg" ]] && _message "$mesg"
       fi
       ;;
 
diff --git a/Completion/Commands/_next_tags b/Completion/Commands/_next_tags
index d9a5f08d8..a308b307c 100644
--- a/Completion/Commands/_next_tags
+++ b/Completion/Commands/_next_tags
@@ -3,30 +3,103 @@
 # Main widget.
 
 _next_tags() {
-  local comp ins
+  local ins ops="$PREFIX$SUFFIX"
 
-  if [[ -z $compstate[old_list] ]]; then
-    comp=()
+  unfunction _all_labels _next_label
+
+  _all_labels() {
+    local gopt=-J len tmp pre suf ret=1 descr spec
+
+    if [[ "$1" = -([12]|)[VJ] ]]; then
+      gopt="$1"
+      shift
+    fi
+
+    tmp=${argv[(ib:4:)-]}
+    len=$#
+    if [[ tmp -lt len ]]; then
+      pre=$(( tmp-1 ))
+      suf=$tmp
+    elif [[ tmp -eq $# ]]; then
+      pre=-2
+      suf=$(( len+1 ))
+    else
+      pre=4
+      suf=5
+    fi
+
+    while comptags -A "$1" curtag spec; do
+      [[ "$_next_tags_not" = *\ ${spec}\ * ]] && continue
+      _comp_tags="$_comp_tags $spec "
+      if [[ "$curtag" = *:* ]]; then
+        zformat -f descr "${curtag#*:}" "d:$3"
+        _description "$gopt" "${curtag%:*}" "$2" "$descr"
+        curtag="${curtag%:*}"
+
+        "$4" "${(P@)2}" "${(@)argv[5,-1]}"
+      else
+        _description "$gopt" "$curtag" "$2" "$3"
+
+        "${(@)argv[4,pre]}" "${(P@)2}" "${(@)argv[suf,-1]}" && ret=0
+      fi
+    done
+
+    return ret
+  }
+
+  _next_label() {
+    local gopt=-J descr spec
+
+    if [[ "$1" = -([12]|)[VJ] ]]; then
+      gopt="$1"
+      shift
+    fi
+
+    if comptags -A "$1" curtag spec; then
+      [[ "$_next_tags_not" = *\ ${spec}\ * ]] && continue
+      _comp_tags="$_comp_tags $spec "
+      if [[ "$curtag" = *:* ]]; then
+        zformat -f descr "${curtag#*:}" "d:$3"
+        _description "$gopt" "${curtag%:*}" "$2" "$descr"
+        curtag="${curtag%:*}"
+        eval "${2}=( \${(P)2} \$argv[4,-1] )"
+      else
+        _description "$gopt" "$curtag" "$2" "$3"
+        eval "${2}=( \$argv[4,-1] \${(P)2} )"
+      fi
+
+      return 0
+    fi
+
+    return 1
+  }
+
+  if [[ "${LBUFFER%${PREFIX}}" = "$_next_tags_pre" ]]; then
+    PREFIX="$_next_tags_pfx"
+    SUFFIX="$_next_tags_sfx"
   else
-    comp=(_complete)
+    _next_tags_pre="${LBUFFER%${PREFIX}}"
+    if [[ "$LASTWIDGET" = (_next_tags|list-*|*complete*) ]]; then
+      PREFIX="$_lastcomp[prefix]"
+      SUFFIX="$_lastcomp[suffix]"
+    fi
   fi
 
-  (( $+_sort_tags )) || _next_tags_not=
-
-  _sort_tags=_next_tags_sort
-  _next_tags_pre="${LBUFFER%${PREFIX}}"
   _next_tags_not="$_next_tags_not $_lastcomp[tags]"
+  _next_tags_pfx="$PREFIX"
+  _next_tags_sfx="$SUFFIX"
 
   if [[ -n "$compstate[old_insert]" ]]; then
-    PREFIX="$_lastcomp[prefix]"
-    SUFFIX="$_lastcomp[suffix]"
     ins=1
+  else
+    ins=unambiguous
   fi
 
-  _main_complete "$comp[@]"
+  _main_complete _complete _next_tags_completer
 
-  [[ $compstate[insert] = automenu ]] &&
-     compstate[insert]=automenu-unambiguous
+  [[ $compstate[insert] = automenu ]] && compstate[insert]=automenu-unambiguous
+  [[ $compstate[insert] = *unambiguous && -n "$ops" &&
+     -z "$_lastcomp[unambiguous]" ]] && compadd -Uns "$SUFFIX" - "$PREFIX"
 
   compstate[insert]="$ins"
   compstate[list]='list force'
@@ -34,11 +107,19 @@ _next_tags() {
   compprefuncs=( "$compprefuncs[@]" _next_tags_pre )
 }
 
+# Completer, for wrap-around.
+
+_next_tags_completer() {
+  _next_tags_not=
+
+  _complete
+}
+
 # Pre-completion function.
 
 _next_tags_pre() {
 
-  # Probably `remove' our sort function. A better test would be nice, but
+  # Probably `remove' our label functions. A better test would be nice, but
   # I think one should still be able to edit the current word between
   # attempts to complete it.
 
@@ -47,65 +128,10 @@ _next_tags_pre() {
     compstate[insert]=menu:2
     return 0
   elif [[ ${LBUFFER%${PREFIX}} != ${_next_tags_pre}* ]]; then
-    unset _sort_tags
+    unfunction _all_labels _next_label
+    autoload -U _all_labels _next_label
   else
     compprefuncs=( "$compprefuncs[@]" _next_tags_pre )
-    [[ -n "$compstate[old_list]" && -n "$_next_tags_reset" ]] &&
-        _next_tags_not= _next_tags_reset=
-  fi
-}
-
-# Helper function for sorting tags. Most of this is copied from _tags.
-
-_next_tags_sort() {
-  local order tags tag nodef tmp
-
-  zstyle -a ":completion:${curcontext}:" tag-order order ||
-      order=('arguments values' options)
-
-  # But we also remove the tags we've already tried...
-
-  tags=( "${(@)order:#(${(j:|:)~${=_next_tags_not}})(|:*)}" )
-
-  # ... unless that would remove all offered tags.
-
-  if [[ $funcstack[4] = _files ]]; then
-    if zstyle -a ":completion:${curcontext}:" file-patterns tmp; then
-      [[ "$tags" = *${${tmp[-1]##[^\\]:}%:*}* ]] &&
-          tags=( $order ) _next_tags_reset=yes
-    else
-      [[ "$tags" = *all-files* ]] && tags=( $order ) _next_tags_reset=yes
-    fi
-  else
-     [[ $#tags -ne $#order && "$tags" != *(${(j:|:)~argv})* ]] &&
-        tags=( $order ) _next_tags_reset=yes
-  fi
-  for tag in $tags; do
-    case $tag in
-    -)     nodef=yes;;
-    *\(\)) "${${tag%%[ 	]#\(\)}##[ 	]#}" "$@";;
-    \!*)   comptry "${(@)argv:#(${(j:|:)~${=~tag[2,-1]}})}";;
-    ?*)    comptry -m "$tag";;
-    esac
-  done
-
-  if [[ -z "$nodef" ]]; then
-    if [[ $funcstack[4] = _files ]]; then
-      if zstyle -a ":completion:${curcontext}:" file-patterns tmp; then
-        [[ "$argv" = *${${tmp[-1]#*[^\\]:}%:*}* ]] && _next_tags_reset=yes
-      else
-        [[ "$argv" = *all-files* ]] && _next_tags_reset=yes
-      fi
-    fi
-    tmp=( "${(@)argv:#(${(j:|:)~${=_next_tags_not}})(|:*)}" )
-
-    # $prev is set in _tags!
-
-    if [[ -n "$prev" && ( $#tmp -ne 0 || $funcstack[4] = _files ) ]]; then
-      comptry "$tmp[@]"
-    else
-      comptry "$argv[@]"
-    fi
   fi
 }
 
diff --git a/Completion/Core/_all_labels b/Completion/Core/_all_labels
index fa7118ec4..a03112ee4 100644
--- a/Completion/Core/_all_labels
+++ b/Completion/Core/_all_labels
@@ -1,11 +1,7 @@
 #autoload
 
-local gopt=-J len tmp pre suf tloop ret=1 descr
+local gopt=-J len tmp pre suf ret=1 descr spec
 
-if [[ "$1" = -t ]]; then
-  tloop=yes
-  shift
-fi
 if [[ "$1" = -([12]|)[VJ] ]]; then
   gopt="$1"
   shift
@@ -24,21 +20,19 @@ else
   suf=5
 fi
 
-while [[ -z "$tloop" ]] || comptags -N; do
-  while comptags -A "$1" curtag; do
-    if [[ "$curtag" = *:* ]]; then
-      zformat -f descr "${curtag#*:}" "d:$3"
-      _description "$gopt" "${curtag%:*}" "$2" "$descr"
-      curtag="${curtag%:*}"
+while comptags -A "$1" curtag spec; do
+  _comp_tags="$_comp_tags $spec "
+  if [[ "$curtag" = *:* ]]; then
+    zformat -f descr "${curtag#*:}" "d:$3"
+    _description "$gopt" "${curtag%:*}" "$2" "$descr"
+    curtag="${curtag%:*}"
 
-      "$4" "${(P@)2}" "${(@)argv[5,-1]}"
-    else
-      _description "$gopt" "$curtag" "$2" "$3"
+    "$4" "${(P@)2}" "${(@)argv[5,-1]}"
+  else
+    _description "$gopt" "$curtag" "$2" "$3"
 
-      "${(@)argv[4,pre]}" "${(P@)2}" "${(@)argv[suf,-1]}" && ret=0
-    fi
-  done
-  [[ -z "$tloop" || ret -eq 0 ]] && break
+    "${(@)argv[4,pre]}" "${(P@)2}" "${(@)argv[suf,-1]}" && ret=0
+  fi
 done
 
 return ret
diff --git a/Completion/Core/_files b/Completion/Core/_files
index 8a9bbfc95..a64e5c093 100644
--- a/Completion/Core/_files
+++ b/Completion/Core/_files
@@ -6,7 +6,7 @@ zparseopts -a opts \
     '/=tmp' 'f=tmp' 'g+:-=tmp' q n 1 2 P: S: r: R: W: X+: M+: F: J+: V+:
 
 type="${(@j::M)${(@)tmp#-}#?}"
-(( $tmp[(I)-g*] )) && glob="${(j: :)${(@M)tmp:#-g*}#-g}"
+(( $tmp[(I)-g*] )) && glob="${(j:,:)${(@M)tmp:#-g*}#-g}"
 ign=$opts[(I)-F]
 if (( ign )); then
   ign=( $=opts[ign+1] )
@@ -20,56 +20,59 @@ else
 fi
 
 if zstyle -a ":completion:${curcontext}:" file-patterns tmp; then
-  [[ "$type" = */* ]] && glob="$glob *(-/)"
+  [[ "$type" = */* ]] && glob="$glob,*(-/)"
   pats=()
   for i in ${tmp//\\%p/ ${${glob:-\*}//:/\\:} }; do
     if [[ $i = *[^\\]:* ]]; then
-      pats=( "$pats[@]" " $i" )
+      pats=( "$pats[@]" " $i " )
     else
-      pats=( "$pats[@]" " ${i}:files" )
+      pats=( "$pats[@]" " ${i}:files " )
     fi
   done
 else
   if [[ "$type" = *g* ]]; then
     if [[ "$type" = */* ]]; then
-      pats=( " ${glob//:/\\:} *(-/):globbed-files" '*:all-files' )
+      pats=( " ${glob//:/\\:}:globbed-files *(-/):directories" '*:all-files ' )
     else
-      pats=( " ${glob//:/\\:}:globbed-files"
-             '*(-/):directories' '*:all-files' )
+      pats=( " ${glob//:/\\:}:globbed-files "
+             '*(-/):directories ' '*:all-files ' )
     fi
   elif [[ "$type" = */* ]]; then
-    pats=( '*(-/):directories' '*:all-files' )
+    pats=( '*(-/):directories ' '*:all-files ' )
   else
-    pats=( '*:all-files' )
+    pats=( '*:all-files ' )
   fi
 fi
 
-for def in "$pats[@]"; do ###"${(@)${(@)pats#*[^\\]:}%%:*}"; do
+for def in "$pats[@]"; do
+  def="${def##[[:blank:]]#}"
+  while [[ "$def" = *[^\\][[:blank:]]* ]]; do
+    sdef="${(M)def#*[^\\][[:blank:]]}"
+    tag="${${sdef#*[^\\]:}%%:*}"
+    pat="${${${sdef%%:${tag}*}//\\\\:/:}//,/ }"
 
-  tag="${${def#*[^\\]:}%%:*}"
-  pat="${${def%%:${tag}*}//\\\\:/:}"
-
-  if [[ "$pat" != \ # ]]; then
-    if [[ "$def" = *:${tag}:* ]]; then
-      descr="${def#*:${tag}:}"
+    if [[ "$sdef" = *:${tag}:* ]]; then
+      descr="${(Q)sdef#*:${tag}:}"
     else
       descr=file
       end=yes
     fi
-  fi
 
-  if _wanted "$tag"; then
-    _comp_ignore=()
-    while _next_label "$tag" expl "$descr"; do
-      _comp_ignore=( $_comp_ignore $ign )
-      if [[ -n "$end" ]]; then
-        _path_files -g "$pat" "$opts[@]" "$expl[@]" && ret=0
-      else
-        _path_files "$expl[@]" -g "$pat" "$opts[@]" && ret=0
-      fi
+    _tags "$tag"
+    while _tags; do
+      _comp_ignore=()
+      while _next_label "$tag" expl "$descr"; do
+        _comp_ignore=( $_comp_ignore $ign )
+        if [[ -n "$end" ]]; then
+          _path_files -g "$pat" "$opts[@]" "$expl[@]" && ret=0
+        else
+          _path_files "$expl[@]" -g "$pat" "$opts[@]" && ret=0
+        fi
+      done
     done
-    (( ret )) || return 0
-  fi
+    def="${${def#${sdef}}##[[:blank:]]#}"
+  done
+  (( ret )) || return 0
 done
 
 return 1
diff --git a/Completion/Core/_next_label b/Completion/Core/_next_label
index e309e53ea..d2d698171 100644
--- a/Completion/Core/_next_label
+++ b/Completion/Core/_next_label
@@ -1,13 +1,14 @@
 #autoload
 
-local gopt=-J descr
+local gopt=-J descr spec
 
 if [[ "$1" = -([12]|)[VJ] ]]; then
   gopt="$1"
   shift
 fi
 
-if comptags -A "$1" curtag; then
+if comptags -A "$1" curtag spec; then
+  _comp_tags="$_comp_tags $spec "
   if [[ "$curtag" = *:* ]]; then
     zformat -f descr "${curtag#*:}" "d:$3"
     _description "$gopt" "${curtag%:*}" "$2" "$descr"
diff --git a/Completion/Core/_requested b/Completion/Core/_requested
index bd838a28e..90fdec279 100644
--- a/Completion/Core/_requested
+++ b/Completion/Core/_requested
@@ -8,7 +8,6 @@ if [[ "$1" = -([12]|)[VJ] ]]; then
 fi
 
 if comptags -R "$1"; then
-  _comp_tags="$_comp_tags $1"
   if [[ $# -gt 3 ]]; then
     _all_labels "$gopt" "$@"
   elif [[ $# -gt 1 ]]; then
diff --git a/Completion/Core/_wanted b/Completion/Core/_wanted
index 32875ec57..958f9e18e 100644
--- a/Completion/Core/_wanted
+++ b/Completion/Core/_wanted
@@ -17,17 +17,10 @@ if [[ "$1" = -([12]|)[VJ] ]]; then
   shift
 fi
 
-if [[ $# -gt 3 ]]; then
-  if _tags "$targs[@]" "$1"; then
-    _comp_tags="$_comp_tags $1"
+_tags "$targs[@]" "$1"
 
-    _all_labels -t "$gopt" "$@"
-  else
-    return 1
-  fi
-elif [[ $# -gt 1 ]]; then
-  _tags -- "$targs[@]" "$1" && _comp_tags="$_comp_tags $1" &&
-    _description "$gopt" "$@"
-else
-  _tags -- "$targs[@]" "$1" && _comp_tags="$_comp_tags $1"
-fi
+while _tags; do
+  _all_labels "$gopt" "$@" && return 0
+done
+
+return 1
diff --git a/Completion/Debian/_apt b/Completion/Debian/_apt
index 169b5f5f7..66129c949 100644
--- a/Completion/Debian/_apt
+++ b/Completion/Debian/_apt
@@ -75,7 +75,7 @@ _apt_arguments () {
   nul=$'\0'
   qnul="\$'\\0'"
 
-  comp_bool='_wanted values && compadd "$expl_bool[@]" '"$bool"
+  comp_bool='_wanted values expl_bool "boolean value" compadd "$expl_bool[@]" '"$bool"
   comp_intlevel= #"_message 'intlevel'"
   comp_configfile='_files "$expl_configfile[@]"'
   comp_arbitem= #"_message 'Foo::Bar=bar'"
diff --git a/Completion/Debian/_deb_packages b/Completion/Debian/_deb_packages
index b5e4ffd85..7973d9868 100644
--- a/Completion/Debian/_deb_packages
+++ b/Completion/Debian/_deb_packages
@@ -1,7 +1,57 @@
 #autoload
 
-if (( ! $+_deb_packages )); then
-  _deb_packages=( $(awk '/^Package:/ { print $2 }' /var/lib/dpkg/status) )
-fi
+# Usage: _deb_packages expl... avail|installed|uninstalled
 
-compadd "$@" - $_deb_packages
+_deb_packages_update_avail () {
+  if (( ! $+_deb_packages_cache_avail )); then
+    _deb_packages_cache_avail=(
+      ${(f)"$(apt-cache dumpavail | awk '/^Package:/ { print $2 }')"}
+    )
+  fi
+  cachevar=_deb_packages_cache_avail
+}
+
+_deb_packages_update_installed () {
+  if (( ! $+_deb_packages_cache_installed )); then
+    _deb_packages_cache_installed=(
+      ${${${(f)"$(dpkg --get-selections)"}:#*deinstall}%%	*}
+    )
+  fi
+  cachevar=_deb_packages_cache_installed
+}
+
+_deb_packages_update_uninstalled () {
+  _deb_packages_update_avail
+  _deb_packages_update_installed
+  if (( ! $+_deb_packages_cache_uninstalled )); then
+    _deb_packages_cache_uninstalled=(
+      ${_deb_packages_cache_avail:#${(j:|:)~${_deb_packages_cache_installed:q}}}
+    )
+  fi
+  cachevar=_deb_packages_cache_uninstalled
+}
+
+_deb_packages () {
+  local command="$argv[$#]" expl cachevar pkgset
+
+  [[ "$command" = (installed|uninstalled|avail) ]] || {
+    _message "_deb_packages:unknown command: $command"
+    return
+  }
+
+  zstyle -s ":completion:${curcontext}:" packageset pkgset
+
+  [[ "$pkgset" = (installed|uninstalled|avail|available) ]] || {
+    pkgset="$command"
+  }
+
+  [[ "$pkgset" = "available" ]] && pkgset="avail"
+
+  expl=("${(@)argv[1,-2]}")
+
+  _deb_packages_update_$pkgset
+
+  _tags packages && compadd "$expl[@]" - "${(@P)cachevar}"
+}
+
+_deb_packages "$@"
diff --git a/Completion/User/_cvs b/Completion/User/_cvs
index 356c7a80a..ce928fe50 100644
--- a/Completion/User/_cvs
+++ b/Completion/User/_cvs
@@ -19,662 +19,640 @@ _cvs () {
 
 # define cvs command dispatch function.
 
-if ! builtin functions _cvs_command >&-; then
-  _cvs_command () {
-    typeset -A cmds
-    cmds=(add " ad new "          admin " adm rcs "       annotate " ann "
-	  checkout " co get "     commit " ci com "       diff " di dif "
-	  edit ""                 editors ""              export " exp ex "
-	  history " hi his "      import " im imp "       init ""
-	  log " lo rlog "         login " logon lgn "     logout ""
-	  rdiff " patch pa "      release " re rel "      remove " rm delete "
-	  status " st stat "      rtag " rt rfreeze "     tag " ta freeze "
-	  unedit ""               update " up upd "       watch ""
-	  watchers "")
-
-    if (( CURRENT == 1 )); then
-      compadd "$@" ${(k)cmds} || compadd "$@" ${(kv)=cmds}
+(( $+functions[_cvs_command] )) ||
+_cvs_command () {
+  local cmd
+  typeset -A cmds
+  cmds=(add " ad new "          admin " adm rcs "       annotate " ann "
+	checkout " co get "     commit " ci com "       diff " di dif "
+	edit ""                 editors ""              export " exp ex "
+	history " hi his "      import " im imp "       init ""
+	log " lo rlog "         login " logon lgn "     logout ""
+	rdiff " patch pa "      release " re rel "      remove " rm delete "
+	status " st stat "      rtag " rt rfreeze "     tag " ta freeze "
+	unedit ""               update " up upd "       watch ""
+	watchers "")
+
+  if (( CURRENT == 1 )); then
+    _tags commands && { compadd "$@" ${(k)cmds} || compadd "$@" ${(kv)=cmds} }
+  else
+    local curcontext="$curcontext"
+
+    cmd="${${(k)cmds[(R)* $words[1] *]}:-${(k)cmds[(i)$words[1]]}}"
+    if (( $#cmd )); then
+      curcontext="${curcontext%:*:*}:cvs-${cmd}:"
+      _cvs_$cmd
     else
-      case "${${(k)cmds[(R)* $words[1] *]}:-$words[1]}" in
-	add) _cvs_add;;
-	admin) _cvs_admin;;
-	annotate) _cvs_annotate;;
-	checkout) _cvs_checkout;;
-	commit) _cvs_commit;;
-	diff) _cvs_diff;;
-	edit) _cvs_edit;;
-	editors) _cvs_editors;;
-	export) _cvs_export;;
-	history) _cvs_history;;
-	import) _cvs_import;;
-	init) _cvs_init;;
-	log) _cvs_log;;
-	login) _cvs_login;;
-	logout) _cvs_logout;;
-	rdiff) _cvs_rdiff;;
-	release) _cvs_release;;
-	remove) _cvs_remove;;
-	status) _cvs_status;;
-	rtag) _cvs_rtag;;
-	tag) _cvs_tag;;
-	unedit) _cvs_unedit;;
-	update) _cvs_update;;
-	watch) _cvs_watch;;
-	watchers) _cvs_watchers;;
-	*) _message "unknown cvs command: $words[1]";;
-      esac
+      _message "unknown cvs command: $words[1]"
     fi
-  }
-fi
+  fi
+}
 
 # define completion functions for each cvs command
 
-if ! builtin functions _cvs_add >&-; then
-  _cvs_add () {
-    # "+k:m:"
-    _arguments -s \
-      '-k+:keyword substitution:_cvs_k' \
-      '-m+:message:_cvs_m' \
-      '*:file:_cvs_files_unmaintained' \
-  }
-fi
-
-if ! builtin functions _cvs_admin >&-; then
-  _cvs_admin () {
-    # "+ib::c:a:A:e:l::u::LUn:N:m:o:s:t::IqxV:k:"
-    _arguments -s \
-      -{i,L,U,I,q,x} \
-      '-b-:default branch:(1.1.1)' \
-      '-c+:comment leader (not used):' \
-      '-a+:login names (not work with CVS):' \
-      '-A+:access list to append (not work with CVS):' \
-      '-e+:access list to erase (not work with CVS):' \
-      '-l-:revision to lock:' \
-      '-u-:revision to unlock:' \
-      '-n+:symbolic-name[\:revision]:' \
-      '-N+:symbolic-name[\:revision]:' \
-      '-m+:revision\:msg:' \
-      '-o+:range to delete:' \
-      '-s+:state[\:revision]:' \
-      '-t-:descriptive text:_cvs_admin_t' \
-      '-V+:version (obsolete):' \
-      '-k+:keyword substitution:_cvs_k' \
-      '*:file:_cvs_files'
-  }
-fi
+(( $+functions[_cvs_add] )) ||
+_cvs_add () {
+  # "+k:m:"
+  _arguments -s \
+    '-k+:keyword substitution:_cvs_k' \
+    '-m+:message:_cvs_m' \
+    '*:file:_cvs_files_unmaintained' \
+}
 
-if ! builtin functions _cvs_admin_t >&-; then
-  _cvs_admin_t () {
-    if compset -P -; then
-      _message 'descriptive text'
-    else
-      _files "$@"
-    fi
-  }
-fi
-
-if ! builtin functions _cvs_annotate >&-; then
-  _cvs_annotate () {
-    # "+lr:D:fR"
-    _arguments -s \
-      -{l,f,R} \
-      '-r+:tag:_cvs_revisions' \
-      '-D+:date:_cvs_D' \
-      '*:file:_cvs_files'
-  }
-fi
-
-if ! builtin functions _cvs_checkout >&-; then
-  _cvs_checkout () {
-    # "+ANnk:d:flRpQqcsr:D:j:P"
-    _arguments -s \
-      -{A,N,n,f,l,R,q,c,s,P} \
-      '-k+:keyword substitution:_cvs_k' \
-      '-d+:directory:_files -/' \
-      '-r+:tag:_cvs_revisions' \
-      '-D+:date:_cvs_D' \
-      '-j+:tag:_cvs_revisions' \
-      '*:module:_cvs_modules'
-  }
-fi
-
-if ! builtin functions _cvs_commit >&-; then
-  _cvs_commit () {
-    # "+nlRm:fF:r:"
-    _arguments -s \
-      -{n,l,R,f} \
-      '-m+:message:_cvs_m' \
-      '-F+:log message file:_files' \
-      '-r+:tag:_cvs_revisions' \
-      '*:file:_cvs_files_modified'
-  }
-fi
+(( $+functions[_cvs_admin] )) ||
+_cvs_admin () {
+  # "+ib::c:a:A:e:l::u::LUn:N:m:o:s:t::IqxV:k:"
+  _arguments -s \
+    -{i,L,U,I,q,x} \
+    '-b-:default branch:(1.1.1)' \
+    '-c+:comment leader (not used):' \
+    '-a+:login names (not work with CVS):' \
+    '-A+:access list to append (not work with CVS):' \
+    '-e+:access list to erase (not work with CVS):' \
+    '-l-:revision to lock:' \
+    '-u-:revision to unlock:' \
+    '-n+:symbolic-name(\:revision):' \
+    '-N+:symbolic-name(\:revision):' \
+    '-m+:revision\:msg:' \
+    '-o+:range to delete:' \
+    '-s+:state(\:revision):' \
+    '-t-:descriptive text:_cvs_admin_t' \
+    '-V+:version (obsolete):' \
+    '-k+:keyword substitution:_cvs_k' \
+    '*:file:_cvs_files'
+}
 
-if ! builtin functions _cvs_diff >&-; then
-  _cvs_diff () {
-    # "+abcdefhilnpstuw0123456789BHNRC:D:F:I:L:U:V:W:k:r:"
-    _arguments -s \
-      -{l,R} \
-      '-D+:date:_cvs_D' \
-      '-k+:keyword substitution:_cvs_k' \
-      '-r+:tag:_cvs_revisions' \
-      -{h,p,0,1,2,3,4,5,6,7,8,9} \
-      '--binary' \
-      '--brief' \
-      '--changed-group-format=:format:' \
-      '-c' '-C+:lines:' '--context=-:lines:' \
-      '-e' '--ed' \
-      '-t' '--expand-tabs' \
-      '-f' '--forward-ed' \
-      '--horizon-lines=:lines:' \
-      '--ifdef=:name:' \
-      '-w' '--ignore-all-space' \
-      '-B' '--ignore-blank-lines' \
-      '-i' '--ignore-case' \
-      '-I+:regex:' '--ignore-matching-lines=:regex:' \
-      '-b' '--ignore-space-change' \
-      '--initial-tab' \
-      '*-L+:label:' '*--label=:label:' \
-      '--left-column' \
-      '--line-format=:format:' \
-      '-d' '--minimal' \
-      '-N' '--new-file' \
-      '--new-group-format=:format:' \
-      '--new-line-format=:format:' \
-      '--old-group-format=:format:' \
-      '--old-line-format=:format:' \
-      '--paginate' \
-      '-n' '--rcs' \
-      '-s' '--report-identical-files' \
-      '--show-c-function' \
-      '-F+:regex:' '--show-function-line=:regex:' \
-      '-y' '--side-by-side' \
-      '-H' '--speed-large-files' \
-      '--suppress-common-lines' \
-      '-a' '--text' \
-      '--unchanged-group-format=:format:' \
-      '--unchanged-line-format=:format:' \
-      '-u' '-U+:lines:' '--unified=-:lines:' \
-      '-W:columns:' '--width=:columns:' \
-      '*:file:_cvs_diff_arg'
-  }
-fi
+(( $+functions[_cvs_admin_t] )) ||
+_cvs_admin_t () {
+  if compset -P -; then
+    _message 'descriptive text'
+  else
+    _files "$@"
+  fi
+}
 
-if ! builtin functions _cvs_diff_arg >&-; then
-  _cvs_diff_arg () {
-    _cvs_files_modified || _cvs_files
-  }
-fi
+(( $+functions[_cvs_annotate] )) ||
+_cvs_annotate () {
+  # "+lr:D:fR"
+  _arguments -s \
+    -{l,f,R} \
+    '-r+:tag:_cvs_revisions' \
+    '-D+:date:_cvs_D' \
+    '*:file:_cvs_files'
+}
 
-if ! builtin functions _cvs_edit >&-; then
-  _cvs_edit () {
-    # "+lRa:"
-    _arguments -s \
-      -{l,R} \
-      '-a+:action:(edit unedit commit all none)'
-      '*:file:_cvs_files'
-  }
-fi
+(( $+functions[_cvs_checkout] )) ||
+_cvs_checkout () {
+  # "+ANnk:d:flRpQqcsr:D:j:P"
+  _arguments -s \
+    -{A,N,n,f,l,R,q,c,s,P} \
+    '-k+:keyword substitution:_cvs_k' \
+    '-d+:directory:_files -/' \
+    '-r+:tag:_cvs_revisions' \
+    '-D+:date:_cvs_D' \
+    '-j+:tag:_cvs_revisions' \
+    '*:module:_cvs_modules'
+}
 
-if ! builtin functions _cvs_editors >&-; then
-  _cvs_editors () {
-    # "+lR"
-    _arguments -s \
-      -{l,R} \
-      '*:file:_cvs_files'
-  }
-fi
-
-if ! builtin functions _cvs_export >&-; then
-  _cvs_export () {
-    # "+Nnk:d:flRQqr:D:"
-    _arguments -s \
-      -{N,n,f,l,R,Q,q} \
-      '-k+:keyword substitution:_cvs_k' \
-      '-d+:directory:_files -/' \
-      '-r+:tag:_cvs_revisions' \
-      '-D+:date:_cvs_D' \
-      '*:module:_cvs_modules'
-  }
-fi
-
-if ! builtin functions _cvs_history >&-; then
-  _cvs_history () {
-    # "+Tacelow?D:b:f:m:n:p:r:t:u:x:X:z:"
-    _arguments -s \
-      -{T,a,c,e,l,o,w,\?} \
-      '-D+:date:_cvs_D' \
-      '-b+:string:' \
-      '-f+:arg:' \
-      '-m+:module:_cvs_modules' \
-      '-n+:arg:' \
-      '*-p+:repository:' \
-      '-r+:rev:' \
-      '-t+:tag:' \
-      '-u+:user name:' \
-      '-x+:type:_cvs_history_x' \
-      '-X+:arg:' \
-      '-z+:arg:' \
-      '*:file:_cvs_files'
-  }
-fi
-
-if ! builtin functions _cvs_history_x >&-; then
-  _cvs_history_x () {
-    compset -P '*'
-
-    compadd "$@" -y '(
-    F\ --\ release
-    O\ --\ checkout
-    E\ --\ export
-    T\ --\ rtag
-    C\ --\ merge\ collision-detected
-    G\ --\ merge\ succeed
-    U\ --\ working\ file\ was\ copied
-    W\ --\ working\ file\ was\ deleted
-    A\ --\ A\ file\ was\ added
-    M\ --\ A\ file\ was\ modified
-    R\ --\ A\ file\ was\ removed
-    )' F O E T C G U W A M R
-  }
-fi
-
-if ! builtin functions _cvs_import >&-; then
-  _cvs_import () {
-    # "+Qqdb:m:I:k:W:"
-    _arguments -s \
-      -{Q,q,d} \
-      '-b+:branch:' \
-      '-m+:message:_cvs_m' \
-      '*-I+:name:_files' \
-      '-k+:keyword substitution:_cvs_k' \
-      '*-W+:spec:' \
-      ':repository:_cvs_modules' \
-      ':vendor tag:' \
-      ':release tag:'
-  }
-fi
+(( $+functions[_cvs_commit] )) ||
+_cvs_commit () {
+  # "+nlRm:fF:r:"
+  _arguments -s \
+    -{n,l,R,f} \
+    '-m+:message:_cvs_m' \
+    '-F+:log message file:_files' \
+    '-r+:tag:_cvs_revisions' \
+    '*:file:_cvs_files_modified'
+}
 
-if ! builtin functions _cvs_init >&-; then
-  _cvs_init () {
-    false
-  }
-fi
+(( $+functions[_cvs_diff] )) ||
+_cvs_diff () {
+  # "+abcdefhilnpstuw0123456789BHNRC:D:F:I:L:U:V:W:k:r:"
+  _arguments -s \
+    -{l,R} \
+    '-D+:date:_cvs_D' \
+    '-k+:keyword substitution:_cvs_k' \
+    '-r+:tag:_cvs_revisions' \
+    -{h,p,0,1,2,3,4,5,6,7,8,9} \
+    '--binary' \
+    '--brief' \
+    '--changed-group-format=:format:' \
+    '-c' '-C+:lines:' '--context=-:lines:' \
+    '-e' '--ed' \
+    '-t' '--expand-tabs' \
+    '-f' '--forward-ed' \
+    '--horizon-lines=:lines:' \
+    '--ifdef=:name:' \
+    '-w' '--ignore-all-space' \
+    '-B' '--ignore-blank-lines' \
+    '-i' '--ignore-case' \
+    '-I+:regex:' '--ignore-matching-lines=:regex:' \
+    '-b' '--ignore-space-change' \
+    '--initial-tab' \
+    '*-L+:label:' '*--label=:label:' \
+    '--left-column' \
+    '--line-format=:format:' \
+    '-d' '--minimal' \
+    '-N' '--new-file' \
+    '--new-group-format=:format:' \
+    '--new-line-format=:format:' \
+    '--old-group-format=:format:' \
+    '--old-line-format=:format:' \
+    '--paginate' \
+    '-n' '--rcs' \
+    '-s' '--report-identical-files' \
+    '--show-c-function' \
+    '-F+:regex:' '--show-function-line=:regex:' \
+    '-y' '--side-by-side' \
+    '-H' '--speed-large-files' \
+    '--suppress-common-lines' \
+    '-a' '--text' \
+    '--unchanged-group-format=:format:' \
+    '--unchanged-line-format=:format:' \
+    '-u' '-U+:lines:' '--unified=-:lines:' \
+    '-W:columns:' '--width=:columns:' \
+    '*:file:_cvs_diff_arg'
+}
 
-if ! builtin functions _cvs_login >&-; then
-  _cvs_login () {
-    false
-  }
-fi
+(( $+functions[_cvs_diff_arg] )) ||
+_cvs_diff_arg () {
+  _cvs_files_modified || _cvs_files
+}
 
-if ! builtin functions _cvs_logout >&-; then
-  _cvs_logout () {
-    false
-  }
-fi
-
-if ! builtin functions _cvs_rdiff >&-; then
-  _cvs_rdiff () {
-    # "+V:k:cuftsQqlRD:r:"
-    _arguments -s \
-      -{c,u,f,t,s,Q,q,l,R} \
-      '-V+:version:' \
-      '-k+:keyword substitution:_cvs_k' \
-      '*-D+:date:_cvs_D' \
-      '*-r+:tag:_cvs_revisions' \
-      '*:module:_cvs_modules'
-  }
-fi
-
-if ! builtin functions _cvs_release >&-; then
-  _cvs_release () {
-    # "+Qdq"
-    _arguments -s \
-      -{Q,d,q} \
-      '*:directory:_files -/'
-  }
-fi
-
-if ! builtin functions _cvs_remove >&-; then
-  _cvs_remove () {
-    # "+flR"
-    _arguments -s \
-      -{f,l,R} \
-      '*:file:_cvs_files_removed'
-  }
-fi
+(( $+functions[_cvs_edit] )) ||
+_cvs_edit () {
+  # "+lRa:"
+  _arguments -s \
+    -{l,R} \
+    '-a+:action:(edit unedit commit all none)' \
+    '*:file:_cvs_files'
+}
 
-if ! builtin functions _cvs_status >&-; then
-  _cvs_status () {
-    # "+vlR"
-    _arguments -s \
-      -{v,l,R} \
-      '*:file:_cvs_files'
-  }
-fi
-
-if ! builtin functions _cvs_tag >&-; then
-  _cvs_tag () {
-    # "+FQqlRcdr:D:bf"
-    _arguments -s \
-      -{F,Q,q,l,R,c,d,b,f} \
-      '-r+:tag:_cvs_revisions' \
-      '-D+:date:_cvs_D' \
-      '*:file:_cvs_files'
-  }
-fi
+(( $+functions[_cvs_editors] )) ||
+_cvs_editors () {
+  # "+lR"
+  _arguments -s \
+    -{l,R} \
+    '*:file:_cvs_files'
+}
+
+(( $+functions[_cvs_export] )) ||
+_cvs_export () {
+  # "+Nnk:d:flRQqr:D:"
+  _arguments -s \
+    -{N,n,f,l,R,Q,q} \
+    '-k+:keyword substitution:_cvs_k' \
+    '-d+:directory:_files -/' \
+    '-r+:tag:_cvs_revisions' \
+    '-D+:date:_cvs_D' \
+    '*:module:_cvs_modules'
+}
+
+(( $+functions[_cvs_history] )) ||
+_cvs_history () {
+  # "+Tacelow?D:b:f:m:n:p:r:t:u:x:X:z:"
+  _arguments -s \
+    -{T,a,c,e,l,o,w,\?} \
+    '-D+:date:_cvs_D' \
+    '-b+:string:' \
+    '-f+:file:_cvs_files' \
+    '-m+:module:_cvs_modules' \
+    '-n+:module:_cvs_modules' \
+    '*-p+:repository:' \
+    '-r+:rev:' \
+    '-t+:tag:' \
+    '-u+:user name:' \
+    '-x+:type:_cvs_history_x' \
+    '-X+:arg:' \
+    '-z+:timezone:' \
+    '*:file:_cvs_files'
+}
+
+(( $+functions[_cvs_history_x] )) ||
+_cvs_history_x () {
+  _values -s '' 'type' \
+    'F[release]' \
+    'O[checkout]' \
+    'E[export]' \
+    'T[rtag]' \
+    'C[merge collision-detected]' \
+    'G[merge succeed]' \
+    'U[working file was copied]' \
+    'W[working file was deleted]' \
+    'A[A file was added]' \
+    'M[A file was modified]' \
+    'R[A file was removed]'
+}
+
+(( $+functions[_cvs_import] )) ||
+_cvs_import () {
+  # "+Qqdb:m:I:k:W:"
+  _arguments -s \
+    -{Q,q,d} \
+    '-b+:branch:' \
+    '-m+:message:_cvs_m' \
+    '*-I+:name:_files' \
+    '-k+:keyword substitution:_cvs_k' \
+    '*-W+:spec:' \
+    ':repository:_cvs_modules' \
+    ':vendor tag:' \
+    ':release tag:'
+}
+
+(( $+functions[_cvs_init] )) ||
+_cvs_init () {
+  false
+}
+
+(( $+functions[_cvs_log] )) ||
+_cvs_log () {
+  # "+bd:hlNRr::s:tw::"
+  _arguments -s \
+    -{b,h,l,N,R,t} \
+    '-d+:dates:' \
+    '-r-:revisions:' \
+    '-s+:states:' \
+    '-w-:logins:' \
+    '*:file:_cvs_files'
+}
+
+(( $+functions[_cvs_login] )) ||
+_cvs_login () {
+  false
+}
+
+(( $+functions[_cvs_logout] )) ||
+_cvs_logout () {
+  false
+}
+
+(( $+functions[_cvs_rdiff] )) ||
+_cvs_rdiff () {
+  # "+V:k:cuftsQqlRD:r:"
+  _arguments -s \
+    -{c,u,f,t,s,Q,q,l,R} \
+    '-V+:version:' \
+    '-k+:keyword substitution:_cvs_k' \
+    '*-D+:date:_cvs_D' \
+    '*-r+:tag:_cvs_revisions' \
+    '*:module:_cvs_modules'
+}
+
+(( $+functions[_cvs_release] )) ||
+_cvs_release () {
+  # "+Qdq"
+  _arguments -s \
+    -{Q,d,q} \
+    '*:directory:_files -/'
+}
+
+(( $+functions[_cvs_remove] )) ||
+_cvs_remove () {
+  # "+flR"
+  _arguments -s \
+    -{f,l,R} \
+    '*:file:_cvs_files_removed'
+}
+
+(( $+functions[_cvs_rtag] )) ||
+_cvs_rtag () {
+  # "+FanfQqlRdbr:D:"
+  _arguments -s \
+    -{F,a,n,f,Q,q,l,R,d,b} \
+    '*-D+:date:_cvs_D' \
+    '*-r+:tag:_cvs_revisions' \
+    ':tag:' \
+    '*:module:_cvs_modules'
+}
+
+(( $+functions[_cvs_status] )) ||
+_cvs_status () {
+  # "+vlR"
+  _arguments -s \
+    -{v,l,R} \
+    '*:file:_cvs_files'
+}
+
+(( $+functions[_cvs_tag] )) ||
+_cvs_tag () {
+  # "+FQqlRcdr:D:bf"
+  _arguments -s \
+    -{F,Q,q,l,R,c,d,b,f} \
+    '-r+:tag:_cvs_revisions' \
+    '-D+:date:_cvs_D' \
+    ':tag:' \
+    '*:file:_cvs_files'
+}
+
+(( $+functions[_cvs_unedit] )) ||
+_cvs_unedit () {
+  # "+lR"
+  _arguments -s \
+    -{l,R} \
+    '*:file:_cvs_files'
+}
+
+(( $+functions[_cvs_update] )) ||
+_cvs_update () {
+  # "+ApCPflRQqduk:r:D:j:I:W:"
+  _arguments -s \
+    -{A,C,p,P,f,l,R,Q,q,d,u} \
+    '-k+:keyword substitution:_cvs_k' \
+    '-r+:tag:_cvs_revisions' \
+    '-D+:date:_cvs_D' \
+    '-j+:tag:_cvs_revisions' \
+    '*-I+:name:_files' \
+    '*-W+:spec:' \
+    '*:file:_cvs_files'
+}
+
+(( $+functions[_cvs_watch] )) ||
+_cvs_watch () {
+  local expl
+
+  if (( CURRENT == 2 )); then
+    _wanted values expl 'watch command' compadd on off add remove
+  else
+    case "$words[2]" in
+      on|off) # "+lR"
+	_arguments -s \
+	    -{l,R} \
+	    ':watch command:' \
+	    '*:file:_cvs_files'
+	;;
+      add|remove) # "+lRa:"
+	_arguments -s \
+	    -{l,R} \
+	    '*-a+:action:(edit unedit commit all none)' \
+	    ':watch command:' \
+	    '*:file:_cvs_files'
+	;;
+    esac
+  fi
+}
 
-if ! builtin functions _cvs_unedit >&-; then
-  _cvs_unedit () {
-    # "+lR"
-    _arguments -s \
+(( $+functions[_cvs_watchers] )) ||
+_cvs_watchers () {
+  # "+lR"
+  _arguments -s \
       -{l,R} \
       '*:file:_cvs_files'
-  }
-fi
-
-if ! builtin functions _cvs_update >&-; then
-  _cvs_update () {
-    # "+ApPflRQqduk:r:D:j:I:W:"
-    _arguments -s \
-      -{A,p,P,f,l,R,Q,q,d,u} \
-      '-k+:keyword substitution:_cvs_k' \
-      '-r+:tag:_cvs_revisions' \
-      '-D+:date:_cvs_D' \
-      '-j+:tag:_cvs_revisions' \
-      '*-I+:name:_files' \
-      '*-W+:spec:' \
-      '*:file:_cvs_files'
-  }
-fi
+}
 
-if ! builtin functions _cvs_watch >&-; then
-  _cvs_watch () {
-    if (( CURRENT == 2 )); then
-      compadd on off add remove
-    else
-      case "$words[2]" in
-	on|off) # "+lR"
-	  _arguments -s \
-	  -{l,R} \
-	  ':watch command:' \
-	  ':*:file:_cvs_files'
-	  ;;
-	add|remove) # "+lRa:"
-	  _arguments -s \
-	  -{l,R} \
-	  '*-a+:action:(edit unedit commit all none)' \
-	  ':watch command:' \
-	  ':*:file:_cvs_files'
-	  ;;
-      esac
-    fi
-  }
-fi
+(( $+functions[_cvs_loadstat] )) ||
+_cvs_loadstat () {
+  zstyle -t ":completion:${curcontext}:" disable-stat && return
+  (( $+_cvs_loadstat_tried )) && return
+  _cvs_loadstat_tried=yes
 
-if ! builtin functions _cvs_watchers >&-; then
-  _cvs_watchers () {
-    # "+lR"
-    _arguments -s \
-      -{l,R} \
-      ':*:file:_cvs_files'
-  }
-fi
+  zmodload -i zsh/stat 2>/dev/null
+}
 
-if ! builtin functions _cvs_root >&-; then
-  _cvs_root () {
-    compadd "$@" $_cvs_roots || _files "$@" -/
-  }
-fi
+(( $+functions[_cvs_root] )) ||
+_cvs_root () {
+  local cvspassfile id
 
-if ! builtin functions _cvs_tempdir >&-; then
-  _cvs_tempdir () {
-    compadd "$@" $TMPPREFIX:h $TMPDIR /tmp
-  }
-fi
+  typeset -gU _cvs_roots
 
-if ! builtin functions _cvs_user_variable >&-; then
-  _cvs_user_variable () {
-    if compset -P '*='; then
-      _default
+  if [[ -f "${cvspassfile::=${CVS_PASSFILE:-$HOME/.cvspass}}" ]]; then
+    _cvs_loadstat
+    if (( $+builtins[stat] )); then
+      id="$(LC_ALL=C builtin stat -g +mtime -F '%Y/%m/%d-%T' "$cvspassfile")"
     else
-      _message "variable=value"
+      id="$(LC_ALL=C ls -l "$cvspassfile")"
+    fi
+    if [[ "$id" != "$_cvs_pass_id" ]]; then
+      _cvs_roots=($_cvs_roots ${${(f)"$(<$cvspassfile)"}%% *})
+      _cvs_pass_id="$id"
     fi
+  fi
+
+  _tags files && {
+    compadd -M 'r:|[:@./]=* r:|=*' "$@" $_cvs_roots || _files "$@" -/
   }
-fi
+}
+
+(( $+functions[_cvs_tempdir] )) ||
+_cvs_tempdir () {
+  _tags directories && compadd "$@" $TMPPREFIX:h $TMPDIR /tmp
+}
+
+(( $+functions[_cvs_user_variable] )) ||
+_cvs_user_variable () {
+  if compset -P '*='; then
+    _default
+  else
+    _message "variable=value"
+  fi
+}
 
 # define completion functions for cvs global options.
 
-if ! builtin functions _cvs_bindir >&-; then
-  _cvs_bindir () {
-    compadd "$@" /usr/local/bin || _files "$@" -/
-  }
-fi
+(( $+functions[_cvs_bindir] )) ||
+_cvs_bindir () {
+  _tags directories && { compadd "$@" /usr/local/bin || _files "$@" -/ }
+}
 
-if ! builtin functions _cvs_editor >&-; then
-  _cvs_editor () {
-    compadd "$@" vi
-  }
-fi
+(( $+functions[_cvs_editor] )) ||
+_cvs_editor () {
+  _tags commands && compadd "$@" vi
+}
 
-if ! builtin functions _cvs_gzip_level >&-; then
-  _cvs_gzip_level () {
-    compadd "$@" 9
-  }
-fi
+(( $+functions[_cvs_gzip_level] )) ||
+_cvs_gzip_level () {
+  _tags values && compadd "$@" 9
+}
 
 # define completion functions for cvs common options and arguments.
 
-if ! builtin functions _cvs_D >&-; then
-  _cvs_D () {
-    compadd "$@" today yesterday week\ ago month\ ago
-  }
-fi
+(( $+functions[_cvs_D] )) ||
+_cvs_D () {
+  _tags values && compadd "$@" today yesterday week\ ago month\ ago
+}
 
-if ! builtin functions _cvs_k >&-; then
-  _cvs_k () {
-    compadd "$@" kv kvl k o b v
-  }
-fi
+(( $+functions[_cvs_k] )) ||
+_cvs_k () {
+  _tags values && compadd "$@" kv kvl k o b v
+}
 
-if ! builtin functions _cvs_m >&-; then
-  _cvs_m () {
-    _message "log message"
-  }
-fi
+(( $+functions[_cvs_m] )) ||
+_cvs_m () {
+  _message "log message"
+}
 
-if ! builtin functions _cvs_modules >&-; then
-  _cvs_modules () {
-    local root=$CVSROOT
-    [[ -f CVS/Root ]] && root=$(<CVS/Root)
+(( $+functions[_cvs_modules] )) ||
+_cvs_modules () {
+  local root=$CVSROOT expl
 
-    if [[ $root = :* || ! -d $root ]]; then
-      _message "module name"
-    else
-      compadd - \
-	$root/^CVSROOT(:t) \
-	${${(M)${(f)"$(<$root/CVSROOT/modules)"}:#[^#]*}%%[ 	]*}
-    fi
-  }
-fi
+  [[ -f CVS/Root ]] && root=$(<CVS/Root)
 
-if ! builtin functions _cvs_revisions >&-; then
-  _cvs_revisions () {
-    compadd - ${${${(M)${(f)"$(cvs -q status -vl .)"}:#	*}##[ 	]##}%%[ 	]*}
-  }
-fi
+  if [[ $root = :* || ! -d $root ]]; then
+    _message "module name"
+  else
+    _wanted modules expl module \
+        compadd - $root/^CVSROOT(:t) \
+            ${${(M)${(f)"$(<$root/CVSROOT/modules)"}:#[^#]*}%%[ 	]*}
+  fi
+}
+
+(( $+functions[_cvs_revisions] )) ||
+_cvs_revisions () {
+  local expl
+
+  _wanted values expl revision \
+      compadd - ${${${(M)${(f)"$(cvs -q status -vl .)"}:#	*}##[ 	]##(No Tags Exist)#}%%[ 	]*}
+}
 
 # define completion functions for files maintained by cvs.
 
-if ! builtin functions _cvs_setup_prefix >&-; then
-  _cvs_setup_prefix () {
-    if [[ -prefix */ ]]; then
-      qpref="${PREFIX%/*}/"
-      pref=$~qpref
-    else
-      qpref=
-      pref=./
-    fi
-  }
-fi
+(( $+functions[_cvs_setup_prefix] )) ||
+_cvs_setup_prefix () {
+  if [[ -prefix */ ]]; then
+    qpref="${PREFIX%/*}/"
+    pref=$~qpref
+  else
+    qpref=
+    pref=./
+  fi
+}
 
-if ! builtin functions _cvs_extract_directory_entries >&-; then
-  _cvs_extract_directory_entries () {
-    entries=($entries ${${${(M)rawentries:#D/*}#D/}%%/*})
-  }
-fi
+(( $+functions[_cvs_extract_directory_entries] )) ||
+_cvs_extract_directory_entries () {
+  entries=($entries ${${${(M)rawentries:#D/*}#D/}%%/*})
+}
 
-if ! builtin functions _cvs_extract_file_entries >&-; then
-  _cvs_extract_file_entries () {
-    entries=($entries ${${${(M)rawentries:#/*}#/}%%/*})
-  }
-fi
-
-if ! builtin functions _cvs_extract_modifiedfile_entries >&-; then
-  _cvs_extract_modifiedfile_entries () {
-    if [[ -n "$compconfig[_cvs_disable_stat]" ]] ||
-      ! { zmodload -e stat || zmodload stat }; then
-      _cvs_extract_file_entries
-      return
-    fi
+(( $+functions[_cvs_extract_file_entries] )) ||
+_cvs_extract_file_entries () {
+  entries=($entries ${${${(M)rawentries:#/*}#/}%%/*})
+}
 
-    local ents pats
-    ents=(${${${${(M)rawentries:#/*}#/}/\\/[^\\/]#\\///}%/[^/]#/[^/]#})
-    pats=(${${${(f)"$(LANG=C builtin stat -gn +mtime -F '%a %b %e %T %Y' ${pref}*(D))"}##*/}/ //})
-    eval 'ents=(${ents:#('${(j:|:)${(@)pats:q}}')})'
-    entries=($entries ${ents%%/*})
-  }
-fi
-
-if ! builtin functions _cvs_setup_allentries >&-; then
-  _cvs_setup_allentries () {
-    entries=()
-    if [[ -f ${pref}CVS/Entries ]]; then
-      local rawentries
-      rawentries=(${(f)"$(<${pref}CVS/Entries)"})
-      _cvs_extract_file_entries
-      _cvs_extract_directory_entries
-    fi
-  }
-fi
-
-if ! builtin functions _cvs_setup_direntries >&-; then
-  _cvs_setup_direntries () {
-    entries=()
-    if [[ -f ${pref}CVS/Entries ]]; then
-      local rawentries
-      rawentries=(${(f)"$(<${pref}CVS/Entries)"})
-      _cvs_extract_directory_entries
-    fi
-  }
-fi
-
-if ! builtin functions _cvs_setup_modentries >&-; then
-  _cvs_setup_modentries () {
-    entries=()
-    if [[ -f ${pref}CVS/Entries ]]; then
-      local rawentries
-      rawentries=(${(f)"$(<${pref}CVS/Entries)"})
-      _cvs_extract_modifiedfile_entries
-      _cvs_extract_directory_entries
-    fi
-  }
-fi
+(( $+functions[_cvs_extract_modifiedfile_entries] )) ||
+_cvs_extract_modifiedfile_entries () {
+  _cvs_loadstat
+  if (( ! $+builtins[stat] )); then
+    _cvs_extract_file_entries
+    return
+  fi
 
-if ! builtin functions _cvs_directories >&-; then
-  _cvs_directories () {
-    if [[ -d ${pref}CVS ]]; then
-      _cvs_setup_direntries
-      (( $#entries )) && compgen "$@" -g "${(j:|:)${(@)entries:q}}"
-    else
-      _files "$@"
-    fi
-  }
-fi
-
-if ! builtin functions _cvs_files >&-; then
-  _cvs_files () {
-    local qpref pref entries
-    _cvs_setup_prefix
-    if [[ -d ${pref}CVS ]]; then
-      _cvs_setup_allentries
-      (( $#entries )) && compgen "$@" -g "${(j:|:)${(@)entries:q}}"
-    else
-      _files "$@"
-    fi
-  }
-fi
-
-if ! builtin functions _cvs_files_modified >&-; then
-  _cvs_files_modified () {
-    local qpref pref entries
-    _cvs_setup_prefix
-    if [[ -d ${pref}CVS ]]; then
-      _cvs_setup_modentries
-      (( $#entries )) && compgen "$@" -g "${(j:|:)${(@)entries:q}}"
-    else
-      _files "$@"
-    fi
-  }
-fi
-
-if ! builtin functions _cvs_files_removed >&-; then
-  _cvs_files_removed () {
-    local qpref pref entries
-    _cvs_setup_prefix
-    if [[ -d ${pref}CVS ]]; then
-      _cvs_setup_allentries
-      setopt localoptions unset
-      local omit
-      omit=(${pref}*(D:t))
-      eval 'entries=(${entries:#('${(j:|:)${(@)omit:q}}')})'
-      compadd "$@" -P "$qpref" - ${entries:q} ||
-      _cvs_directories "$@"
-    else
-      _files "$@"
-    fi
-  }
-fi
-
-if ! builtin functions _cvs_files_unmaintained >&-; then
-  _cvs_files_unmaintained () {
-    local qpref pref entries
-    _cvs_setup_prefix
-    if [[ -d ${pref}CVS ]]; then
-      _cvs_setup_allentries
-      setopt localoptions unset
-      local omit
-      omit=($_cvs_ignore_default ${entries:q} ${=cvsignore})
-      [[ -r ~/.cvsignore ]] && omit=($omit $(<~/.cvsignore))
-      [[ -r ${pref}.cvsignore ]] && omit=($omit $(<${pref}.cvsignore))
-      compgen "$@" -g '*~(*/|)('${(j:|:)omit}')(D)' ||
-      compgen "$@" -g '*~(*/|)('${(j:|:)${(@)entries:q}}')(D)' ||
-      _cvs_directories "$@"
-    else
-      _files "$@"
-    fi
-  }
-fi
+  local ents pats
+  ents=(${${${${(M)rawentries:#/*}#/}/\\/[^\\/]#\\///}%/[^/]#/[^/]#})
+  pats=(${${${(f)"$(LC_ALL=C builtin stat -gn +mtime -F '%a %b %e %T %Y' ${pref}*(D))"}##*/}/ //})
+  eval 'ents=(${ents:#('${(j:|:)${(@)pats:q}}')})'
+  entries=($entries ${ents%%/*})
+}
 
-# define configuration variables.
+(( $+functions[_cvs_setup_allentries] )) ||
+_cvs_setup_allentries () {
+  entries=()
+  if [[ -f ${pref}CVS/Entries ]]; then
+    local rawentries
+    rawentries=(${(f)"$(<${pref}CVS/Entries)"})
+    _cvs_extract_file_entries
+    _cvs_extract_directory_entries
+  fi
+}
+
+(( $+functions[_cvs_setup_direntries] )) ||
+_cvs_setup_direntries () {
+  entries=()
+  if [[ -f ${pref}CVS/Entries ]]; then
+    local rawentries
+    rawentries=(${(f)"$(<${pref}CVS/Entries)"})
+    _cvs_extract_directory_entries
+  fi
+}
+
+(( $+functions[_cvs_setup_modentries] )) ||
+_cvs_setup_modentries () {
+  entries=()
+  if [[ -f ${pref}CVS/Entries ]]; then
+    local rawentries
+    rawentries=(${(f)"$(<${pref}CVS/Entries)"})
+    _cvs_extract_modifiedfile_entries
+    _cvs_extract_directory_entries
+  fi
+}
 
-if (( ! $+_cvs_roots )); then
-  if [[ -f ~/.cvspass ]]; then
-    _cvs_roots=(${${(f)"$(<~/.cvspass)"}%% *})
+(( $+functions[_cvs_directories] )) ||
+_cvs_directories () {
+  if [[ -d ${pref}CVS ]]; then
+    _cvs_setup_direntries
+    (( $#entries )) && _files "$@" -g "${(j:|:)${(@)entries:q}}"
   else
-    _cvs_roots=()
+    _files "$@"
   fi
-fi
+}
+
+(( $+functions[_cvs_files] )) ||
+_cvs_files () {
+  local qpref pref entries
+  _cvs_setup_prefix
+  if [[ -d ${pref}CVS ]]; then
+    _cvs_setup_allentries
+    (( $#entries )) && _files "$@" -g "${(j:|:)${(@)entries:q}}"
+  else
+    _files "$@"
+  fi
+}
+
+(( $+functions[_cvs_files_modified] )) ||
+_cvs_files_modified () {
+  local qpref pref entries
+  _cvs_setup_prefix
+  if [[ -d ${pref}CVS ]]; then
+    _cvs_setup_modentries
+    (( $#entries )) && _files "$@" -g "${(j:|:)${(@)entries:q}}"
+  else
+    _files "$@"
+  fi
+}
+
+(( $+functions[_cvs_files_removed] )) ||
+_cvs_files_removed () {
+  local qpref pref entries
+  _cvs_setup_prefix
+  if [[ -d ${pref}CVS ]]; then
+    _cvs_setup_allentries
+    setopt localoptions unset
+    local omit
+    omit=(${pref}*(D:t))
+    eval 'entries=(${entries:#('${(j:|:)${(@)omit:q}}')})'
+    _tags directories && compadd "$@" -P "$qpref" - ${entries:q} ||
+        _cvs_directories "$@"
+  else
+    _files "$@"
+  fi
+}
+
+(( $+functions[_cvs_files_unmaintained] )) ||
+_cvs_files_unmaintained () {
+  local qpref pref entries
+  _cvs_setup_prefix
+  if [[ -d ${pref}CVS ]]; then
+    _cvs_setup_allentries
+    setopt localoptions unset
+    local omit
+    omit=($_cvs_ignore_default ${entries:q} ${=cvsignore})
+    [[ -r ~/.cvsignore ]] && omit=($omit $(<~/.cvsignore))
+    [[ -r ${pref}.cvsignore ]] && omit=($omit $(<${pref}.cvsignore))
+    _path_files "$@" -g '*~(*/|)('${(j:|:)omit}')(D)' ||
+        _path_files "$@" -g '*~(*/|)('${(j:|:)${(@)entries:q}}')(D)' ||
+        _cvs_directories "$@"
+  else
+    _files "$@"
+  fi
+}
+
+# define configuration variables.
 
-if (( ! $+_cvs_ignore_default )); then
-  _cvs_ignore_default=(
-    RCS SCCS CVS CVS.adm RCSLOG 'cvslog.*' tags TAGS .make.state .nse_depinfo
-    '*\~' '\#*' '.\#*' ',*' '_$*' '*$' '*.old' '*.bak' '*.BAK' '*.orig' '*.rej'
-    '.del-*' '*.a' '*.olb' '*.o' '*.obj' '*.so' '*.exe' '*.Z' '*.elc' '*.ln'
-    core
-  )
-fi
+(( $+_cvs_ignore_default )) ||
+_cvs_ignore_default=(
+  RCS SCCS CVS CVS.adm RCSLOG 'cvslog.*' tags TAGS .make.state .nse_depinfo
+  '*\~' '\#*' '.\#*' ',*' '_$*' '*$' '*.old' '*.bak' '*.BAK' '*.orig' '*.rej'
+  '.del-*' '*.a' '*.olb' '*.o' '*.obj' '*.so' '*.exe' '*.Z' '*.elc' '*.ln'
+  core
+)
 
 # call real _cvs.
 
-_cvs "$@"
+[[ -o kshautoload ]] || _cvs "$@"
diff --git a/Completion/User/_gdb b/Completion/User/_gdb
index a29eaf8b2..0445e18e9 100644
--- a/Completion/User/_gdb
+++ b/Completion/User/_gdb
@@ -17,7 +17,8 @@ elif compset -P '-(exec|se)='; then
 elif compset -P '-(symbols|core|command)='; then
   _files
 elif [[ "$PREFIX" = -* ]]; then
-  if _wanted options; then
+  _tags options
+  while _tags; do
     while _next_label options expl option; do
       compadd "$expl[@]" -QS '' - -symbols\= -exec\= -se\= -core\= -command\= \
                                   -directory\= -cd\= -tty\= && ret=0
@@ -25,7 +26,7 @@ elif [[ "$PREFIX" = -* ]]; then
 	    		          -batch -fullname -f -b && ret=0
     done
     (( ret )) || return 0
-  fi
+  done
 else
   prev="$words[CURRENT-1]"
 
diff --git a/Completion/User/_gprof b/Completion/User/_gprof
index 0a1d621be..659e921e8 100644
--- a/Completion/User/_gprof
+++ b/Completion/User/_gprof
@@ -1,12 +1,58 @@
 #compdef gprof
 
-_arguments -s -{a,b,c,D,h,i,l,L,s,T,v,w,x,y,z} \
-           -{A,C,e,E,f,F,J,n,N,O,p,P,q,Q,Z}:'function name: _exec_funcs' \
+local curcontext="$curcontext" state line ret=1
+typeset -A opt_args
+
+_arguments -C -s -{a,b,c,D,h,i,l,L,s,T,v,w,x,y,z} \
+           -{A,C,e,E,f,F,J,n,N,O,p,P,q,Q,Z}:'function name:->funcs' \
 	   '-I:directory:_dir_list' \
-	   '-d-:debug level:' '-k:function names: _exec_funcs -p' \
+	   '-d-:debug level:' '-k:function names:->pair' \
 	   '-m:minimum execution count:' \
-	   ':executable:_files -g *(*)' \
-	   ':profile file:_files -g gmon.*' \
+	   ':executable:_files -g \*\(\*\)' \
+	   ':profile file:_files -g gmon.\*' \
 	   -- -s '(#--[no-] --)' \
-           '*=name*:function name: _exec_funcs' \
-	   '*=dirs*:directory:_dir_list'
+           '*=name*:function name:->funcs' \
+	   '*=dirs*:directory:_dir_list' && ret=0
+
+if [[ -n "$state" ]]; then
+  local cmd pair expl
+
+  _tags functions || return 1
+
+  [[ "$state" = pair ]] && pair=yes
+
+  if [[ $#line -gt 1 ]]; then
+    cmd="$line[2]"
+  else
+    return 1
+  fi
+
+  if [[ -n "$cmd" ]]; then
+    if [[ "$cmd" = /* ]]; then
+      tmp="$cmd"
+    else
+      tmp="$PWD/$cmd"
+    fi
+
+    if [[ "$tmp" != "$_gprof_command" ]]; then
+      _gprof_command="$tmp"
+      _gprof_funcs=( "${(@)${(@M)${(@f)$(nm $cmd)}:#[^ ]# [tT] ([^_]|_[^_])*}##* }" )
+    fi
+  
+    if [[ -n "$pair" ]]; then
+      if compset -P '*/'; then
+        expl='call arc to function'
+      else
+        expl='call arc from function'
+      fi
+    else
+      expl=function
+    fi
+    _wanted functions expl "$expl" \
+        compadd "$expl[@]" -M 'r:|_=* r:|=*' - "$_gprof_funcs[@]" && ret=0
+  else
+    return 1
+  fi
+fi
+
+return ret
diff --git a/Completion/User/_groups b/Completion/User/_groups
index 27444d26d..7ee9969cd 100644
--- a/Completion/User/_groups
+++ b/Completion/User/_groups
@@ -2,7 +2,7 @@
 
 local expl groups tmp
 
-_wanted groups || return 1
+_tags groups || return 1
 
 if ! zstyle -a ":completion:${curcontext}:" groups groups; then
   (( $+_cache_groups )) ||
@@ -16,4 +16,4 @@ if ! zstyle -a ":completion:${curcontext}:" groups groups; then
   groups=( "$_cache_groups[@]" )
 fi
 
-_all_labels groups expl group compadd "$@" - "$groups[@]"
+_wanted groups expl group compadd "$@" - "$groups[@]"
diff --git a/Completion/User/_lp b/Completion/User/_lp
index e996507ce..60cf8cfd0 100644
--- a/Completion/User/_lp
+++ b/Completion/User/_lp
@@ -36,28 +36,27 @@ if (( ! $+_lp_cache )); then
 fi
 
 if compset -P -P || [[ "$words[CURRENT-1]" = -P ]]; then
-  if _wanted printers; then
-    if zstyle -T ":completion:${curcontext}:printers" verbose; then
-      zformat -a list ' -- ' "$_lp_cache[@]"
-      disp=(-ld list)
-    else
-      disp=()
-    fi
-    _all_labels printers expl printer \
-        compadd "$disp[@]" - "${(@)_lp_cache%%:*}" && return 0
+  if zstyle -T ":completion:${curcontext}:printers" verbose; then
+    zformat -a list ' -- ' "$_lp_cache[@]"
+    disp=(-ld list)
+  else
+    disp=()
+  fi
+  _wanted printers expl printer \
+      compadd "$disp[@]" - "${(@)_lp_cache%%:*}" && return 0
 
-    (( $+_lp_alias_cache )) || return 1
+  (( $+_lp_alias_cache )) || return 1
 
-    if zstyle -T ":completion:${curcontext}:printers" verbose; then
-      zformat -a list ' -- ' "$_lp_alias_cache[@]"
-      disp=(-ld list)
-    else
-      disp=()
-    fi
-    compadd "$expl[@]" "$disp[@]" - "${(@)_lp_alias_cache%%:*}"
+  if zstyle -T ":completion:${curcontext}:printers" verbose; then
+    zformat -a list ' -- ' "$_lp_alias_cache[@]"
+    disp=(-ld list)
   else
-    return 1
+    disp=()
   fi
+  _wanted printers expl printer \
+      compadd "$disp[@]" - "${(@)_lp_alias_cache%%:*}" && return 0
+
+  return 1
 else
   if [[ "${words[1]:t}" = (lpq|lprm) ]]; then
     if [[ "$words" = *-P* ]]; then
diff --git a/Completion/User/_mh b/Completion/User/_mh
index 724b45e5a..29d6bc2a1 100644
--- a/Completion/User/_mh
+++ b/Completion/User/_mh
@@ -17,16 +17,13 @@ if compset -P 1 -; then
   # get list of options, which MH commands can generate themselves
   # awk is just too icky to use for this, sorry.  send me one if
   # you come up with it.
-  if _wanted options; then
-    _all_labels options expl option \
-        compadd - $($words[1] -help | perl -ne 'if (/^\s*-\(?(\S+)/) {
+  _wanted options expl option \
+      compadd - $($words[1] -help | perl -ne 'if (/^\s*-\(?(\S+)/) {
             $n = $1;
             $n =~ s/\)//g;
             print $n =~ s/^\[([a-z]+)\]// ? "$n\n$1$n\n" : "$n\n";
           }')
-    return
-  fi
-  return 1
+  return
 elif compset -P 1 '[+@]' || [[ "$prev" = -draftfolder ]]; then
   # Complete folder names.
   local mhpath
@@ -72,13 +69,15 @@ else
     # leaving foldnam empty works here
   fi
 
-  if _wanted sequences; then
+  _tags sequences
+  while _tags; do
     while _next_label sequences expl sequence; do
       compadd "$expl[@]" $(mark $foldnam 2>/dev/null | awk -F: '{ print $1 }') &&
         ret=0
       compadd "$expl[@]" reply next cur prev first last all unseen && ret=0
       _files "$expl[@]" -W folddir -g '<->' && ret=0
     done
-  fi
+    (( ret )) || return 0
+  done
   return ret
 fi
diff --git a/Completion/User/_mount b/Completion/User/_mount
index a148fff27..418b7974f 100644
--- a/Completion/User/_mount
+++ b/Completion/User/_mount
@@ -543,7 +543,7 @@ fstype)
       compadd "$expl[@]" -qS, -M 'L:|no=' - "$fss[@]" && ret=0
   ;;
 fsopt)
-  _wanted options || return 1
+  _tags options || return 1
 
   eval 'tmp=(' '"$_fs_'${(s:,:)^${opt_args[$typeops]:-${deffs}}}'[@]"' ')'
   tmp=( "$_fs_any[@]" "${(@)tmp:#}" )
diff --git a/Completion/User/_netscape b/Completion/User/_netscape
index 82fa4509a..ed2bccc75 100644
--- a/Completion/User/_netscape
+++ b/Completion/User/_netscape
@@ -56,16 +56,14 @@ if [[ "$state" = "remote" ]]; then
       fi
     ;;
     *)
-      if _wanted commands; then
-        if [[ -z "$QIPREFIX" ]]; then
-	  _all_labels commands expl 'remote commands' \
-  	      compadd  -s'(' -S '' -M 'm:{a-zA-Z}={A-Za-z}' - \
-                      $remote_commands && ret=0
-        else
-	  _all_labels commands expl 'remote commands' \
-              compadd -qS '(' -M 'm:{a-zA-Z}={A-Za-z}' - \
-                      $remote_commands && ret=0
-	fi
+      if [[ -z "$QIPREFIX" ]]; then
+	_wanted commands expl 'remote commands' \
+  	    compadd -s'(' -S '' -M 'm:{a-zA-Z}={A-Za-z}' - \
+                    $remote_commands && ret=0
+      else
+	_wanted commands expl 'remote commands' \
+            compadd -qS '(' -M 'm:{a-zA-Z}={A-Za-z}' - \
+                    $remote_commands && ret=0
       fi
     ;;
   esac
@@ -78,12 +76,14 @@ if [[ "$state" = "urls" ]]; then
         compadd authors blank cache document fonts global hype image-cache \
             license logo memory-cache mozilla plugins && ret=0
   else
-    if _wanted prefixes; then
+    _tags prefixes
+    while _tags; do
       while _next_label prefixes expl 'URL prefix'; do
         compadd "$expl[@]" -S '' about: mocha: javascript: && ret=0
         _urls "$@" && ret=0
       done
-    fi
+      (( ret )) || return 0
+    done
   fi
 fi
 
diff --git a/Completion/User/_nslookup b/Completion/User/_nslookup
index 7d2a12142..44ab4cacc 100644
--- a/Completion/User/_nslookup
+++ b/Completion/User/_nslookup
@@ -19,9 +19,7 @@
 # other characters than lower case letters, we try to call the function
 # `_nslookup_host'.
 
-setopt localoptions extendedglob
-
-local state expl ret=1 setopts
+local context curstate="$curcontext" expl ret=1 setopts
 
 setopts=(
   'all[print current values]' \
@@ -40,7 +38,7 @@ setopts=(
   '(noignoretc)ignoretc[ignore packet truncation errors]' \
   '(ignoretc)noignoretc[don'"'"'t ignore packet truncation errors]' \
   'class[change query class]:query class:((in\:Internet\ class chaos\:CHAOS\ class hesiod\:MIT\ Athena\ Hesiod\ class any\:wildcard\ \(any\ of\ the\ above\)))'
-  'domain[change default domain]:default domain:_hosts'
+  "domain[change default domain]:default domain:_domains"
   'srchlist[change default domain and search list]: :->srchlist'
   'port[change name server port]:name server port:'
   {query,}type'[change type of information query]:query information type:((a\:internet\ address cname\:canonical\ name\ for\ alias hinfo\:CPU\ and\ operating\ system\ type minfo\:mailbox\ or\ mail\ list\ information mx\:mail\ exchanger ns\:name\ server\ for\ zone ptr\:host\ name\ or\ other\ information soa\:domain\'"'"'s\ \`start-of-authority\'"'"'\ information txt\:text\ information uinfo\:user\ information wks\:supported\ well-known\ services))'
@@ -52,23 +50,25 @@ setopts=(
 if [[ -n "$compcontext" ]]; then
   if [[ CURRENT -eq 1 ]]; then
 
-    funcall ret _nslookup_command && return ret
+    _funcall ret _nslookup_command && return ret
 
-    _description expl 'command'
-    compadd "$expl[@]" - server lserver root finger ls view help set && ret=0
-    _hosts && ret=0
+    _alternative \
+        'commands:command:(server lserver root finger ls view help set exit)' \
+	'hosts:: _hosts' && ret=0
     return ret
   elif [[ "$compstate[context]" = redirect ]]; then
 
-    funcall ret _nslookup_redirect && return ret
+    _funcall ret _nslookup_redirect && return ret
+
+    _tags -C redirection files || return 1
 
     if [[ "$words[1]" != (finger|ls) ]]; then
       _message "redirection not allowed for command \`$words[1]'"
       return 1
     elif [[ "$compstate[redirect]" = '>' ]]; then
-      _description expl 'write to file'
+      _description files expl 'write to file'
     elif [[ "$compstate[redirect]" = '>>' ]]; then
-      _description expl 'append to file'
+      _description files expl 'append to file'
     else
       _message "unknown redirection operator \`$compstate[redirect]'"
       return 1
@@ -79,15 +79,14 @@ if [[ -n "$compcontext" ]]; then
   fi
 
   if [[ "$words[1]" = [a-z]## ]]; then
-    funcall ret _nslookup_$words[1] && return ret
+    _funcall ret _nslookup_$words[1] && return ret
   else
-    funcall ret _nslookup_host && return ret
+    _funcall ret _nslookup_host && return ret
   fi
 
   case "$words[1]" in
   (|l)server)
-    _description expl 'new default server'
-    _hosts "$expl[@]"
+    _wanted hosts expl 'new default server' _hosts
     return
     ;;
   root|exit|help|\?)
@@ -104,24 +103,23 @@ if [[ -n "$compcontext" ]]; then
      '-d[all records]' \
      '-h[CPU and operating system information]' \
      '-s[well-known services]' \
-     ':domain:_hosts'
+     ":domain:_domains"
     return
     ;;
   view)
-    _description expl 'view file'
+    _description files expl 'view file'
     _files "$expl[@]"
     return
     ;;
   set)
-    typeset -A values
+    typeset -A val_args
 
     _values 'state information' "$setopts[@]" && ret=0
 
     [[ -z "$state" ]] && return ret
     ;;
   *)
-    _description expl 'server'
-    _hosts "$expl[@]"
+    _wanted hosts expl 'server' _hosts
     return
   esac
 fi
@@ -130,9 +128,9 @@ fi
 
 if [[ -z "$state" ]]; then
   local line
-  typeset -A options
+  typeset -A opt_args
 
-  _arguments \
+  _arguments -C \
     "-${(@)^${(@M)setopts:#*\]:*}/\[/=[}" \
     "-${(@)^setopts:#(\(|*\]:)*}" \
     "${(@)^${(@)${(@M)setopts:#\(*}/\)/)-}/\(/(-}" \
@@ -143,15 +141,17 @@ fi
 # This is completion after `srchlist' for both types.
 
 if [[ -n "$state" ]]; then
+  _tags domains || return 1
+
   if compset -P '*/'; then
-    _description expl 'search list entry'
+    _description domains expl 'search list entry'
   else
-    _description expl 'default domain name and first search list entry'
+    _description domains expl 'default domain name and first search list entry'
   fi
   if [[ -n "$_vals_cache_multi" ]]; then
-    _hosts "$expl[@]" -qS/ -r "/\\- \\t\\n$_vals_cache_multi"
+    _domains "$expl[@]" -qS/ -r "/\\- \\t\\n$_vals_cache_multi"
   else
-    _hosts "$expl[@]" -qS/
+    _domains "$expl[@]" -qS/
   fi
   return
 fi
diff --git a/Completion/User/_rlogin b/Completion/User/_rlogin
index bf8ff751d..2509bd79c 100644
--- a/Completion/User/_rlogin
+++ b/Completion/User/_rlogin
@@ -28,7 +28,7 @@ _rlogin () {
     return ret
     ;;
   rcp)
-    local curcontext="$curcontext" state line ret=1
+    local curcontext="$curcontext" state line ret=1 expl
     typeset -A opt_args
 
     _arguments -C -s \
@@ -40,7 +40,7 @@ _rlogin () {
       if compset -P '*:'; then
 	_files && ret=0
       elif compset -P '*@'; then
-        _wanted hosts && _rlogin_hosts -S: -q && ret=0
+        _wanted hosts expl host _rlogin_hosts -S: -q && ret=0
       else
         _alternative \
 	    'files:: _files' \
@@ -54,11 +54,11 @@ _rlogin () {
 }
 
 _rlogin_users () {
-  _wanted users && _combination -s '[:@]' my-accounts users-hosts users "$@"
+  _tags users && _combination -s '[:@]' my-accounts users-hosts users "$@"
 }
 
 _rlogin_hosts () {
-  _wanted hosts &&
+  _tags hosts &&
       if [[ "$IPREFIX" == *@ ]]; then
         _combination -s '[:@]' my-accounts users-hosts "users=${IPREFIX/@}" hosts "$@"
       else
diff --git a/Completion/User/_socket b/Completion/User/_socket
index 353a66fd5..af9c8ab0a 100644
--- a/Completion/User/_socket
+++ b/Completion/User/_socket
@@ -1,34 +1,55 @@
 #compdef socket
 
-local state line expl
-typeset -A options
+# Style used:
+#
+#  hosts-ports
+#    The style that contains pairs `host:port'.
 
-_arguments -s \
-  -{b,c,f,q,r,v,w} \
-  -{s,l} \
-  '-p:command:->command' \
+local curcontext="$curcontext" state line expl
+typeset -A opt_args
+
+[[ $CURRENT -eq 2 ]] &&
+    { ! zstyle -T ":completion:${curcontext}:options" prefix-needed ||
+      [[ "$PREFIX" = -* ]] } &&
+    _wanted options expl option \
+        compadd -M 'r:|[_-]=* r:|=*' "$expl[@]" - -version
+
+_arguments -C -s \
+  '-b[background]' \
+  '-c[crlf]' \
+  '-f[fork]' \
+  '-q[quit]' \
+  '-r[read only]' \
+  '-v[verbose]' \
+  '-w[write only]' \
+  '-s[server]' \
+  '-l[loop]' \
+  '-p[program]:command:->command' \
   ':arg1:->arg1' \
   ':arg2:->arg2'
 
 case "$state" in
 command)
   compset -q
-  _normal
+  if [[ $CURRENT -eq 1 ]]; then
+    _command_names -e "$@"
+  else
+    _normal
+  fi
   ;;
 
 arg1)
-  if (( $+options[-s] )); then
-    _message 'port'
+  if (( $+opt_args[-s] )); then
+    _ports
   else
-    _description expl 'host'
-    _hosts "$expl[@]"
+    _wanted hosts expl 'host' _combination '' hosts-ports hosts -
   fi
   ;;
 
 arg2)
-  if (( ! $+options[-s] )); then
-    _description expl 'port'
-    _hostports $line[2] "$expl[@]"
+  if (( ! $+opt_args[-s] )); then
+    _wanted ports expl 'port to connect' \
+        _combination '' hosts-ports hosts="${line[1]:q}" ports -
   fi
   ;;
 esac
diff --git a/Completion/User/_tiff b/Completion/User/_tiff
index 9616009c3..608325fdf 100644
--- a/Completion/User/_tiff
+++ b/Completion/User/_tiff
@@ -195,12 +195,14 @@ if [[ -n "$state" ]]; then
       ;;
     esac
   else
-    if _wanted values; then
+    _tags values
+    while _tags; do
       while _next_label values expl 'compression scheme'; do
         compadd "$expl[@]" - none g4 packbits && ret=0
         compadd "$expl[@]" -qS: - lzw zip jpeg g3 && ret=0
       done
-    fi
+      (( ret )) || return 0
+    done
   fi
 fi
 
diff --git a/Completion/User/_urls b/Completion/User/_urls
index 3989f2219..4234aa274 100644
--- a/Completion/User/_urls
+++ b/Completion/User/_urls
@@ -49,18 +49,22 @@ local localhttp_userdir="$localhttp[3]"
 
 if [[ "$1" = -f ]]; then
   shift
-  _wanted -C -f files && _files "$@" && return
+  _wanted -C -f files _files "$@" && return 0
 fi
 
 ipre="$IPREFIX"
 
-if ! compset -P '(#b)([-+.a-z0-9]#):' && _wanted -C argument prefixes; then
-  while _next_label prefixes expl 'URL prefix' "$@"; do
-    [[ -d $urls_path/bookmark ]] &&
-      compadd "$expl[@]" -S '' bookmark: && ret=0
-    compadd "$expl[@]" -S '' file: ftp:// gopher:// http:// && ret=0
+if ! compset -P '(#b)([-+.a-z0-9]#):'; then
+  _tags -C argument prefixes
+  while _tags; do
+    while _next_label prefixes expl 'URL prefix' "$@"; do
+      [[ -d $urls_path/bookmark ]] &&
+        compadd "$expl[@]" -S '' bookmark: && ret=0
+      compadd "$expl[@]" -S '' file: ftp:// gopher:// http:// && ret=0
+    done
+    (( ret )) || return 0
   done
-  return ret
+  return 1
 fi
 scheme="$match[1]"
 
@@ -73,17 +77,19 @@ case "$scheme" in
   ;;
   file)
     if ! compset -P //; then
-      _wanted -C file files || return 1
-
-      while _next_label files expl 'local file' "$@"; do
-        if [[ -prefix / ]]; then
-	  _path_files "$expl[@]" -S '' -g '*(^/)' && ret=0
-	  _path_files "$expl[@]" -S/ -r '/' -/ && ret=0
-        elif [[ -z "$PREFIX" ]]; then
-	  compadd "$expl[@]" -S '/' -r '/' - "${PWD%/}" && ret=0
-        fi
+      _tags -C file files
+      while _tags; do
+        while _next_label files expl 'local file' "$@"; do
+          if [[ -prefix / ]]; then
+	    _path_files "$expl[@]" -S '' -g '*(^/)' && ret=0
+	    _path_files "$expl[@]" -S/ -r '/' -/ && ret=0
+          elif [[ -z "$PREFIX" ]]; then
+	    compadd "$expl[@]" -S '/' -r '/' - "${PWD%/}" && ret=0
+          fi
+        done
+	(( ret )) || return 0
       done
-      return ret
+      return 1
     fi
   ;;
   bookmark)
@@ -93,34 +99,40 @@ case "$scheme" in
           compadd "$@" -U - \
               "$ipre$(<"$urls_path/$scheme/${(Q)PREFIX}${(Q)SUFFIX}")" && ret=0
     else
-      if _wanted -C bookmark files; then
+      _tags -C bookmark files
+      while _tags; do
         while _next_label files expl 'bookmark'; do
           _path_files -W "$urls_path/$scheme" "$expl[@]" -S '' -g '*(^/)' && 
               ret=0
           _path_files -W "$urls_path/$scheme" -S/ -r '/' -/ && ret=0
         done
-      fi
+	(( ret )) || return 0
+      done
     fi
     return ret
   ;;
 esac
 
 # Complete hosts
-if ! compset -P '(#b)([^/]#)/' && _wanted hosts; then
+if ! compset -P '(#b)([^/]#)/'; then
   uhosts=($urls_path/$scheme/$PREFIX*$SUFFIX(/:t))
 
-  while _next_label hosts expl host "$@"; do
-    (( $#uhosts )) || _hosts -S/ && ret=0
-    [[ "$scheme" = http ]] && uhosts=($uhosts $localhttp_servername)
-    compadd "$expl[@]" -S/ - $uhosts && ret=0
+  _tags hosts
+  while _tags; do
+    while _next_label hosts expl host "$@"; do
+      (( $#uhosts )) || _hosts -S/ && ret=0
+      [[ "$scheme" = http ]] && uhosts=($uhosts $localhttp_servername)
+      compadd "$expl[@]" -S/ - $uhosts && ret=0
+    done
+    (( ret )) || return 0
   done
-  return ret
+  return 1
 fi
 host="$match[1]"
 
 # Complete part after hostname
 
-_wanted -C local files || return 1
+_tags -C local files || return 1
 
 if [[ "$localhttp_servername" = "$host" ]]; then
   if compset -P \~; then
@@ -129,20 +141,29 @@ if [[ "$localhttp_servername" = "$host" ]]; then
       return
     fi
     user="$match[1]"
-    while _next_label files expl 'local file'; do
-      _path_files "$expl[@]" -W ~$user/$localhttp_userdir -g '*(^/)' && ret=0
-      _path_files "$expl[@]" -W ~$user/$localhttp_userdir -S/ -r '/' -/ && ret=0
+    while _tags; do
+      while _next_label files expl 'local file'; do
+        _path_files "$expl[@]" -W ~$user/$localhttp_userdir -g '*(^/)' && ret=0
+        _path_files "$expl[@]" -W ~$user/$localhttp_userdir -S/ -r '/' -/ && ret=0
+      done
+      (( ret )) || return 0
     done
   else
-    while _next_label files expl 'local file'; do
-      _path_files "$expl[@]" -W $localhttp_documentroot -g '*(^/)' && ret=0
-      _path_files "$expl[@]" -W $localhttp_documentroot -S/ -r '/' -/ && ret=0
+    while _tags; do
+      while _next_label files expl 'local file'; do
+        _path_files "$expl[@]" -W $localhttp_documentroot -g '*(^/)' && ret=0
+        _path_files "$expl[@]" -W $localhttp_documentroot -S/ -r '/' -/ && ret=0
+      done
+      (( ret )) || return 0
     done
   fi
 else
-  while _next_label files expl 'local file'; do
-    _path_files "$expl[@]" -W $urls_path/$scheme/$host -g '*(^/)' && ret=0
-    _path_files "$expl[@]" -W $urls_path/$scheme/$host -S/ -r '/' -/ && ret=0
+  while _tags; do
+    while _next_label files expl 'local file'; do
+      _path_files "$expl[@]" -W $urls_path/$scheme/$host -g '*(^/)' && ret=0
+      _path_files "$expl[@]" -W $urls_path/$scheme/$host -S/ -r '/' -/ && ret=0
+    done
+    (( ret )) || return 0
   done
 fi
 return $ret
diff --git a/Completion/User/_users b/Completion/User/_users
index d04731af9..dce0fd584 100644
--- a/Completion/User/_users
+++ b/Completion/User/_users
@@ -2,9 +2,7 @@
 
 local expl users
 
-_wanted users || return 1
-
 zstyle -a ":completion:${curcontext}:" users users &&
-    _all_labels users expl user compadd "$@" - "$users[@]" && return 0
+    _wanted users expl user compadd "$@" - "$users[@]" && return 0
 
-_all_labels users expl user compadd "$@" - "${(@k)userdirs}"
+_wanted users expl user compadd "$@" - "${(@k)userdirs}"
diff --git a/Completion/User/_users_on b/Completion/User/_users_on
index b19cff6e7..b5c05e12b 100644
--- a/Completion/User/_users_on
+++ b/Completion/User/_users_on
@@ -2,10 +2,8 @@
 
 local expl
 
-_wanted users || return 1
-
-if which users >/dev/null; then
-  _all_labels users expl 'users logged on' \
+if (( $+commands[users] )); then
+  _wanted users expl 'users logged on' \
       compadd "$@" - $(_call users users) && return 0
 else
   # Other methods of finding out users logged on should be added here
diff --git a/Completion/User/_whois b/Completion/User/_whois
index 827ebe627..4b6d73b86 100644
--- a/Completion/User/_whois
+++ b/Completion/User/_whois
@@ -1,12 +1,14 @@
-#compdef whois
+#compdef whois fwhois
 
 _whois () {
-  setopt localoptions extendedglob
   _whois_setup
-  $_whois_comp
+  case "$0" in
+  fwhois) _whois_fwhois;;
+  *) $_whois_comp;;
+  esac
 }
 
-builtin functions _whois_setup >&- ||
+(( $+functions[_whois_setup] )) ||
 _whois_setup () {
   (( $+_whois_defaultserver )) ||
     _whois_defaultserver='whois.internic.net'
@@ -65,6 +67,7 @@ _whois_setup () {
   (( $+_whois_arguments )) || {
     local help="$(whois </dev/null 2>&1)"
     local tmp opt opts
+    local hostopt=-h+
 
     if [[ $help = *"user[@<whois.server>]"* ]]; then
       _whois_comp=_whois_fwhois
@@ -72,6 +75,7 @@ _whois_setup () {
       _whois_comp=_whois_multi
     else
       _whois_comp=_whois_single
+      hostopt=-h
     fi
 
     _whois_arguments=()
@@ -96,25 +100,29 @@ _whois_setup () {
     for opt in $tmp; do
       opts=(-${^tmp:#$opt})
       if (( $#opts )); then opts="($opts)"; else opts=; fi
-      _whois_arguments=("$_whois_arguments[@]"
-	"${opts}-${opt}[${${${(@M)_whois_servers:#*:$opt}%:?}:-specify host}]${(M)${(M)opt:#h}/h/:host:_whois_hosts}"
-      )
+      if [[ $opt = h ]]; then
+	_whois_arguments=("$_whois_arguments[@]"
+	  "${opts}${hostopt}:host:_whois_hosts")
+      else
+	_whois_arguments=("$_whois_arguments[@]"
+	  "${opts}-${opt}[${${(@M)_whois_servers:#*:$opt}%:?}]")
+      fi
     done
   }
 }
 
 _whois_single () {
-  local state line expl
+  local curcontext="$curcontext" state line expl
   typeset -A opt_args
   local tmp host
 
-  _arguments \
+  _arguments -C \
     "$_whois_arguments[@]" \
     ':identifier:->identifier'
 
   case "$state" in
   identifier)
-    if [[ -z "$QIPREFIX" ]]; then
+    if [[ -z "$QIPREFIX" && -z "$PREFIX" ]]; then
       compadd -QS '' \'
       return
     fi
@@ -126,7 +134,7 @@ _whois_single () {
         break
       fi
     done
-    if builtin functions "_whois:$host" >&-; then
+    if (( $+functions[_whois:$host] )); then
       "_whois:$host" "$expl[@]"
     else
       _message "identifier"
@@ -136,11 +144,11 @@ _whois_single () {
 }
 
 _whois_multi () {
-  local state line expl
+  local curcontext="$curcontext" state line expl
   typeset -A opt_args
   local tmp host
 
-  _arguments \
+  _arguments -C \
     "$_whois_arguments[@]" \
     '*::identifier:->identifier'
 
@@ -153,7 +161,7 @@ _whois_multi () {
         break
       fi
     done
-    if builtin functions "_whois:$host" >&-; then
+    if (( $+functions[_whois:$host] )); then
       "_whois:$host" "$expl[@]"
     else
       _message "identifier"
@@ -166,13 +174,13 @@ _whois_fwhois () {
   if compset -P '*@'; then
     _whois_hosts "$@"
   else
-    if [[ -z "$QIPREFIX" ]]; then
+    if [[ -z "$QIPREFIX" && -z "$PREFIX" ]]; then
       compadd -QS '' \'
       return
     fi
     compset -q
     host="$_whois_defaultserver"
-    if builtin functions "_whois:$host" >&-; then
+    if (( $+functions[_whois:$host] )); then
       "_whois:$host" "$@"
     else
       _message "identifier"
@@ -181,28 +189,33 @@ _whois_fwhois () {
 }
 
 _whois_hosts () {
-  compadd "$@" \
-    -M 'm:{a-zA-Z}={A-Za-z} r:|.=* r:|=*' \
-    - ${_whois_servers%:?} || _hosts "$@"
+  _tags hosts &&
+    compadd "$@" \
+      -M 'm:{a-zA-Z}={A-Za-z} r:|.=* r:|=*' \
+      - ${_whois_servers%:?} || _hosts "$@"
 }
 
 _whois_ports () {
-  compadd "$@" - whois || _ports "$@"
+  _tags ports && compadd "$@" - whois || _ports "$@"
 }
 
-builtin functions _whois:whois.internic.net >&- ||
+(( $+functions[_whois:whois.internic.net] )) ||
 _whois:whois.internic.net () {
   if (( CURRENT == 1 )); then
-    compadd HELP DOMAIN HOST
+    local expl
+
+    _wanted strings expl string compadd HELP DOMAIN HOST
   else
     _message 'string'
   fi
 }
 
-builtin functions _whois:whois.nic.ad.jp >&- ||
+(( $+functions[_whois:whois.nic.ad.jp] )) ||
 _whois:whois.nic.ad.jp () {
   if (( CURRENT == 1 )); then
-    compadd HELP DOM NET HOST PERSON CONN COM
+    local expl
+
+    _wanted strings expl string compadd HELP DOM NET HOST PERSON CONN COM
   else
     _message 'string'
   fi
diff --git a/Completion/X/_x_colormapid b/Completion/X/_x_colormapid
index 3c637c1d9..61b0a72f1 100644
--- a/Completion/X/_x_colormapid
+++ b/Completion/X/_x_colormapid
@@ -2,7 +2,7 @@
 
 local expl list desc
 
-_wanted colormapids || return 1
+_tags colormapids || return 1
 
 list=(${(f)"$(xprop -root -f RGB_COLOR_MAP 32xcccccccxx ': $0\n'|awk -F'[ ():]' '/^[a-zA-Z_]+\(RGB_COLOR_MAP\)/ {print $5, "--", $1}')"})
 
@@ -12,5 +12,5 @@ else
   desc=()
 fi
 
-_all_labels colormapids expl 'colormap id' \
+_wanted colormapids expl 'colormap id' \
     compadd "$@" "$desc[@]" - "${(@)list%% *}" 
diff --git a/Completion/X/_x_display b/Completion/X/_x_display
index 94c3fa9a4..f547a64fa 100644
--- a/Completion/X/_x_display
+++ b/Completion/X/_x_display
@@ -1,3 +1,3 @@
 #autoload
 
-_wanted displays && _hosts -S ':0 ' -r :
+_tags displays && _hosts -S ':0 ' -r :
diff --git a/Completion/X/_x_extension b/Completion/X/_x_extension
index 11e53fa6c..5b742a78c 100644
--- a/Completion/X/_x_extension
+++ b/Completion/X/_x_extension
@@ -2,18 +2,18 @@
 
 local expl
 
-_wanted extensions || return 1
+_tags extensions || return 1
 
 (( $+_xe_cache )) || _xe_cache=( "${(@)${(@f)$(xdpyinfo)}[(r)number of extensions:*,-1][2,(r)default screen number:*][1,-2]//[      ]}" )
 
 if [[ "$1" = -a ]]; then
   shift
 
-  _all_labels extensions expl 'X extensions' \
+  _wanted extensions expl 'X extensions' \
       compadd "$@" -M 'm:{a-z}={A-Z} r:|-=* r:|=*' - all "$_xe_cache[@]"
 else
   [[ "$1" = - ]] && shift
 
-  _all_labels extensions expl 'X extensions' \
+  _wanted extensions expl 'X extensions' \
       compadd "$@" -M 'm:{a-z}={A-Z} r:|-=* r:|=*' - "$_xe_cache[@]"
 fi
diff --git a/Completion/X/_x_font b/Completion/X/_x_font
index 43a713b34..228542bd2 100644
--- a/Completion/X/_x_font
+++ b/Completion/X/_x_font
@@ -2,7 +2,7 @@
 
 local expl
 
-_wanted fonts || return 1
+_tags fonts || return 1
 
 # This *has* to be improved some day...
 
@@ -12,5 +12,5 @@ if (( ! $+_font_cache )); then
  _font_cache=( "${(@)^${(@f)$(_call fonts xlsfonts)}%%--*}--" )
 fi
 
-_all_labels fonts expl font \
+_wanted fonts expl font \
     compadd -M 'r:|-=* r:|=*' "$@" -S '' - "$_font_cache[@]"
diff --git a/Completion/X/_x_keysym b/Completion/X/_x_keysym
index f50762f7e..8d4cfa1f8 100644
--- a/Completion/X/_x_keysym
+++ b/Completion/X/_x_keysym
@@ -2,7 +2,7 @@
 
 local expl
 
-_wanted keysyms || return 1
+_tags keysyms || return 1
 
 if (( ! $+_keysym_cache )); then
   local file
@@ -18,5 +18,5 @@ if (( ! $+_keysym_cache )); then
   fi
 fi
 
-_all_labels keysyms expl 'key symbol' \
+_wanted keysyms expl 'key symbol' \
     compadd "$@" -M 'm:{a-z}={A-Z} r:|-=* r:|=*' - $_keysym_cache
diff --git a/Completion/X/_x_window b/Completion/X/_x_window
index 1862db9a7..24d6048a7 100644
--- a/Completion/X/_x_window
+++ b/Completion/X/_x_window
@@ -2,17 +2,17 @@
 
 local list expl
 
-_wanted windows || return 1
+_tags windows || return 1
 
 list=( "${(@)${(M@)${(@f)$(_call windows xwininfo -root -tree)}:#[ 	]#0x[0-9a-f]# \"*}##[ 	]#}" )
 
 if [[ "$1" = -n ]]; then
   shift
 
-  _all_labels windows expl 'window name' \
+  _wanted windows expl 'window name' \
       compadd "$@" -d list - "${(@)${(@)list#*\"}%%\"*}"
 else
   [[ "$1" = - ]] && shift
 
-  _all_labels windows expl 'window ID' compadd "$@" -d list - "${(@)list%% *}"
+  _wanted windows expl 'window ID' compadd "$@" -d list - "${(@)list%% *}"
 fi
diff --git a/Completion/X/_xmodmap b/Completion/X/_xmodmap
index 6595d5adf..5c7fcf3fe 100644
--- a/Completion/X/_xmodmap
+++ b/Completion/X/_xmodmap
@@ -82,12 +82,14 @@ if [[ -n "$state" ]]; then
     [[ "$what" = *ksym* ]] && _x_keysym "$suf[@]" && ret=0
 
   else
-    if _wanted commands; then
+    _tags commands
+    while _tags; do
       while _next_label commands expl command; do
         compadd "$expl[@]" -S ' ' keycode keysym clear add remove && ret=0
         compadd "$expl[@]" -S ' = ' pointer && ret=0
       done
-    fi
+      (( ret )) || return 0
+    done
   fi
 fi
 
diff --git a/Completion/X/_xutils b/Completion/X/_xutils
index a57f7be36..c0d94a998 100644
--- a/Completion/X/_xutils
+++ b/Completion/X/_xutils
@@ -55,23 +55,29 @@ xhost)
     if [[ "$tmp" = *:* ]]; then
       if compset -P '(#b)(*):'; then
 	type="$match[1]"
-	_wanted displays &&
-            while _next_label displays expl 'disallow access'; do
+	_tags displays
+	while _tags; do
+          while _next_label displays expl 'disallow access'; do
 	      { compadd "$expl[@]" -M 'm:{a-z}={A-Z} r:|[:.]=* r:|=*' - \
 		        ${${(M)tmp:#(#i)$type:*}#(#i)$type:} ||
-	            _hosts "$expl[@]" } && return 0
-	    done
+	            _hosts "$expl[@]" } && ret=0
+	  done
+	  (( ret )) || return 0
+        done
       else
 	_alternative \
 	    'types:name family:compadd -S: ${(L)tmp%%:*}' \
 	    'hosts:host:compadd ${(@)tmp#*:}' && ret=0
       fi
     else
-      _wanted displays &&
-          while _next_label displays expl 'disallow access'; do
-	    { compadd "$expl[@]" -M 'm:{a-z}={A-Z} r:|[:.]=* r:|=*' - $tmp ||
-              _hosts "$expl[@]" } && return 0
-          done
+      _tags displays
+      while _tags; do
+        while _next_label displays expl 'disallow access'; do
+	  { compadd "$expl[@]" -M 'm:{a-z}={A-Z} r:|[:.]=* r:|=*' - $tmp ||
+            _hosts "$expl[@]" } && ret=0
+        done
+	(( ret )) || return 0
+      done
     fi
   else
     compset -P +
diff --git a/Completion/X/_xwit b/Completion/X/_xwit
index 998627869..69b210e5b 100644
--- a/Completion/X/_xwit
+++ b/Completion/X/_xwit
@@ -17,7 +17,7 @@ _xwit_guard () {
 _xwit_compopts () {
   local expl
   _wanted options expl option compadd - ${(k)no[(R)*~0]} ||
-      _all_labels options expl option compadd - ${(k)no}
+      _wanted options expl option compadd - ${(k)no}
 }
 
 _regex_arguments _xwit_parse \
diff --git a/Doc/Zsh/compsys.yo b/Doc/Zsh/compsys.yo
index 29a259f34..55d2c292d 100644
--- a/Doc/Zsh/compsys.yo
+++ b/Doc/Zsh/compsys.yo
@@ -945,15 +945,19 @@ expected by the caller of tt(_files).
 
 If the tt(file-patterns) style is set, the default tags are not
 used. Instead, the value of the style says which tags and which
-patterns are to be offered. The strings in the value are of the form
-`var(patterns)tt(:)var(tag)'. The var(patterns) gives one or more glob 
-patterns separated by spaces that are to be used to generate
+patterns are to be offered. The strings in the value contain
+specifications of the form
+`var(patterns)tt(:)var(tag)'; each string may contain any number of
+such specifications. The var(patterns) give one or more glob 
+patterns separated by commas that are to be used to generate
 filenames. If it contains the sequence `tt(%p)', that is replaced by
 the pattern(s) given by the calling function.
 Colons in the pattern have to be preceded by a backslash to
 make them distinguishable from the colon before the var(tag). The
 var(tag)s of all strings in the value will be offered by tt(_files)
-(again, one after another) and used when looking up other styles. If
+(again, one after another) and used when looking up other styles. For
+strings containing more than one specification, the filenames for all
+specifications will be generated at the same try. If
 no `tt(:)var(tag)' is given the `tt(files)' tag will be used. The
 var(tag) may also be
 followed by an optional second colon and a description. If that is
@@ -978,7 +982,7 @@ directories in the first try and all files as the second try. To
 achieve this, one could do:
 
 example(zstyle ':completion:*' file-patterns \ 
-    '%p *(-/):globbed-files' '*:all-files')
+    '%p:globbed-files *(-/):directories' '*:all-files')
 
 Note also that during the execution of completion functions, the
 tt(EXTENDED_GLOB) option is in effect, so the characters `tt(#)',
@@ -2216,22 +2220,12 @@ var(N), complete the var(N)th most recently modified file.  Note the
 completion, if any, is always unique.
 )
 findex(_next_tags)
-item(tt(_next_tags))(
+item(tt(_next_tags) (^Xn))(
 This allows to complete types of matches that are not immediately
 offered because of the setting of the tt(tag-order) style. After a
 normal completion was tried, invoking this command makes the matches
 for the next tag (or set of tags) be used. Repeatedly invoking this
-command makes the following tags be used. To be able to complete the
-matches selected by tt(_next_tags), the tt(completer) style should
-contain tt(_next_tags) as its first string. With that, the normal key
-binding (normally tt(TAB)) can be used to complete the matches shown
-after the call to tt(_next_tags).
-
-Normally, this command is not bound to a key. To invoke it with, say
-`tt(^Xn)', one would use:
-
-example(zle -C _next_tags complete-word _next_tags
-bindkey '^Xn' _next_tags)
+command makes the following tags be used.
 )
 findex(_read_comp (^X^R))
 item(tt(_read_comp (^X^R)))(
@@ -2442,7 +2436,7 @@ user to the tt(tag-order) style is prefered over the one given to
 tt(_next_label).
 
 Note that this function must not be called without a previous call to
-tt(_tags), tt(_wanted) or tt(_requested) because it uses the tag label
+tt(_tags) or tt(_requested) because it uses the tag label
 for the current tag found by these functions.
 
 A normal use of this function for the tag labels for the tag tt(foo)
@@ -2450,12 +2444,13 @@ looks like this:
 
 example(local expl ret=1
 ...
-_wanted foo || return 1
-...
-while _next_label foo expl '...'; do
-  compadd "$expl[@]" ... && ret=0
-done
-...
+if _requested foo; then
+  ...
+  while _next_label foo expl '...'; do
+    compadd "$expl[@]" ... && ret=0
+  done
+  ...
+fi
 return ret
 )
 )
@@ -2477,9 +2472,10 @@ For example:
 
 example(local expl
 ...
-_wanted foo || return 1
-...
-_all_labels foo expl '...' compadd ... - $matches)
+if _requested foo; then
+  ...
+  _all_labels foo expl '...' compadd ... - $matches
+fi)
 
 Will complete the strings from the tt(matches) parameter, using
 tt(compadd) with additional options which will take precedence over
@@ -2525,7 +2521,7 @@ while _tags; do
 done)
 )
 findex(_wanted)
-item(tt(_wanted) [ tt(-12VJ) ] var(tag) var(name) var(descr) [ var(specs) ... ])(
+item(tt(_wanted) [ tt(-12VJ) ] var(tag) var(name) var(descr) var(command) var(args) ...)(
 In many contexts only one type of matches can be generated but even
 then it should be tested if the tag representing those matches is
 requested by the user. This function makes that easier.
@@ -2538,6 +2534,10 @@ description built, you can just do:
 
 example(_wanted tag expl 'description' \ 
     compadd matches...)
+
+Unlike tt(_requested), however, tt(_wanted) can not be called without
+the var(command). That's because tt(_wanted) also implements the loop
+over the tags, not only the one for the labels.
 )
 findex(_alternative)
 item(tt(_alternative) [ tt(-C) var(name) ] var(specs) ...)(
diff --git a/Etc/completion-style-guide b/Etc/completion-style-guide
index d57a1a7fb..71b5c9a5c 100644
--- a/Etc/completion-style-guide
+++ b/Etc/completion-style-guide
@@ -63,12 +63,12 @@ example).
 Then, before adding the matches, see if matches of that type are
 requested by the user in the current context. If you will add only one 
 type of matches, this is very simple. You can use the function
-`_wanted' for this. Its return value is zero only if the type of
-matches is requested by the user, so you can just do:
+`_wanted' for this. Well, you can often use it, that is. Use it as in:
 
-  _wanted names || return 1
+  _wanted names expl 'name' compadd - alice bob
 
-  _all_labels names expl 'name' compadd - alice bob
+This is like testing if the tag `names' is requested by the user and
+then calling `_all_labels' with the same arguments.
 
 The `_all_labels' function implements the loop over the tag aliases and
 handles the user-defined description, using (in the example) the
@@ -88,13 +88,6 @@ the last argument. A good example for such a function is
 And the `-' will be replaced by the options that are to be given to
 `compadd'.
 
-Since the above sequence of command is used so often, the `_wanted'
-function can also accept the same arguments as `_all_labels'. In this
-case it will do the test for the requested tag and then just call
-`_all_labels', so:
-
-  _wanted names expl 'name' compadd - alice bob
-
 Note that you can also give the `-J' and `-V' options with the
 optional `1' or `2' preceding them supported by `_description':
 
@@ -332,11 +325,11 @@ often be using the tags function that allows you to give the
 explanation to the same function that is used to test if the tags are
 requested (again: see above). Just as a reminder:
 
-  _wanted [ -[1,2]V | -[1,2]J ] <tag> expl <descr>
+  _wanted [ -[1,2]V | -[1,2]J ] <tag> expl <descr> <cmd> ...
 
 and
 
-  _requested [ -[1,2]V | -[1,2]J ] <tag> expl <descr>
+  _requested [ -[1,2]V | -[1,2]J ] <tag> expl <descr> [ <cmd> ... ]
 
 is all you need to make your function work correctly with both tags
 and description at the same time.
diff --git a/Functions/Zftp/zfcd_match b/Functions/Zftp/zfcd_match
index b5902cdde..8e2b6452a 100644
--- a/Functions/Zftp/zfcd_match
+++ b/Functions/Zftp/zfcd_match
@@ -30,7 +30,7 @@ if [[ $ZFTP_SYSTEM = UNIX* ]]; then
   rm -f $tmpf
   [[ -n $dir && $dir != */ ]] && dir="$dir/"
   if [[ -n $WIDGET ]]; then
-    _all_labels directories expl 'remote directory'
+    _wanted directories expl 'remote directory'
         compadd -S/ -q -P "$dir" - $reply
   elif [[ -n $dir ]]; then
     reply=(${dir}$reply)
diff --git a/Functions/Zftp/zfget_match b/Functions/Zftp/zfget_match
index 0fe2bc06f..1d90bea60 100644
--- a/Functions/Zftp/zfget_match
+++ b/Functions/Zftp/zfget_match
@@ -17,7 +17,7 @@ if [[ $ZFTP_SYSTEM == UNIX* && $1 == */* ]]; then
     local reply
     reply=(${${${(f)"$(<$tmpf)"}##$dir}%\*})
     rm -f $tmpf
-    _all_labels files expl 'remote file' compadd -P $dir - $reply
+    _wanted files expl 'remote file' compadd -P $dir - $reply
   else
     # On the first argument to ls, we usually get away with a glob.
     zftp ls "$1*$2" >$tmpf
@@ -28,7 +28,7 @@ else
   local fcache_name
   zffcache
   if [[ -n $WIDGET ]]; then
-    _all_labels files expl 'remote file' compadd -F fignore - ${(P)fcache_name}
+    _wanted files expl 'remote file' compadd -F fignore - ${(P)fcache_name}
   else
     reply=(${(P)fcache_name});
   fi
diff --git a/Src/Zle/computil.c b/Src/Zle/computil.c
index e73fe8eaf..09746c1bb 100644
--- a/Src/Zle/computil.c
+++ b/Src/Zle/computil.c
@@ -2291,7 +2291,7 @@ bin_comptags(char *nam, char **args, char *ops, int func)
     case 'N': min = 0; max =  0; break;
     case 'R': min = 1; max =  1; break;
     case 'S': min = 1; max =  1; break;
-    case 'A': min = 2; max =  2; break;
+    case 'A': min = 2; max =  3; break;
     default:
 	zwarnnam(nam, "invalid option: %s", args[0], 0);
 	return 1;
@@ -2365,6 +2365,14 @@ bin_comptags(char *nam, char **args, char *ops, int func)
 		}
 		s->ptr = q + 1;
 		setsparam(args[2], ztrdup(*v == '-' ? dyncat(args[1], v) : v));
+		if (args[3]) {
+		    char *r = dupstring(*q), *p;
+
+		    for (p = r + (v - *q); *p && *p != ':'; p++);
+		    *p = '\0';
+
+		    setsparam(args[3], ztrdup(r));
+		}
 		return 0;
 	    }
 	    return 1;