about summary refs log tree commit diff
diff options
context:
space:
mode:
authorTanaka Akira <akr@users.sourceforge.net>1999-11-15 12:01:46 +0000
committerTanaka Akira <akr@users.sourceforge.net>1999-11-15 12:01:46 +0000
commit35b2633ad941966f5fca07b625a594a5b68c0fdb (patch)
treeb54740d014e594ba5d81931cdcdb3387bcf9dfca
parentbb98460a01ce1f6c1e71f7e401f782c81b71486b (diff)
downloadzsh-35b2633ad941966f5fca07b625a594a5b68c0fdb.tar.gz
zsh-35b2633ad941966f5fca07b625a594a5b68c0fdb.tar.xz
zsh-35b2633ad941966f5fca07b625a594a5b68c0fdb.zip
manual/8639
-rw-r--r--Completion/Base/_arg_compile2
-rw-r--r--Completion/Base/_arguments51
-rw-r--r--Completion/Base/_brace_parameter2
-rw-r--r--Completion/Base/_command_names2
-rw-r--r--Completion/Base/_condition10
-rw-r--r--Completion/Base/_default5
-rw-r--r--Completion/Base/_describe42
-rw-r--r--Completion/Base/_equal2
-rw-r--r--Completion/Base/_first2
-rw-r--r--Completion/Base/_jobs8
-rw-r--r--Completion/Base/_math2
-rw-r--r--Completion/Base/_parameter2
-rw-r--r--Completion/Base/_regex_arguments4
-rw-r--r--Completion/Base/_subscript29
-rw-r--r--Completion/Base/_tilde16
-rw-r--r--Completion/Base/_values55
-rw-r--r--Completion/Builtins/_aliases2
-rw-r--r--Completion/Builtins/_arrays6
-rw-r--r--Completion/Builtins/_autoload6
-rw-r--r--Completion/Builtins/_bindkey12
-rw-r--r--Completion/Builtins/_builtin6
-rw-r--r--Completion/Builtins/_cd6
-rw-r--r--Completion/Builtins/_command6
-rw-r--r--Completion/Builtins/_compdef12
-rw-r--r--Completion/Builtins/_disable2
-rw-r--r--Completion/Builtins/_echotc9
-rw-r--r--Completion/Builtins/_enable2
-rw-r--r--Completion/Builtins/_functions6
-rw-r--r--Completion/Builtins/_hash22
-rw-r--r--Completion/Builtins/_kill9
-rw-r--r--Completion/Builtins/_limits6
-rw-r--r--Completion/Builtins/_pids14
-rw-r--r--Completion/Builtins/_popd10
-rw-r--r--Completion/Builtins/_sched5
-rw-r--r--Completion/Builtins/_stat15
-rw-r--r--Completion/Builtins/_trap5
-rw-r--r--Completion/Builtins/_unhash2
-rw-r--r--Completion/Builtins/_vars14
-rw-r--r--Completion/Builtins/_wait2
-rw-r--r--Completion/Builtins/_which2
-rw-r--r--Completion/Builtins/_zftp35
-rw-r--r--Completion/Builtins/_zle9
-rw-r--r--Completion/Builtins/_zmodload14
-rw-r--r--Completion/Commands/_complete_help35
-rw-r--r--Completion/Commands/_correct_word15
-rw-r--r--Completion/Commands/_expand_word21
-rw-r--r--Completion/Commands/_history_complete_word36
-rw-r--r--Completion/Commands/_read_comp4
-rw-r--r--Completion/Core/.distfiles2
-rw-r--r--Completion/Core/_alternative21
-rw-r--r--Completion/Core/_approximate31
-rw-r--r--Completion/Core/_complete21
-rw-r--r--Completion/Core/_correct6
-rw-r--r--Completion/Core/_description16
-rw-r--r--Completion/Core/_expand61
-rw-r--r--Completion/Core/_files6
-rw-r--r--Completion/Core/_list12
-rw-r--r--Completion/Core/_main_complete21
-rw-r--r--Completion/Core/_match20
-rw-r--r--Completion/Core/_menu8
-rw-r--r--Completion/Core/_message4
-rw-r--r--Completion/Core/_normal23
-rw-r--r--Completion/Core/_oldlist26
-rw-r--r--Completion/Core/_options8
-rw-r--r--Completion/Core/_parameters5
-rw-r--r--Completion/Core/_path_files12
-rw-r--r--Completion/Core/_requested12
-rw-r--r--Completion/Core/_set_options7
-rw-r--r--Completion/Core/_sort_tags6
-rw-r--r--Completion/Core/_style74
-rw-r--r--Completion/Core/_tags61
-rw-r--r--Completion/Core/_unset_options7
-rw-r--r--Completion/Core/_wanted21
-rw-r--r--Completion/Core/compdump2
-rw-r--r--Completion/Core/compinit253
-rw-r--r--Completion/Core/compinstall30
-rw-r--r--Completion/Debian/_apt16
-rw-r--r--Completion/Debian/_deb_packages13
-rw-r--r--Completion/Linux/_rpm33
-rw-r--r--Completion/User/_archie9
-rw-r--r--Completion/User/_cvs61
-rw-r--r--Completion/User/_dd10
-rw-r--r--Completion/User/_flex4
-rw-r--r--Completion/User/_gcc10
-rw-r--r--Completion/User/_gdb27
-rw-r--r--Completion/User/_gprof6
-rw-r--r--Completion/User/_groups7
-rw-r--r--Completion/User/_gs31
-rw-r--r--Completion/User/_hosts6
-rw-r--r--Completion/User/_killall6
-rw-r--r--Completion/User/_lynx4
-rw-r--r--Completion/User/_mailboxes44
-rw-r--r--Completion/User/_make13
-rw-r--r--Completion/User/_man6
-rw-r--r--Completion/User/_mh32
-rw-r--r--Completion/User/_mount21
-rw-r--r--Completion/User/_mutt6
-rw-r--r--Completion/User/_netscape45
-rw-r--r--Completion/User/_nslookup28
-rw-r--r--Completion/User/_pbm15
-rw-r--r--Completion/User/_perl_basepods11
-rw-r--r--Completion/User/_perl_builtin_funcs5
-rw-r--r--Completion/User/_perl_modules4
-rw-r--r--Completion/User/_ports5
-rw-r--r--Completion/User/_rcs3
-rw-r--r--Completion/User/_rlogin33
-rw-r--r--Completion/User/_socket32
-rw-r--r--Completion/User/_ssh108
-rw-r--r--Completion/User/_stty25
-rw-r--r--Completion/User/_tar10
-rw-r--r--Completion/User/_telnet46
-rw-r--r--Completion/User/_tiff27
-rw-r--r--Completion/User/_urls81
-rw-r--r--Completion/User/_use_lo4
-rw-r--r--Completion/User/_user_at_host14
-rw-r--r--Completion/User/_users4
-rw-r--r--Completion/User/_users_on2
-rw-r--r--Completion/User/_wget4
-rw-r--r--Completion/User/_whois24
-rw-r--r--Completion/User/_yp46
-rw-r--r--Completion/X/_x_arguments19
-rw-r--r--Completion/X/_x_color13
-rw-r--r--Completion/X/_x_cursor6
-rw-r--r--Completion/X/_x_display4
-rw-r--r--Completion/X/_x_extension4
-rw-r--r--Completion/X/_x_font3
-rw-r--r--Completion/X/_x_keysym3
-rw-r--r--Completion/X/_x_modifier8
-rw-r--r--Completion/X/_x_window2
-rw-r--r--Completion/X/_xmodmap7
-rw-r--r--Completion/X/_xt_arguments57
-rw-r--r--Completion/X/_xutils12
-rw-r--r--Doc/Zsh/compsys.yo15
-rw-r--r--Doc/Zsh/mod_computil.yo6
-rw-r--r--Etc/completion-style-guide416
-rw-r--r--Src/Zle/computil.c651
-rw-r--r--Src/Zle/computil.mdd2
137 files changed, 2184 insertions, 1345 deletions
diff --git a/Completion/Base/_arg_compile b/Completion/Base/_arg_compile
index 8eb2e80f5..44db86abe 100644
--- a/Completion/Base/_arg_compile
+++ b/Completion/Base/_arg_compile
@@ -39,7 +39,7 @@
 #       "assign"  as loose, but must follow an "=" in the same word ("=")
 #     HOW should be suffixed with a colon if the following argument is
 #      _not_ required to appear.
-#     STR is to be displayed based on compconfig[describe_options].
+#     STR is to be displayed based on style `description'
 #     XOR is another option in combination with which OPT may not appear.
 #      It may be ":" to disable non-option completions when OPT is present.
 #     MSG is a string to be displayed above the matches in a listing.
diff --git a/Completion/Base/_arguments b/Completion/Base/_arguments
index fbc7d7875..531b11407 100644
--- a/Completion/Base/_arguments
+++ b/Completion/Base/_arguments
@@ -3,7 +3,8 @@
 # Complete the arguments of the current command according to the
 # descriptions given as arguments to this function.
 
-local long cmd="$words[1]" descr mesg subopts
+local long cmd="$words[1]" descr mesg subopts opt usecc autod
+local oldcontext="$curcontext"
 
 long=$argv[(I)--]
 if (( long )); then
@@ -151,30 +152,33 @@ if (( long )); then
   set -- "$tmpargv[@]" "${(@P)name}"
 fi
 
-if [[ "$1" = -O?* ]]; then
-  subopts=( "${(@P)1[3,-1]}" )
-  shift
-elif [[ "$1" = -O ]]; then
-  subopts=( "${(@P)1}" )
-  shift 2
-else
-  subopts=()
-fi
+subopts=()
+while getopts ':O:C' opt; do
+  if [[ "$opt" = O ]]; then
+    subopts=( "${(@P)OPTARG}" )
+  else
+    usecc=yes
+  fi
+done
 
-if comparguments -i "$compconfig[autodescribe_options]" "$@"; then
+shift OPTIND-1
+
+_style -s options auto-description autod
+
+if comparguments -i "$autod" "$@"; then
   local nm="$compstate[nmatches]" action noargs aret expl local
   local next direct odirect equal single match matched ws tmp1 tmp2
-  local opts _sub_context oldsc="${_sub_context}"
+  local opts subc
 
   if comparguments -D descr action; then
-    comparguments -C _sub_context
-    _sub_context="${oldsc}:${oldsc:+${oldsc}-}${_sub_context}"
+    comparguments -C subc
+    curcontext="${oldcontext}:$subc"
 
     if comparguments -O next direct odirect equal; then
       opts=yes
-      _tags "${oldsc}:any" arguments options
+      _tags arguments options
     else
-      _tags "${oldsc}:any" arguments
+      _tags arguments
     fi
   else
     if comparguments -a; then
@@ -185,7 +189,7 @@ if comparguments -i "$compconfig[autodescribe_options]" "$@"; then
     comparguments -O next direct odirect equal || return 1
 
     opts=yes
-    _tags "${oldsc}:any" options
+    _tags options
   fi
 
   while _tags; do
@@ -196,6 +200,11 @@ if comparguments -i "$compconfig[autodescribe_options]" "$@"; then
         if [[ "$action" = -\>* ]]; then
           comparguments -W line opt_args
           state="${${action[3,-1]##[ 	]#}%%[ 	]#}"
+	  if [[ -n "$usecc" ]]; then
+	    curcontext="$subc"
+	  else
+	    context="$subc"
+	  fi
           compstate[restore]=''
           aret=yes
         else
@@ -248,7 +257,7 @@ if comparguments -i "$compconfig[autodescribe_options]" "$@"; then
         fi
       fi
       if [[ -z "$matched" ]] && _requested options &&
-          { ! _style options prefix-needed yes ||
+          { ! _style options prefix-needed ||
             [[ "$PREFIX" = [-+]* ]] } ; then
         comparguments -M match
 
@@ -296,8 +305,8 @@ if comparguments -i "$compconfig[autodescribe_options]" "$@"; then
 	  SUFFIX="$suffix"
 	  IPREFIX="${IPREFIX}${equal[1]%%:*}="
 	  matched=yes
-	  comparguments -L "$equal[1]" descr action _sub_context
-          _sub_context="${oldsc}:${oldsc+${oldsc}-}${_sub_context}"
+	  comparguments -L "$equal[1]" descr action subc
+	  curcontext="${oldcontext}:$subc"
 	  continue
         fi
       fi
@@ -306,6 +315,8 @@ if comparguments -i "$compconfig[autodescribe_options]" "$@"; then
     [[ -n "$aret" || nm -ne compstate[nmatches] ]] && break
   done
 
+  [[ -z "$aret" || -z "$usecc" ]] && curcontext="$oldcontext"
+
   [[ -n "$aret" ]] && return 300
 
   [[ -n "$mesg" ]] && _message "$mesg"
diff --git a/Completion/Base/_brace_parameter b/Completion/Base/_brace_parameter
index 1d1a48c78..3502bd794 100644
--- a/Completion/Base/_brace_parameter
+++ b/Completion/Base/_brace_parameter
@@ -1,6 +1,6 @@
 #compdef -brace-parameter-
 
-_tags any parameters && _parameters -e
+_requested -t parameters && _parameters -e
 
 
 # Without the `-e' option, we would use the following (see the file
diff --git a/Completion/Base/_command_names b/Completion/Base/_command_names
index 8d8f5630f..63c8601e9 100644
--- a/Completion/Base/_command_names
+++ b/Completion/Base/_command_names
@@ -27,4 +27,4 @@ fi
 
 args=( "$@" )
 
-_alternative -O args any "$defs[@]"
+_alternative -O args "$defs[@]"
diff --git a/Completion/Base/_condition b/Completion/Base/_condition
index 93bbdc7f4..51ac6bf0d 100644
--- a/Completion/Base/_condition
+++ b/Completion/Base/_condition
@@ -3,13 +3,9 @@
 local prev="$words[CURRENT-1]"
 
 if [[ "$prev" = -o ]]; then
-  _tags - -o options || return 1
-
-  _options
+  _tags -C -o options && _options
 elif [[ "$prev" = -([no]t|ef) ]]; then
-  _tags - "$prev" files || return 1
-
-  _files
+  _tags -C "$prev" files && _files
 else
-  _alternative any 'files:: _files' 'parameters:: _parameters'
+  _alternative 'files:: _files' 'parameters:: _parameters'
 fi
diff --git a/Completion/Base/_default b/Completion/Base/_default
index cf4077d3b..920f3a959 100644
--- a/Completion/Base/_default
+++ b/Completion/Base/_default
@@ -14,10 +14,9 @@ local expl
 
 # compcall || return 0
 
-_tags any files || return 1
+_tags files || return 1
 
-_description expl file
-_files "$expl[@]" && return
+_files && return 0
 
 # magicequalsubst allows arguments like <any-old-stuff>=~/foo to do
 # file name expansion after the =.  In that case, it's natural to
diff --git a/Completion/Base/_describe b/Completion/Base/_describe
index db2011727..181ccbfcb 100644
--- a/Completion/Base/_describe
+++ b/Completion/Base/_describe
@@ -2,54 +2,54 @@
 
 # This can be used to add options or values with descriptions as matches.
 
-local cmd opt expl tmps tmpd tmpmd tmpms ret=1 showd _nm hide args
-local type=values
+local _cmd _opt _expl _tmps _tmpd _tmpmd _tmpms _ret=1 _showd _nm _hide _args
+local _type=values
 
-cmd="$words[1]"
+_cmd="$words[1]"
 
 # Get the options.
 
-while getopts 'oc:' opt; do
-  if [[ "$opt" = o ]]; then
-    type=options
+while getopts 'oc:' _opt; do
+  if [[ "$_opt" = o ]]; then
+    _type=options
   else
-    cmd="$OPTARG"
+    _cmd="$OPTARG"
   fi
 done
 shift OPTIND-1
 
 # Do the tests. `showd' is set if the descriptions should be shown.
 
-_tags -c "$cmd" any "$type" || return 1
+_tags "$_type" || return 1
 
-_style "$type" description yes && showd=yes
+_style "$_type" description && _showd=yes
 
-_description expl "$1"
+_description _expl "$1"
 shift
 
-if [[ -n "$showd" ]]; then
+if [[ -n "$_showd" ]]; then
   compdescribe -I ' -- ' "$@"
 else
   compdescribe -i "$@"
 fi
 
-[[ "$type" = options ]] && _style options prefix-hidden yes && hide=yes
+[[ "$_type" = options ]] && _style options prefix-hidden && _hide=yes
 
-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.
 
-  if [[ -n "$hide" ]]; then
+  if [[ -n "$_hide" ]]; then
     if [[ "$PREFIX" = --* ]]; then
-      tmpd=( "${(@)tmpd#--}" )
-      tmps=( "${(@)tmps#--}" )
+      _tmpd=( "${(@)_tmpd#--}" )
+      _tmps=( "${(@)_tmps#--}" )
     elif [[ "$PREFIX" = [-+]* ]]; then
-      tmpd=( "${(@)tmpd#[-+]}" )
-      tmps=( "${(@)tmps#[-+]}" )
+      _tmpd=( "${(@)_tmpd#[-+]}" )
+      _tmps=( "${(@)_tmps#[-+]}" )
     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
 
-return ret
+return _ret
diff --git a/Completion/Base/_equal b/Completion/Base/_equal
index 760f85c68..b0d31f2be 100644
--- a/Completion/Base/_equal
+++ b/Completion/Base/_equal
@@ -4,6 +4,6 @@ local args
 
 args=( "$@" )
 
-_alternative -O args any \
+_alternative -O args \
     'commands:command:compadd - ${(@k)commands}' \
     'aliases:alias:compadd - ${(@k)aliases}'
diff --git a/Completion/Base/_first b/Completion/Base/_first
index fc434fca7..7c070d743 100644
--- a/Completion/Base/_first
+++ b/Completion/Base/_first
@@ -50,7 +50,7 @@
 #       # We first search in the last ten words, then in the last
 #       # twenty words, and so on...
 #       while [[ i -le max ]]; do
-#         if [[ -n "$compconfig[history_sort]" ]]; then
+#         if _style history-entries sort; then
 #           _description expl "history ($n)"
 #         else
 #           _description -V expl "history ($n)"
diff --git a/Completion/Base/_jobs b/Completion/Base/_jobs
index ba83d784e..40d6efc34 100644
--- a/Completion/Base/_jobs
+++ b/Completion/Base/_jobs
@@ -2,11 +2,11 @@
 
 local expl disp jobs job jids pfx='%' desc
 
-_tags any jobs || return 1
+_tags jobs || return 1
 
-_style jobs prefix-needed yes && [[ "$PREFIX" != %* ]] && return 1
-_style jobs prefix-hidden yes && pfx=''
-_style jobs description yes   && desc=yes
+_style jobs prefix-needed && [[ "$PREFIX" != %* ]] && return 1
+_style jobs prefix-hidden && pfx=''
+_style jobs description   && desc=yes
 
 if [[ "$1" = -r ]]; then
   jids=( "${(@k)jobstates[(R)running*]}" )
diff --git a/Completion/Base/_math b/Completion/Base/_math
index 77d97acf1..821121c33 100644
--- a/Completion/Base/_math
+++ b/Completion/Base/_math
@@ -9,4 +9,4 @@ if [[ "$SUFFIX" = *[^a-zA-Z0-9_]* ]]; then
   SUFFIX="${SUFFIX%%[^a-zA-Z0-9_]*}"
 fi
 
-_tags any parameters && _parameters
+_tags parameters && _parameters
diff --git a/Completion/Base/_parameter b/Completion/Base/_parameter
index 3ed91d620..1c4d5e014 100644
--- a/Completion/Base/_parameter
+++ b/Completion/Base/_parameter
@@ -1,6 +1,6 @@
 #compdef -parameter-
 
-_tags any parameters && _parameters -e
+_tags parameters && _parameters -e
 
 # Without the `-e' option, we would use the following (see the file
 # Core/_parameters for more enlightenment).
diff --git a/Completion/Base/_regex_arguments b/Completion/Base/_regex_arguments
index e2858e66c..ba6d330da 100644
--- a/Completion/Base/_regex_arguments
+++ b/Completion/Base/_regex_arguments
@@ -329,7 +329,9 @@ _regex_arguments () {
   local regex index first last nullable
   local i state next
 
-  local cache_dir="${compconfig[regex_arguments_path]:-$HOME/.zsh/regex_arguments}"
+  local cache_dir
+  _style -s regex argument-path cache_dir
+  [[ -z "$cache_dir" ]] && cache_dir="$HOME/.zsh/regex_arguments"
   local cache_file="$cache_dir/$1"
   local cache_test
 
diff --git a/Completion/Base/_subscript b/Completion/Base/_subscript
index c5c6ca7e9..80a3b1720 100644
--- a/Completion/Base/_subscript
+++ b/Completion/Base/_subscript
@@ -3,30 +3,25 @@
 local expl
 
 if [[ "$PREFIX" = :* ]]; then
-  _tags any char-classes || return 1
-
-  _description expl 'character class'
-  compadd "$expl[@]" -p: -S ':]' alnum alpha blank cntrl digit graph \
-                                 lower print punct space upper xdigit
+  _wanted char-classes expl 'character class' &&
+      compadd "$expl[@]" -p: -S ':]' alnum alpha blank cntrl digit graph \
+                                     lower print punct space upper xdigit
 elif [[ ${(Pt)${compstate[parameter]}} = assoc* ]]; then
-  _tags any association-keys || return 1
-
-  _description expl 'association key'
-  if [[ "$RBUFFER" = \]* ]]; then
-    compadd "$expl[@]" -S '' - "${(@kP)${compstate[parameter]}}"
-  else
-    compadd "$expl[@]" -S ']' - "${(@kP)${compstate[parameter]}}"
-  fi
+  _wanted association-keys expl 'association key' &&
+      if [[ "$RBUFFER" = \]* ]]; then
+        compadd "$expl[@]" -S '' - "${(@kP)${compstate[parameter]}}"
+      else
+        compadd "$expl[@]" -S ']' - "${(@kP)${compstate[parameter]}}"
+      fi
 elif [[ ${(Pt)${compstate[parameter]}} = array* ]]; then
   local list i j ret=1 disp
 
-  _tags any indexes parameters
+  _tags indexes parameters
 
   while _tags; do
-    if _requested indexes; then
-      _description -V expl 'array index'
+    if _requested indexes -V expl 'array index'; then
       ind=( {1..${#${(P)${compstate[parameter]}}}} )
-      if _style indexes description yes; then
+      if _style indexes description; then
         list=()
         for i in "$ind[@]"; do
           [[ "$i" = ${PREFIX}*${SUFFIX} ]] &&
diff --git a/Completion/Base/_tilde b/Completion/Base/_tilde
index afdca1222..bd21cd044 100644
--- a/Completion/Base/_tilde
+++ b/Completion/Base/_tilde
@@ -14,19 +14,17 @@ else
   suf=(-qS/)
 fi
 
-_tags any users named-directoriess directory-stack
+_tags users named-directories directory-stack
 
 while _tags; do
   _requested users && _users "$suf[@]" "$@" && ret=0
-  if _requested named-directories; then
-    _description expl 'named directory'
-    compadd "$suf[@]" "$expl[@]" "$@" - "${(@k)nameddirs}"
-  fi
+  _requested named-directories expl 'named directory' &&
+      compadd "$suf[@]" "$expl[@]" "$@" - "${(@k)nameddirs}"
 
-  if _requested directory-stack &&
-     { ! _style directory-stack prefix-needed yes ||
+  if _requested directory-stack -V expl 'directory stack' &&
+     { ! _style directory-stack prefix-needed ||
        [[ "$PREFIX" = [-+]* ]] }; then
-    if _style directory-stack description yes; then
+    if _style directory-stack description; then
       integer i
 
       lines=("${PWD}" "${dirstack[@]}")
@@ -48,8 +46,6 @@ while _tags; do
       list=( ${PREFIX[1]}{0..${#dirstack}} )
       disp=()
     fi
-
-    _description -V expl 'directory stack'
     compadd "$expl[@]" "$suf[@]" "$disp[@]" -Q - "$list[@]" && ret=0
   fi
   (( ret )) || return 0
diff --git a/Completion/Base/_values b/Completion/Base/_values
index e4d61d288..70a461a48 100644
--- a/Completion/Base/_values
+++ b/Completion/Base/_values
@@ -1,27 +1,28 @@
 #autoload
 
-local subopts
-
-if [[ "$1" = -O?* ]]; then
-  subopts=( "${(@P)1[3,-1]}" )
-  shift
-if [[ "$1" = -O ]]; then
-  subopts=( "${(@P)1}" )
-  shift 2
-else
-  subopts=()
-fi
+local subopts opt usecc
+
+subopts=()
+while getopts ':O:C' opt; do
+  if [[ "$opt" = O ]]; then
+    subopts=( "${(@P)OPTARG}" )
+  else
+    usecc=yes
+  fi
+done
+
+shift OPTIND-1
 
 if compvalues -i "$@"; then
 
-  local noargs args opts descr action expl sep _sub_context oldsc="$_sub_context"
+  local noargs args opts descr action expl sep subc
+  local oldcontext="$curcontext"
 
   if ! compvalues -D descr action; then
 
-    compvalues -C _sub_context
-    _sub_context="${oldsc}:${oldsc+${oldsc}-}${_sub_context}"
+    _tags values || return 1
 
-    _tags "${_sub_context}" values || return 1
+    curcontext="${oldcontext}:values"
 
     compvalues -V noargs args opts
 
@@ -47,8 +48,8 @@ if compvalues -i "$@"; then
         PREFIX="$prefix"
 	SUFFIX="$suffix"
         IPREFIX="${IPREFIX}${args[1]%%:*}="
-	compvalues -L "${args[1]%%:*}" descr action _sub_context
-        _sub_context="${oldsc}:${oldsc+${oldsc}-}${_sub_context}"
+	compvalues -L "${args[1]%%:*}" descr action subc
+	curcontext="${oldcontext}:$subc"
       fi
     else
       compvalues -d descr
@@ -63,14 +64,19 @@ if compvalues -i "$@"; then
         args -S= -M 'r:|[_-]=* r:|=*' -- \
         opts -qS= -M 'r:|[_-]=* r:|=*'
 
+      curcontext="$oldcontext"
+
       return
     fi
   else
-    compvalues -C _sub_context
-    _sub_context="${oldsc}:${oldsc+${oldsc}-}${_sub_context}"
+    compvalues -C subc
+    curcontext="${oldcontext}:$subc"
   fi
 
-  _tags "${oldsc}:any" arguments || return 1
+  if ! _tags arguments; then
+    curcontext="$oldcontext"
+    return 1
+  fi
 
   _description expl "$descr"
 
@@ -83,6 +89,11 @@ if compvalues -i "$@"; then
   if [[ "$action" = -\>* ]]; then
     compvalues -v val_args
     state="${${action[3,-1]##[ 	]#}%%[ 	]#}"
+    if [[ -n "$usecc" ]]; then
+      curcontext="$subc"
+    else
+      context="$subc"
+    fi
     compstate[restore]=''
     return 1
   else
@@ -131,7 +142,11 @@ if compvalues -i "$@"; then
     fi
   fi
 
+  curcontext="$oldcontext"
+
   [[ nm -ne "$compstate[nmatches]" ]]
 else
+  curcontext="$oldcontext"
+
   return 1;
 fi
diff --git a/Completion/Builtins/_aliases b/Completion/Builtins/_aliases
index a097d020e..78ec59686 100644
--- a/Completion/Builtins/_aliases
+++ b/Completion/Builtins/_aliases
@@ -2,6 +2,6 @@
 
 local expl
 
-_alternative any:argument \
+_alternative \
   'aliases:regular alias:compadd - ${(@k)aliases}' \
   'global-aliases:global alias:compadd - ${(@k)galiases}'
diff --git a/Completion/Builtins/_arrays b/Completion/Builtins/_arrays
index 37eb20bf5..4f67ff08d 100644
--- a/Completion/Builtins/_arrays
+++ b/Completion/Builtins/_arrays
@@ -2,7 +2,5 @@
 
 local expl
 
-_tags any:argument arrays || return 1
-
-_description expl array
-compadd "$expl[@]" - "${(@k)parameters[(R)*array*]}"
+_wanted arrays expl array &&
+    compadd "$expl[@]" - "${(@k)parameters[(R)*array*]}"
diff --git a/Completion/Builtins/_autoload b/Completion/Builtins/_autoload
index 116bb7765..de5a6045d 100644
--- a/Completion/Builtins/_autoload
+++ b/Completion/Builtins/_autoload
@@ -2,7 +2,5 @@
 
 local expl
 
-_tags any:argument functions || return 1
-
-_description expl 'shell function'
-compadd "$expl[@]" - ${^fpath}/*(N:t)
+_wanted functions expl 'shell function' &&
+    compadd "$expl[@]" - ${^fpath}/*(N:t)
diff --git a/Completion/Builtins/_bindkey b/Completion/Builtins/_bindkey
index 31215a576..98459916b 100644
--- a/Completion/Builtins/_bindkey
+++ b/Completion/Builtins/_bindkey
@@ -10,13 +10,9 @@
 local expl
 
 if [[ "$words[2]" = -*[DAN]* || "$words[CURRENT-1]" = -*M ]]; then
-  _tags -M keymaps || return 1
-
-  _description expl keymap
-  compadd "$expl[@]" - "$keymaps[@]"
+  _wanted -C -M keymaps expl keymap &&
+      compadd "$expl[@]" - "$keymaps[@]"
 else
-  _tags any:argument widgets || return 1
-
-  _description expl widget
-  compadd "$expl[@]" -M 'r:|-=* r:|=*' - "${(@k)widgets}"
+  _wanted widgets expl widget &&
+      compadd "$expl[@]" -M 'r:|-=* r:|=*' - "${(@k)widgets}"
 fi
diff --git a/Completion/Builtins/_builtin b/Completion/Builtins/_builtin
index fcb20560f..8d682420a 100644
--- a/Completion/Builtins/_builtin
+++ b/Completion/Builtins/_builtin
@@ -7,8 +7,6 @@ if (( $CURRENT > 2 )); then
 else
   local expl
 
-  _tags any:command commands || return 1
-
-  _description expl 'builtin command'
-  compadd "$expl[@]" "$@" - "${(k@)builtins}"
+  _wanted commands expl 'builtin command' &&
+      compadd "$expl[@]" "$@" - "${(k@)builtins}"
 fi
diff --git a/Completion/Builtins/_cd b/Completion/Builtins/_cd
index 26846fde2..2203dcf15 100644
--- a/Completion/Builtins/_cd
+++ b/Completion/Builtins/_cd
@@ -22,10 +22,8 @@ if [[ CURRENT -eq 3 ]]; then
   rep=(${~PWD/$words[2]/*}~$PWD(-/N))
   # Now remove all the common parts of $PWD and the completions from this
   rep=(${${rep#${PWD%%$words[2]*}}%${PWD#*$words[2]}})
-  if (( $#rep )) && _tags replacement strings; then
-    _description expl replacement
-    compadd "$expl[@]" $rep
-  fi
+  (( $#rep )) && _wanted -C replacement strings expl replacement &&
+      compadd "$expl[@]" $rep
 elif _popd || [[ $PREFIX != (\~|/|./|../)* && $#cdpath -ne 0 ]]; then
   local tdir tdir2
 
diff --git a/Completion/Builtins/_command b/Completion/Builtins/_command
index 23995dbbe..1cfa6add9 100644
--- a/Completion/Builtins/_command
+++ b/Completion/Builtins/_command
@@ -6,8 +6,6 @@ if [[ CURRENT -ge 3 ]]; then
 else
   local expl
 
-  _tags any:command commands || return 1
-
-  _description expl 'external command'
-  compadd "$expl[@]" "$@" - "${(k@)commands}"
+  _wanted commands expl 'external command' &&
+      compadd "$expl[@]" "$@" - "${(k@)commands}"
 fi
diff --git a/Completion/Builtins/_compdef b/Completion/Builtins/_compdef
index df25d44de..7b4b0cb35 100644
--- a/Completion/Builtins/_compdef
+++ b/Completion/Builtins/_compdef
@@ -12,16 +12,12 @@ while [[ $words[base] = -* ]]; do
 done
 
 if [ "$delete" ]; then
-  _tags any:argument commands || return 1
-
-  _description expl 'completed command'
-  compadd "$expl[@]" - ${(k)_comps}
+  _wanted commands expl 'completed command' &&
+      compadd "$expl[@]" - ${(k)_comps}
 else
   if [[ CURRENT -eq base ]]; then
-    _tags any:argument functions || return 1
-
-    _description expl 'completion function'
-    compadd "$expl[@]" - ${^fpath:/.}/_(|*[^~])(N:t)
+    _wanted functions expl 'completion function' &&
+        compadd "$expl[@]" - ${^fpath:/.}/_(|*[^~])(N:t)
   else
     _command_names
   fi
diff --git a/Completion/Builtins/_disable b/Completion/Builtins/_disable
index 33c202864..7c17c9939 100644
--- a/Completion/Builtins/_disable
+++ b/Completion/Builtins/_disable
@@ -12,4 +12,4 @@ args=()
 [[ "$prev" != -* ]]  &&
     tags=( 'builtins:builtin command:compadd - ${(@k)builtins} )
 
-_alternative any "$args[@]"
+_alternative "$args[@]"
diff --git a/Completion/Builtins/_echotc b/Completion/Builtins/_echotc
index 2193261a1..06b78408d 100644
--- a/Completion/Builtins/_echotc
+++ b/Completion/Builtins/_echotc
@@ -2,8 +2,7 @@
 
 local expl
 
-_tags any:argument capabilities || return 1
-
-_description expl 'terminal capability'
-compadd "$expl[@]" \
-        al dc dl do le up al bl cd ce cl cr dc dl do ho is le ma nd nl se so up
+_wanted capabilities expl 'terminal capability' &&
+    compadd "$expl[@]" \
+            al dc dl do le up al bl cd ce cl cr \
+            dc dl do ho is le ma nd nl se so up
diff --git a/Completion/Builtins/_enable b/Completion/Builtins/_enable
index ae2bdc38c..5cb07539e 100644
--- a/Completion/Builtins/_enable
+++ b/Completion/Builtins/_enable
@@ -12,4 +12,4 @@ args=()
 [[ "$prev" != -* ]]  &&
     tags=( 'builtins:builtin command:compadd - ${(@k)dis_builtins} )
 
-_alternative any "$args[@]"
+_alternative "$args[@]"
diff --git a/Completion/Builtins/_functions b/Completion/Builtins/_functions
index 9e6925ce7..98b21da68 100644
--- a/Completion/Builtins/_functions
+++ b/Completion/Builtins/_functions
@@ -2,7 +2,5 @@
 
 local expl
 
-_tags argument:any functions || return 1
-
-_description expl 'shell function'
-compadd "$expl[@]" "$@" - "${(k@)functions}"
+_wanted functions expl 'shell function' &&
+    compadd "$expl[@]" "$@" - "${(k@)functions}"
diff --git a/Completion/Builtins/_hash b/Completion/Builtins/_hash
index 24a9964b9..e5f182528 100644
--- a/Completion/Builtins/_hash
+++ b/Completion/Builtins/_hash
@@ -4,23 +4,15 @@ local expl
 
 if [[ "$words[2]" = -*d* ]]; then
   if compset -P 1 '*\='; then
-    _tags - -d-value files || return 1
-
-    _path_files -g '*(-/)'
+    _wanted -C -d-value files && _path_files -g '*(-/)'
   else
-    _tags - -d named-directories || return 1
-
-    _description expl 'named directory'
-    compadd "$expl[@]" -q -S '=' - "${(@k)nameddirs}"
+    _wanted -C -d named-directories expl 'named directory' &&
+        compadd "$expl[@]" -q -S '=' - "${(@k)nameddirs}"
   fi
 elif compset -P 1 '*\='; then
-  _tags value executables || return 1
-
-  _description expl 'executable file'
-  _files "$expl[@]" -g '*(*)'
+  _wanted -C value values executables expl 'executable file' &&
+      _files "$expl[@]" -g '*(*)'
 else
-  _tags any:argument commands || return 1
-
-  _description expl command
-  compadd "$expl[@]" -q -S '=' - "${(@k)commands}"
+  _wanted -C name commands expl command &&
+      compadd "$expl[@]" -q -S '=' - "${(@k)commands}"
 fi
diff --git a/Completion/Builtins/_kill b/Completion/Builtins/_kill
index e2dc88dac..0fee6dee8 100644
--- a/Completion/Builtins/_kill
+++ b/Completion/Builtins/_kill
@@ -3,11 +3,8 @@
 local list expl
 
 if compset -P 1 -; then
-
-  _tags - -:signal signals || return 1
-
-  _description expl signal
-  compadd "$expl[@]" $signals[1,-3]
+  _wanted -C - expl signal &&
+      compadd "$expl[@]" $signals[1,-3]
 else
-  _alternative argument 'jobs:: _jobs' 'processes:: _pids'
+  _alternative -C argument 'jobs:: _jobs' 'processes:: _pids'
 fi
diff --git a/Completion/Builtins/_limits b/Completion/Builtins/_limits
index 12e90e96a..dae573e03 100644
--- a/Completion/Builtins/_limits
+++ b/Completion/Builtins/_limits
@@ -2,7 +2,5 @@
 
 local expl
 
-_tags any:argument limits || return 1
-
-_description expl 'process limits'
-compadd "$expl[@]" ${${(f)"$(limit)"}%% *}
+_wanted limits expl 'process limits' &&
+    compadd "$expl[@]" ${${(f)"$(limit)"}%% *}
diff --git a/Completion/Builtins/_pids b/Completion/Builtins/_pids
index f96c11e2d..597a19477 100644
--- a/Completion/Builtins/_pids
+++ b/Completion/Builtins/_pids
@@ -3,23 +3,25 @@
 # If given the `-m <pattern>' option, this tries to complete only pids
 # of processes whose command line match the `<pattern>'.
 
-local list expl match desc
+local list expl match desc listargs args
 
-_tags any processes || return 1
+_wanted processes expl 'process ID' || return 1
 
 if [[ "$1" = -m ]]; then
   match="${2}*"
   shift 2
 fi
 
-_description expl 'process ID'
+_style -a ps list-arguments listargs
+_style -a ps arguments args
+(( $#listargs )) || listargs=( "$args[@]" )
 
-if _style processes description yes; then
-  list=("${(@Mr:COLUMNS-1:)${(f@)$(ps ${=compconfig[ps_listargs]:-$=compconfig[ps_args]} 2>/dev/null)}[2,-1]:#[ 	]#${PREFIX}[0-9]#${SUFFIX}[ 	]*${~match}}")
+if _style processes description; then
+  list=("${(@Mr:COLUMNS-1:)${(f@)$(ps $listargs 2>/dev/null)}[2,-1]:#[ 	]#${PREFIX}[0-9]#${SUFFIX}[ 	]*${~match}}")
   desc=(-ld list)
 else
   desc=()
 fi
 
 compadd "$expl[@]" "$@" "$desc[@]" - \
-  ${${${(M)${(f)"$(ps $=compconfig[ps_args] 2>/dev/null)"}[2,-1]:#*${~match}}## #}%% *}
+    ${${${(M)${(f)"$(ps $args 2>/dev/null)"}[2,-1]:#*${~match}}## #}%% *}
diff --git a/Completion/Builtins/_popd b/Completion/Builtins/_popd
index 5e4910f48..9b9b0d048 100644
--- a/Completion/Builtins/_popd
+++ b/Completion/Builtins/_popd
@@ -7,14 +7,13 @@
 
 setopt extendedglob nonomatch
 
-_tags any directory-stack || return 1
+local expl list lines revlines disp
 
-! _style directory-stack prefix-needed yes ||
-    [[ $PREFIX = [-+]* ]] || return 1
+_wanted directory-stack -V expl 'directory stack' || return 1
 
-local expl list lines revlines disp
+! _style directory-stack prefix-needed || [[ $PREFIX = [-+]* ]] || return 1
 
-if _style directory-stack description yes; then
+if _style directory-stack description; then
   # get the list of directories with their canonical number
   # and turn the lines into an array, removing the current directory
   lines=("${PWD}" "${dirstack[@]}")
@@ -39,5 +38,4 @@ else
   disp=()
 fi
 
-_description -V expl 'directory stack index'
 compadd "$expl[@]" "$@" -qS/ "$disp[@]" -Q - "$list[@]"
diff --git a/Completion/Builtins/_sched b/Completion/Builtins/_sched
index d3245f7ef..6a327e891 100644
--- a/Completion/Builtins/_sched
+++ b/Completion/Builtins/_sched
@@ -4,15 +4,14 @@ local expl lines disp
 
 if [[ CURRENT -eq 2 ]]; then
   if compset -P -; then
-    _tags - - entries || return 1
+    _wanted -C - entries expl 'scheduled jobs' || return 1
 
     lines=(${(f)"$(sched)"})
-    if _style entries description yes; then
+    if _style entries description; then
       disp=( -ld lines )
     else
       disp=()
     fi
-    _description expl 'scheduled jobs'
     [[ -z $lines ]] || compadd "$expl[@]" "$disp[@]" - {1..$#lines}
   else
     _message 'time specification'
diff --git a/Completion/Builtins/_stat b/Completion/Builtins/_stat
index 3f1b62ca3..75370f991 100644
--- a/Completion/Builtins/_stat
+++ b/Completion/Builtins/_stat
@@ -5,11 +5,14 @@ local expl
 if [[ "$words[CURRENT-1]" = -[AH] ]]; then
   _arrays
 else
-  _tags any:argument elements || return 1
+  _tags elements files || return 1
 
-  _description expl 'inode element'
-  [[ "$PREFIX[1]" = + ]] &&
-      compadd "$expl[@]" - +device +inode +mode +nlink +uid +gid +rdev +size \
-                           +atime +mtime +ctime +blksize +block +link
-  _files
+  while _tags; do
+    _requested elements expl 'inode element' &&
+        { ! _style elements prefix-needed || [[ "$PREFIX[1]" = + ]] } &&
+        compadd "$expl[@]" - +device +inode +mode +nlink +uid +gid +rdev \
+                             +size +atime +mtime +ctime +blksize +block +link
+    fi
+    _requested files && _files
+  done
 fi
diff --git a/Completion/Builtins/_trap b/Completion/Builtins/_trap
index 5dbb2d284..bbbef1c55 100644
--- a/Completion/Builtins/_trap
+++ b/Completion/Builtins/_trap
@@ -6,8 +6,5 @@ if [[ CURRENT -eq 2 ]]; then
   compset -q
   _normal
 else
-  _tags any:argument signals || return 1
-
-  _description expl signal
-  compadd "$expl[@]" - "$signals[@]"
+  _wanted signals expl signal && compadd "$expl[@]" - "$signals[@]"
 fi
diff --git a/Completion/Builtins/_unhash b/Completion/Builtins/_unhash
index 6ccbc21a4..7a0d0c25a 100644
--- a/Completion/Builtins/_unhash
+++ b/Completion/Builtins/_unhash
@@ -11,4 +11,4 @@ args=()
 [[ "$fl != -* ]] &&
     args=( 'commands:: _command_names -e' )
 
-_alternative any:argument "$args[@]"
+_alternative "$args[@]"
diff --git a/Completion/Builtins/_vars b/Completion/Builtins/_vars
index 43cdf5d2c..2758f3de2 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 "$expl[@]" $addclose - ${(kP)var}
   fi
 else
-  _tags any parameters || return 1
-
-  _parameters
+  _tags parameters && _parameters
 fi
diff --git a/Completion/Builtins/_wait b/Completion/Builtins/_wait
index 04ad5e873..28fdb7985 100644
--- a/Completion/Builtins/_wait
+++ b/Completion/Builtins/_wait
@@ -1,3 +1,3 @@
 #compdef wait
 
-_alternative argument:any 'jobs:: _jobs' 'processes:: _pids'
+_alternative 'jobs:: _jobs' 'processes:: _pids'
diff --git a/Completion/Builtins/_which b/Completion/Builtins/_which
index 6e9e0a460..5b1427962 100644
--- a/Completion/Builtins/_which
+++ b/Completion/Builtins/_which
@@ -4,7 +4,7 @@ local args
 
 args=( "$@" )
 
-_alternative -O args any:argument \
+_alternative -O args \
   'commands:external command:compadd - ${(k@)commands}' \
   'builtins:builtin command:compadd - ${(k@)builtins}' \
   'functions:shell function:compadd - ${(k@)functions}' \
diff --git a/Completion/Builtins/_zftp b/Completion/Builtins/_zftp
index 2728d1747..8407de30e 100644
--- a/Completion/Builtins/_zftp
+++ b/Completion/Builtins/_zftp
@@ -4,7 +4,7 @@
 # zfcd_match and zfget_match (also used for old-style completion)
 # need to be installed for remote file and directory completion to work.
 
-emulate -L zsh
+# emulate -L zsh
 
 # Don't try any more completion after this.
 _compskip=all
@@ -13,12 +13,10 @@ local subcom expl
 
 if [[ $words[1] = zftp ]]; then
   if [[ $CURRENT -eq 2 ]]; then
-    _tags command commands || return 1
-
-    _description expl sub-command
-    compadd "$expl[@]" open params user login type ascii binary mode put \
-      putat get getat append appendat ls dir local remote mkdir rmdir \
-      session rmsession
+    _wanted commands expl sub-command &&
+        compadd "$expl[@]" open params user login type ascii binary mode put \
+          putat get getat append appendat ls dir local remote mkdir rmdir \
+          session rmsession
     return
   fi
   subcom=$words[2]
@@ -29,28 +27,27 @@ fi
 case $subcom in
   *(cd|ls|dir))
     # complete remote directories
-    _tags "$subcom" directories && zfcd_match $PREFIX $SUFFIX
+    _tags -C "$subcom" directories && zfcd_match $PREFIX $SUFFIX
     ;;
 
   *(get(|at)|gcp|delete|remote))
     # complete remote files
-    _tags "$subcom" files && zfget_match $PREFIX $SUFFIX
+    _tags -C "$subcom" files && zfget_match $PREFIX $SUFFIX
     ;;
 
   *(put(|at)|pcp))
     # complete local files
-    _tags "$subcom" files && _files
+    _tags -C "$subcom" files && _files
     ;;
 
   *(open|anon|params))
     # complete hosts:  should do cleverer stuff with user names
-    _tags "$subcom" hosts && _hosts
+    _tags -C "$subcom" hosts && _hosts
     ;;
 
   *(goto|mark))
     # complete bookmarks.  First decide if ncftp mode is go.
-    _tags "$subcom" bookmarks || return 1
-    _description expl bookmark
+    _wanted -C "$subcom" bookmarks expl bookmark || return 1
     if [[ $words[2] = -*n* ]]; then
       if [[ -f ~/.ncftp/bookmarks ]]; then
         compadd "$expl[@]" - $(awk -F, 'NR > 2 { print $1 }' ~/.ncftp/bookmarks)
@@ -64,16 +61,15 @@ case $subcom in
 
   *session)
     # complete sessions, excluding the current one.
-    _tags "$subcom" sessions || return 1
-    _description expl 'another FTP session'
-    compadd "$expl[@]" - ${$(zftp session):#$ZFTP_SESSION}
+    _wanted -C "$subcom" sessions expl 'another FTP session' &&
+        compadd "$expl[@]" - ${$(zftp session):#$ZFTP_SESSION}
     ;;
 
   *transfer)
     # complete arguments like sess1:file1 sess2:file2
     if [[ $PREFIX = *:* ]]; then
       # complete file in the given session
-      _tags "$subcom" files || return 1
+      _tags -C "$subcom" files || return 1
       local sess=${PREFIX%%:*} oldsess=$ZFTP_SESSION
       compset -p $(( $#sess + 1 ))
       [[ -n $sess ]] && zftp session $sess
@@ -81,9 +77,8 @@ case $subcom in
       [[ -n $sess && -n $oldsess ]] && zftp session $oldsess
     else
       # note here we can complete the current session
-      _tags "$subcom" sessions || return 1
-      _description expl 'FTP session'
-      compadd "$expl[@]" -S : - $(zftp session)
+      _wanted -C "$subcom" sessions expl 'FTP session' &&
+          compadd "$expl[@]" -S : - $(zftp session)
     fi
     ;;
 
diff --git a/Completion/Builtins/_zle b/Completion/Builtins/_zle
index 21997ef62..8e8017817 100644
--- a/Completion/Builtins/_zle
+++ b/Completion/Builtins/_zle
@@ -3,11 +3,8 @@
 local expl
 
 if [[ "$words[2]" = -N && CURRENT -eq 3 ]]; then
-  _tags any:argument functions || return 1
-  _description expl 'widget shell function'
-  compadd "$expl[@]" "$@" - "${(k@)functions}" && ret=0
+  _wanted -C -N functions expl 'widget shell function' &&
+      compadd "$expl[@]" "$@" - "${(k@)functions}" && ret=0
 else
-  _tags any:argument widgets || return 1
-  _description expl widget
-  compadd "$expl[@]" - "${(@k)widgets}"
+  _wanted widgets expl widget && compadd "$expl[@]" - "${(@k)widgets}"
 fi
diff --git a/Completion/Builtins/_zmodload b/Completion/Builtins/_zmodload
index 1a1097a7a..bedc4b08f 100644
--- a/Completion/Builtins/_zmodload
+++ b/Completion/Builtins/_zmodload
@@ -3,15 +3,11 @@
 local fl="$words[2]" expl
 
 if [[ "$fl" = -*(a*u|u*a)* || "$fl" = -*a* && CURRENT -ge 4 ]]; then
-  _tags any:argument builtins || return 1
-  _description expl 'builtin command'
-  compadd "$expl[@]" "$@" - "${(k@)builtins}" && ret=0
+  _wanted builtins expl 'builtin command' &&
+      compadd "$expl[@]" "$@" - "${(k@)builtins}"
 elif [[ "$fl" = -*u* ]]; then
-  _tags any:argument modules || return 1
-  _description expl module
-  compadd "$expl[@]" - "${(@k)modules}"
+  _wanted modules expl module && compadd "$expl[@]" - "${(@k)modules}"
 else
-  _tags any:argument files || return 1
-  _description expl 'module file'
-  compadd "$expl[@]" - ${^module_path}/*.s[ol](N:t:r)
+  _wanted files expl 'module file' &&
+      compadd "$expl[@]" - ${^module_path}/*.s[ol](N:t:r)
 fi
diff --git a/Completion/Commands/_complete_help b/Completion/Commands/_complete_help
new file mode 100644
index 000000000..cfefdcf90
--- /dev/null
+++ b/Completion/Commands/_complete_help
@@ -0,0 +1,35 @@
+#compdef -k complete-word \C-xh
+
+_complete_help() {
+  local _sort_tags=_help_sort_tags text i
+  typeset -A help_tags
+  typeset -U help_contexts
+
+  help_contexts=()
+
+  compadd() { return 1 }
+
+  _main_complete
+
+  unfunction compadd
+
+  for i in "$help_contexts[@]"; do
+    text="${text}
+tags in context \`${i}': ${help_tags[$i]}"
+  done
+
+  compstate[list]=list
+  compstate[force_list]=yes
+  compstate[insert]=''
+
+  compadd -UX "$text[2,-1]" -n ''
+}
+
+_help_sort_tags() {
+  help_contexts=( "$help_contexts[@]" "$curcontext" )
+  help_tags[$curcontext]="${help_tags[$curcontext]}
+    ${argv}"
+  comptry "$@"
+}
+
+_complete_help "$@"
diff --git a/Completion/Commands/_correct_word b/Completion/Commands/_correct_word
index d0abcd4fe..e0fee1fff 100644
--- a/Completion/Commands/_correct_word
+++ b/Completion/Commands/_correct_word
@@ -7,19 +7,8 @@
 # If configurations keys with the prefix `correctword_' are
 # given they override those starting with `correct_'.
 
-local oca="$compconfig[correct_accept]"
-local oco="$compconfig[correct_original]"
-local ocp="$compconfig[correct_prompt]"
-local oci="$compconfig[correct_insert]"
+local curcontext="$curcontext"
 
-compconfig[correct_accept]="${compconfig[correctword_accept]-6n}"
-compconfig[correct_original]="${compconfig[correctword_original]-$oco}"
-compconfig[correct_prompt]="${compconfig[correctword_prompt]-$ocp}"
-compconfig[correct_insert]="${compconfig[correctword_insert]}"
+[[ -z "$curcontext" ]] && curcontext=":correct-word"
 
 _main_complete _correct
-
-compconfig[correct_accept]="$oca"
-compconfig[correct_original]="$oco"
-compconfig[correct_prompt]="$ocp"
-compconfig[correct_insert]="$oci"
diff --git a/Completion/Commands/_expand_word b/Completion/Commands/_expand_word
index d8f5f42f8..b4e22de48 100644
--- a/Completion/Commands/_expand_word
+++ b/Completion/Commands/_expand_word
@@ -5,25 +5,8 @@
 # If configurations keys with the prefix `expandword_' are
 # given they override those starting with `expand_'.
 
-local oes="$compconfig[expand_substitute]"
-local oeg="$compconfig[expand_glob]"
-local oem="$compconfig[expand_menu]"
-local oeo="$compconfig[expand_original]"
-local oep="$compconfig[expand_prompt]"
-local oec="$compconfig[expand_completions]"
+local curcontext="$curcontext"
 
-compconfig[expand_substitute]="${compconfig[expandword_substitute]}"
-compconfig[expand_glob]="${compconfig[expandword_glob]-$oeg}"
-compconfig[expand_menu]="${compconfig[expandword_menu]-$oem}"
-compconfig[expand_original]="${compconfig[expandword_original]-$oeo}"
-compconfig[expand_prompt]="${compconfig[expandword_prompt]-$oep}"
-compconfig[expand_completions]="${compconfig[expandword_completions]-$oec}"
+[[ -z "$curcontext" ]] && curcontext=":expand-word"
 
 _main_complete _expand
-
-compconfig[expand_substitute]="$oes"
-compconfig[expand_glob]="$oeg"
-compconfig[expand_menu]="$oem"
-compconfig[expand_original]="$oeo"
-compconfig[expand_prompt]="$oep"
-compconfig[expand_completions]="$oec"
diff --git a/Completion/Commands/_history_complete_word b/Completion/Commands/_history_complete_word
index 1112339af..ee6ac2de2 100644
--- a/Completion/Commands/_history_complete_word
+++ b/Completion/Commands/_history_complete_word
@@ -7,17 +7,17 @@
 #
 # Available configuration keys:
 #
-#   history_list -- display lists of available matches
-#   history_stop -- prevent looping at beginning and end of matches
-#                   during menu-completion
-#   history_sort -- sort matches lexically (default is to sort by age)
-#   history_remove_all_dups --
-#                   remove /all/ duplicate matches rather than just
-#                   consecutives
+#   :history-entries:list -- display lists of available matches
+#   :history-entries:stop -- prevent looping at beginning and end of matches
+#                            during menu-completion
+#   :history-entries:sort -- sort matches lexically (default is to sort by age)
+#   :history-entries:remove-all-dups --
+#                            remove /all/ duplicate matches rather than just
+#                            consecutives
 #
 
 _history_complete_word () {
-  local expl direction
+  local expl direction stop
 
   if [[ $WIDGET = *newer ]]; then
     direction=older
@@ -25,16 +25,19 @@ _history_complete_word () {
     direction=newer
   fi
 
-  [[ -z "$compconfig[history_list]" ]] && compstate[list]=''
+  _style -s history-entries stop stop
+
+  _style history-entries list || compstate[list]=''
 
   if [[ -n "$compstate[old_list]" &&
-    ( -n "$compconfig[history_stop]" || "$compstate[insert]" = menu ) ]]; then
+        ( -n "$stop" || "$compstate[insert]" = menu ) ]] ; then
     # array of matches is newest -> oldest (reverse of history order)
     if [[ "$direction" == 'older' ]]; then
       if [[ compstate[old_insert] -eq $_hist_menu_length ||
             "$_hist_stop" == 'oldest' ]]; then
         _hist_stop='oldest'
-        [[ "$compconfig[history_stop]" = verbose ]] &&
+	_style history-entries 
+        [[ "$stop" = verbose ]] &&
           _message 'beginning of history reached'
       elif [[ "$_hist_stop" == 'newest' ]]; then
         zle -Rc
@@ -46,8 +49,7 @@ _history_complete_word () {
     elif [[ "$direction" == 'newer' ]]; then
       if [[ compstate[old_insert] -eq 1 || "$_hist_stop" == 'newest' ]]; then
         _hist_stop='newest'
-        [[ "$compconfig[history_stop]" = verbose ]] &&
-          _message 'end of history reached'
+        [[ "$stop" = verbose ]] && _message 'end of history reached'
       elif [[ "$_hist_stop" == 'oldest' ]]; then
         zle -Rc
         _history_complete_word_gen_matches
@@ -66,14 +68,14 @@ _history_complete_word () {
 }
 
 _history_complete_word_gen_matches () {
-  if [[ -n "$compconfig[history_list]" ]]; then
-    if [[ -n "$compconfig[history_sort]" ]]; then
+  if _style history-entries list; then
+    if _style history-entries sort; then
       _description expl 'history word'
     else
       _description -V expl 'history word'
     fi
   else
-    if [[ -n "$compconfig[history_sort]" ]]; then
+    if _style history-entries sort; then
       expl=()
     else
       expl=('-V' '')
@@ -83,7 +85,7 @@ _history_complete_word_gen_matches () {
   [[ -n "$_hist_stop" ]] && PREFIX="$_hist_old_prefix"
 
   local rem_dups
-  if [[ -n "$compconfig[history_remove_all_dups]" ]]; then
+  if _style history-entries remove-all-dups; then
     rem_dups=''
   else
     rem_dups='-1'
diff --git a/Completion/Commands/_read_comp b/Completion/Commands/_read_comp
index 8a46d8af2..a956c65f7 100644
--- a/Completion/Commands/_read_comp
+++ b/Completion/Commands/_read_comp
@@ -22,8 +22,8 @@
 # Global variables used:
 #  _read_comp         Last completion string read from user
 
-emulate -L zsh
-setopt extendedglob nobadpattern # xtrace promptsubst
+# emulate -L zsh
+setopt localoptions extendedglob nobadpattern # xtrace promptsubst
 # local PS4='%N:%i:$((#key))> '
 
 # Took me ages to work this out.  If we're not on the first global
diff --git a/Completion/Core/.distfiles b/Completion/Core/.distfiles
index 63592dfaf..eeac55a97 100644
--- a/Completion/Core/.distfiles
+++ b/Completion/Core/.distfiles
@@ -3,6 +3,6 @@ DISTFILES_SRC='
     _approximate _compalso _complete _correct _description _expand
     _files _list _main_complete _match _menu _multi_parts
     _message _normal _oldlist _options _parameters _path_files
-    _sep_parts _set_options _unset_options
+    _sep_parts _set_options _sort_tags _unset_options
     compdump compinit compinstall
 '
diff --git a/Completion/Core/_alternative b/Completion/Core/_alternative
index f13fc9e5a..76a8380bc 100644
--- a/Completion/Core/_alternative
+++ b/Completion/Core/_alternative
@@ -1,22 +1,23 @@
 #autoload
 
 local tags def expl descr action mesgs nm="$compstack[nmatches]" subopts
+local opt curcontext="$curcontext"
+
+subopts=()
+while getopts 'O:C:' opt; do
+  case "$opt" in
+  O) subopts=( "${(@P)OPTARG}" ) ;;
+  C) curcontext="${curontext}:$OPTARG" ;;
+  esac
+done
 
-if [[ "$1" = -O?* ]]; then
-  subopts=( "${(@P)1[3,-1]}" )
-  shift
-elif [[ "$1" = -O ]]; then
-  subopts=( "${(@P)2}" )
-  shift 2
-else
-  subopts=()
-fi  
+shift OPTIND-1
 
 [[ "$1" = -(|-) ]] && shift
 
 mesgs=()
 
-_tags "$1" "${(@)argv[2,-1]%%:*}"
+_tags "${(@)argv%%:*}"
 
 while _tags; do
   for def; do
diff --git a/Completion/Core/_approximate b/Completion/Core/_approximate
index 235e324f7..910742fee 100644
--- a/Completion/Core/_approximate
+++ b/Completion/Core/_approximate
@@ -7,6 +7,7 @@
 
 local _comp_correct _correct_prompt comax
 local cfgacc cfgorig cfgps cfgins
+local curcontext="$curcontext" oldcontext
 
 # Only if all global matchers have been tried.
 
@@ -16,20 +17,16 @@ local cfgacc cfgorig cfgps cfgins
 
 [[ "${#:-$PREFIX$SUFFIX}" -le 1 ]] && return 1
 
-# Get the configuration values, using either the prefix `correct' or
-# `approximate'.
+# Probably set initial context.
 
-if [[ "$compstate[pattern_match]" = (|\**) ]]; then
-  cfgacc="${compconfig[approximate_accept]:-$compconfig[correct_accept]}"
-  cfgorig="${compconfig[approximate_original]:-$compconfig[correct_original]}"
-  cfgps="${compconfig[approximate_prompt]:-$compconfig[correct_prompt]}"
-  cfgins="${compconfig[approximate_insert]:-$compconfig[correct_insert]}"
-else
-  cfgacc="$compconfig[correct_accept]"
-  cfgorig="$compconfig[correct_original]"
-  cfgps="$compconfig[correct_prompt]"
-  cfgins="$compconfig[correct_insert]"
-fi
+[[ -z "$curcontext" ]] && curcontext=':approximate'
+
+oldcontext="$curcontext"
+
+_style -s '' accept cfgacc
+_style -s '' original cfgorig
+_style -s '' prompt cfgps
+_style -s '' insert cfgins
 
 # Get the number of errors to accept.
 
@@ -86,16 +83,18 @@ _correct_prompt="${cfgps//\\%e/1}"
 [[ -z "$compstate[pattern_match]" ]] && compstate[pattern_match]='*'
 
 while [[ _comp_correct -le comax ]]; do
+  curcontext="${oldcontext}:$_comp_correct"
+
   if _complete; then
     if [[ "$cfgins" = unambig* &&
           "${#compstate[unambiguous]}" -ge "${#:-$PREFIX$SUFFIX}" ]]; then
       compstate[pattern_insert]=unambiguous
     elif [[ compstate[nmatches] -gt 1 || "$cfgorig" = *always* ]]; then
-      local expl
+      local expl format
 
       if [[ "$cfgorig" = *show* ]]; then
-        if [[ -n "$compconfig[description_format]" ]]; then
-	  expl=(-X "${compconfig[description_format]//\\%d/original}")
+        if _style -s descriptions format format; then
+	  expl=(-X "${format//\\%d/original}")
         else
 	  expl=()
         fi
diff --git a/Completion/Core/_complete b/Completion/Core/_complete
index f351c7349..235265326 100644
--- a/Completion/Core/_complete
+++ b/Completion/Core/_complete
@@ -2,16 +2,21 @@
 
 # Generate all possible completions. Note that this is not intended as
 # a normal completion function, but as one possible value for the
-# compconfig[completer] parameter.
+# completer style.
 
-local comp name _tag_context="$_tag_context"
+local comp name curcontext="$curcontext" oldcontext
 
-[[ "$compstate[context]" != command || CURRENT -eq 1 ]] && 
-    _tag_context="-${compstate[context]:s/_/-/}-"
+# Probably set initial context.
+
+[[ -z "$curcontext" ]] && curcontext=':complete'
+
+oldcontext="$curcontext"
 
 # If we have a user-supplied context name, use only that.
 
 if [[ -n "$compcontext" ]]; then
+  curcontext="${curcontext}:$compcontext"
+
   comp="$_comps[$compcontext]"
   [[ -z "$comp" ]] || "$comp"
 
@@ -22,6 +27,7 @@ fi
 
 comp="$_comps[-first-]"
 if [[ ! -z "$comp" ]]; then
+  curcontext="${curcontext}:-first-"
   "$comp"
   if [[ "$_compskip" = all ]]; then
     _compskip=''
@@ -34,12 +40,17 @@ fi
 # For arguments and command names we use the `_normal' function.
 
 if [[ "$compstate[context]" = command ]]; then
+  curcontext="$oldcontext"
   _normal -s
 else
   # Let's see if we have a special completion definition for the other
   # possible contexts.
 
-  comp="$_comps[$_tag_context]"
+  local cname="-${compstate[context]:s/_/-/}-"
+
+  curcontext="${oldcontext}:$cname"
+
+  comp="$_comps[$cname]"
 
   # If not, we use default completion, if any.
 
diff --git a/Completion/Core/_correct b/Completion/Core/_correct
index c9c3d999c..abd70ddeb 100644
--- a/Completion/Core/_correct
+++ b/Completion/Core/_correct
@@ -8,7 +8,11 @@
 # Supported configuration keys are the same as for `_approximate', only
 # starting with `correct'.
 
-local ret=1 opm="$compstate[pattern_match]"
+local ret=1 opm="$compstate[pattern_match]" curcontext="$curcontext"
+
+# Probably set initial context.
+
+[[ -z "$curcontext" ]] && curcontext=':correct'
 
 compstate[pattern_match]='-'
 
diff --git a/Completion/Core/_description b/Completion/Core/_description
index 107be5cd6..8cd9cc2fb 100644
--- a/Completion/Core/_description
+++ b/Completion/Core/_description
@@ -1,6 +1,6 @@
 #autoload
 
-local gropt=-J
+local gropt=-J format
 
 if [[ "$1" = -[VJ]* ]]; then
   gropt="$1"
@@ -9,16 +9,20 @@ fi
 
 _lastdescr=( "$_lastdescr[@]" "$2" )
 
-if [[ -n "$compconfig[group_matches]" ]]; then
-  if [[ -n "$compconfig[description_format]" ]]; then
-    eval "$1=($gropt ${(q)2} -X ${(q)compconfig[description_format]//\\%d/$2})"
+_style -s descriptions format format
+
+if _style matches group; then
+  if [[ -n "$format" ]]; then
+    eval "$1=($gropt ${(q)2} -X ${(q)format//\\%d/$2})"
   else
     eval "$1=($gropt ${(q)2})"
   fi
 else
-  if [[ -n "$compconfig[description_format]" ]]; then
-    eval "$1=(-X ${(q)compconfig[description_format]//\\%d/$2})"
+  if [[ -n "$format" ]]; then
+    eval "$1=(-X ${(q)format//\\%d/$2})"
   else
     eval "$1=()"
   fi
 fi
+
+return 0
diff --git a/Completion/Core/_expand b/Completion/Core/_expand
index df9e0b9ea..97728bd3b 100644
--- a/Completion/Core/_expand
+++ b/Completion/Core/_expand
@@ -7,12 +7,16 @@
 # the expansions done produce no result or do not change the original
 # word from the line.
 
-local exp word="$PREFIX$SUFFIX" group=-V expl expl2 disp
+local exp word="$PREFIX$SUFFIX" group=-V expl expl2 disp orig menu prompt
+local curcontext="$curcontext" expr descr
+
+# Probably set initial context.
+
+[[ -z "$curcontext" ]] && curcontext=':expand'
 
 # First, see if we should insert all *completions*.
 
-if [[ -n "$compconfig[expand_completions]" &&
-      "${(e):-\$[$compconfig[expand_substitute]]}" -eq 1 ]]; then
+if _style -s '' completions expr && [[ "${(e):-\$[$expr]}" -eq 1 ]]; then
   compstate[insert]=all
   return 1
 fi
@@ -28,8 +32,7 @@ exp=("$word")
 # First try substitution. That weird thing spanning multiple lines
 # changes quoted spaces, tabs, and newlines into spaces.
 
-[[ -z "$compconfig[expand_substitute]" ||
-   "${(e):-\$[$compconfig[expand_substitute]]}" -eq 1 ]] &&
+_style -s '' substitute expr && [[ "${(e):-\$[$expr]}" -eq 1 ]] &&
     exp=( "${(e)exp//\\[ 	
 ]/ }" )
 
@@ -39,8 +42,7 @@ exp=("$word")
 
 # Now try globbing.
 
-[[ -z "$compconfig[expand_glob]" ||
-   "${(e):-\$[$compconfig[expand_glob]]}" -eq 1 ]] &&
+_style -s '' glob expr && [[ "${(e):-\$[$expr]}" -eq 1 ]] &&
     exp=( ${~exp}(N) )
 
 # If we don't have any expansions or only one and that is the same
@@ -51,9 +53,14 @@ exp=("$word")
 
 # Get the options for adding the original string and `all'-string.
 
-if [[ "$compconfig[expand_original]" = *show* ]]; then
-  if [[ -n "$compconfig[description_format]" ]]; then
-    expl=(-X "${compconfig[description_format]//\\%d/original}")
+_style -s '' original orig
+_style -s '' menu menu
+_style -s '' prompt prompt
+_style -s descriptions format descr
+
+if [[ "$orig" = *show* ]]; then
+  if [[ -n "$descr" ]]; then
+    expl=(-X "${descr//\\%d/original}")
   else
     expl=()
   fi
@@ -61,11 +68,9 @@ else
   expl=(-n)
 fi
 
-if [[ -n "$compconfig[expand_menu]" &&
-      "$compconfig[expand_menu]" != *only* &&
-      "$compconfig[expand_menu]" = *showall* ]]; then
-  if [[ -n "$compconfig[description_format]" ]]; then
-    expl2=(-ld disp -X "${compconfig[description_format]//\\%d/all words}")
+if [[ -n "$menu" && "$menu" != *only* && "$menu" = *showall* ]]; then
+  if [[ -n "$descr" ]]; then
+    expl2=(-ld disp -X "${descr//\\%d/all words}")
   else
     expl2=(-ld disp )
   fi
@@ -83,7 +88,7 @@ fi
 
 # We have expansions, should we menucomplete them?
 
-if [[ -z "$compconfig[expand_menu]" ]]; then
+if [[ -z "$menu" ]]; then
 
   # No, so if the user only wants a list, we add the strings
   # separately. Otherwise we add the whole array as one string,
@@ -92,14 +97,12 @@ if [[ -z "$compconfig[expand_menu]" ]]; then
   if [[ -z "$compstate[insert]" ]]; then
     compadd -U -V _expand -Q - "$exp[@]"
   else
-    [[ -n "$compconfig[expand_original]" && 
-       "$compconfig[expand_original]" != *last* ]] &&
+    [[ -n "$orig" && "$orig" != *last* ]] &&
         compadd "$expl[@]" -UQ -V _expand_original - "$word"
 
     compadd -UQ -V _expand - "$exp"
 
-    [[ -n "$compconfig[expand_original]" && 
-       "$compconfig[expand_original]" = *last* ]] &&
+    [[ -n "$orig" && "$orig" = *last* ]] &&
         compadd "$expl[@]" -UQ -V _expand_original - "$word"
 
     compstate[insert]=menu
@@ -107,31 +110,27 @@ if [[ -z "$compconfig[expand_menu]" ]]; then
 else
   # Sorting? We just use a different group type then.
 
-  [[ "$compconfig[expand_menu]" = *sort* ]] && group=-J
+  [[ "$menu" = *sort* ]] && group=-J
 
   # Now add the expansion string, probably also adding the original
   # and/or the string containing all expanded string.
 
-  [[ -n "$compconfig[expand_original]" && 
-     "$compconfig[expand_original]" != *last* ]] &&
+  [[ -n "$orig" && "$orig" != *last* ]] &&
       compadd "$expl[@]" -UQ -V _expand_original - "$word"
 
-  [[ $#exp -ne 1 && "$compconfig[expand_menu]" = *last* &&
-     "$compconfig[expand_menu]" != *only* ]] &&
+  [[ $#exp -ne 1 && "$menu" = *last* && "$menu" != *only* ]] &&
       compadd "$expl2[@]" -UQ -V _expand_all - "$exp"
 
-  if [[ -z "$compconfig[expand_prompt]" ]]; then
+  if [[ -z "$prompt" ]]; then
     compadd -UQ $group _expand - "$exp[@]"
   else
-    compadd -UQ -X "${compconfig[expand_prompt]//\\%o/$word}" \
+    compadd -UQ -X "${prompt//\\%o/$word}" \
             $group _expand - "$exp[@]"
   fi
-  [[ $#exp -ne 1 && "$compconfig[expand_menu]" != *last* &&
-     "$compconfig[expand_menu]" != *only* ]] &&
+  [[ $#exp -ne 1 && "$menu" != *last* && "$menu" != *only* ]] &&
       compadd "$expl2[@]" -UQ -V _expand_all - "$exp"
 
-  [[ -n "$compconfig[expand_original]" && 
-     "$compconfig[expand_original]" = *last* ]] &&
+  [[ -n "$orig" && "$orig" = *last* ]] &&
       compadd "$expl[@]" -UQ -V _expand_original - "$word"
 
   compstate[insert]=menu
diff --git a/Completion/Core/_files b/Completion/Core/_files
index 973eea69b..ba5445797 100644
--- a/Completion/Core/_files
+++ b/Completion/Core/_files
@@ -13,9 +13,9 @@ while getopts "P:S:qr:R:W:F:J:V:X:f/g:M:" opt; do
 done
 
 case "$type" in
-file) _tags any all-files                           ;;
-dir)  _tags any directories all-files               ;;
-*)    _tags any globbed-files directories all-files ;;
+file) _tags all-files                           ;;
+dir)  _tags directories all-files               ;;
+*)    _tags globbed-files directories all-files ;;
 esac
 
 while _tags; do
diff --git a/Completion/Core/_list b/Completion/Core/_list
index f0bdda08a..803da2f71 100644
--- a/Completion/Core/_list
+++ b/Completion/Core/_list
@@ -4,11 +4,15 @@
 # insert possible completions only after the list has been shown at
 # least once.
 
-local pre suf
+local pre suf curcontext="$curcontext" expr
+
+# Probably set initial context.
+
+[[ -z "$curcontext" ]] && curcontext=':list'
 
 # Get the strings to compare.
 
-if [[ -z "$compconfig[list_word]" ]]; then
+if _style '' word; then
   pre="$HISTNO$LBUFFER"
   suf="$RBUFFER"
 else
@@ -18,8 +22,8 @@ fi
 
 # Should we only show a list now?
 
-if [[ ( -z "$compconfig[list_condition]" ||
-        "${(e):-\$[$compconfig[list_condition]]}" -eq 1 ) &&
+_style -s '' condition expr
+if [[ ( -z "$expr" || "${(e):-\$[$expr]}" -eq 1 ) &&
       ( "$pre" != "$_list_prefix" || "$suf" != "$_list_suffix" ) ]]; then
 
   # Yes. Tell the completion code about it and save the new values
diff --git a/Completion/Core/_main_complete b/Completion/Core/_main_complete
index f9a8a19ad..ba31399b3 100644
--- a/Completion/Core/_main_complete
+++ b/Completion/Core/_main_complete
@@ -17,10 +17,9 @@
 # state than the global one for which you are completing.
 
 
-local comp post ret=1 _compskip _prio_num=1 _tag_context _cur_contexts
-local context state line opt_args val_args
+local comp post ret=1 _compskip _prio_num=1 _cur_context format
+local context state line opt_args val_args curcontext
 typeset -U _offered_tags _tried_tags _failed_tags _used_tags _unused_tags
-typeset -A _prio_names _prio_contexts _cur_tags _tag_contexts
 
 _offered_tags=()
 _tried_tags=()
@@ -42,7 +41,12 @@ fi
 
 # Get the names of the completers to use in the positional parameters.
 
-(( $# )) || set ${(s.:.)compconfig[completer]}
+if (( ! $# )); then
+  local tmp
+
+  _style -a '' completer tmp
+  set -- "$tmp[@]"
+fi
 
 # And now just call the completer functions defined.
 
@@ -66,9 +70,12 @@ done
 comppostfuncs=()
 
 _lastdescr=( "\`${(@)^_lastdescr:#}'" )
+
+_style -s warnings format format
+
 if [[ compstate[nmatches] -eq 0 &&
       compstate[matcher] -eq compstate[total_matchers] &&
-      -n "$compconfig[warning_format]" && $#_lastdescr -ne 0 ]]; then
+      -n "$format" && $#_lastdescr -ne 0 ]]; then
   local str
 
   compstate[list]=list
@@ -81,10 +88,10 @@ if [[ compstate[nmatches] -eq 0 &&
   *) str="${(j:, :)_lastdescr[1,-2]}, or $_lastdescr[-1]";;
   esac
 
-  compadd -UX "${compconfig[warning_format]//\\%d/$str}" -n ''
+  compadd -UX "${format//\\%d/$str}" -n ''
 fi
 
-[[ "$compconfig[last_prompt]" = always ]] && compstate[last_prompt]=yes
+_style '' last-prompt always && compstate[last_prompt]=yes
 
 _lastcomp=( "${(@kv)compstate}" )
 _lastcomp[completer]="$comp"
diff --git a/Completion/Core/_match b/Completion/Core/_match
index f4e5fc0ee..35d7c2ecb 100644
--- a/Completion/Core/_match
+++ b/Completion/Core/_match
@@ -1,7 +1,7 @@
 #autoload
 
 # This is intended to be used as a completer function after the normal
-# completer as in: `compconf completer=_complete:_match'.
+# completer as in: `compstyle "*" completer _complete _match'.
 # It temporarily switches on pattern matching, allowing you to try 
 # completion on patterns without having to setopt glob_complete.
 #
@@ -9,7 +9,8 @@
 # expand-or-complete function because otherwise the pattern will
 # be expanded using globbing.
 
-local tmp opm="$compstate[pattern_match]" ret=0
+local tmp opm="$compstate[pattern_match]" ret=0 curcontext="$curcontext"
+local orig ins
 
 # Do nothing if we don't have a pattern or there are still global
 # match specifications to try.
@@ -18,9 +19,16 @@ tmp="${${:-$PREFIX$SUFFIX}#[~=]}"
 [[ "$tmp:q" = "$tmp" ||
    compstate[matcher] -ne compstate[total_matchers] ]] && return 1
 
+# Probably set initial context.
+
+[[ -z "$curcontext" ]] && curcontext=':match'
+
+_style -s '' original orig
+_style -s '' insert ins
+
 # Try completion without inserting a `*'?
 
-if [[ -n "$compconfig[match_original]" ]]; then
+if [[ -n "$orig" ]]; then
   compstate[matcher]=-1
   compstate[pattern_match]='-'
   _complete && ret=1
@@ -28,7 +36,7 @@ if [[ -n "$compconfig[match_original]" ]]; then
   compstate[matcher]="$compstate[total_matchers]"
 
   if (( ret )); then
-    [[ "$compconfig[match_insert]" = unambig* &&
+    [[ "$ins" = unambig* &&
        $#compstate[unambiguous] -ge ${#:-${PREFIX}${SUFFIX}} ]] && 
         compstate[pattern_insert]=unambiguous
     return 0
@@ -37,7 +45,7 @@ fi
 
 # No completion with inserting `*'?
 
-[[ "$compconfig[match_original]" = only ]] && return 1
+[[ "$orig" = only ]] && return 1
 
 compstate[matcher]=-1
 compstate[pattern_match]='*'
@@ -45,7 +53,7 @@ _complete && ret=1
 compstate[pattern_match]="$opm"
 compstate[matcher]="$compstate[total_matchers]"
 
-[[ ret -eq 1 && "$compconfig[match_insert]" = unambig* &&
+[[ ret -eq 1 && "$ins" = unambig* &&
    $#compstate[unambiguous] -ge ${#:-${PREFIX}${SUFFIX}} ]] && 
     compstate[pattern_insert]=unambiguous
 
diff --git a/Completion/Core/_menu b/Completion/Core/_menu
index 4cbda4e14..e9558fe05 100644
--- a/Completion/Core/_menu
+++ b/Completion/Core/_menu
@@ -1,10 +1,16 @@
 #autoload
 
+local curcontext="$curcontext"
+
+# Probably set initial context.
+
+[[ -z "$curcontext" ]] && curcontext=':menu'
+
 # This completer is an example showing how menucompletion can be
 # implemented with the new completion system.
 # Use this one before the normal _complete completer, as in:
 #
-#   compconf completer=_menu:_complete
+#   compstyle "*" completer _menu _complete
 
 if [[ -n "$compstate[old_list]" ]]; then
 
diff --git a/Completion/Core/_message b/Completion/Core/_message
index ee869d33b..5c5c42e06 100644
--- a/Completion/Core/_message
+++ b/Completion/Core/_message
@@ -2,9 +2,9 @@
 
 local format
 
-_tags any messages || return 1
+_tags messages || return 1
 
-format="${compconfig[message_format]:-$compconfig[description_format]}"
+_style -s messages format format || _style -s descriptions format format
 
 if [[ -n "$format" ]]; then
   if [[ $compstate[nmatches] -eq 0 ]]; then
diff --git a/Completion/Core/_normal b/Completion/Core/_normal
index 5d0a18406..f31e7e6fc 100644
--- a/Completion/Core/_normal
+++ b/Completion/Core/_normal
@@ -1,7 +1,7 @@
 #autoload
 
 local comp command cmd1 cmd2 pat val name i ret=1 _compskip="$_compskip"
-local _sub_context
+local curcontext="$curcontext"
 
 # If we get the option `-s', we don't reset `_compskip'. This ensures
 # that a value set in the function for the `-first-' context is kept,
@@ -16,19 +16,24 @@ local _sub_context
 
 command="$words[1]"
 if [[ CURRENT -eq 1 ]]; then
+  curcontext="${curcontext}:-command-"
+
   comp="$_comps[-command-]"
   [[ -z "$comp" ]] || "$comp" && ret=0
 
   return ret
-elif [[ "$command[1]" == '=' ]]; then
-  eval cmd1\=$command
-  cmd2="$command[2,-1]"
-elif [[ "$command" == */* ]]; then
-  cmd1="$command"
-  cmd2="${command:t}"
 else
-  cmd1="$command"
-  cmd2="$commands[$command]"
+  if [[ "$command[1]" == '=' ]]; then
+    eval cmd1\=$command
+    cmd2="$command[2,-1]"
+  elif [[ "$command" == */* ]]; then
+    cmd1="$command"
+    cmd2="${command:t}"
+  else
+    cmd1="$command"
+    cmd2="$commands[$command]"
+  fi
+  curcontext="${curcontext}:${cmd1}"
 fi
 
 # See if there are any matching pattern completions.
diff --git a/Completion/Core/_oldlist b/Completion/Core/_oldlist
index 2efc08119..2408613da 100644
--- a/Completion/Core/_oldlist
+++ b/Completion/Core/_oldlist
@@ -1,18 +1,26 @@
 #autoload
 
+local curcontext="$curcontext" list menu
+
+# Probably set initial context.
+
+[[ -z "$curcontext" ]] && curcontext=':oldlist'
+
+_style -s '' list list
+_style -s '' menu menu
+
 # If this is a listing widget and there is already an old list,
-# and either the compconfig key oldlist_list is `always', or it is not `never'
+# and either the style :oldlist:list is `always', or it is not `never'
 # and the list is not already shown, then use the existing list for listing
 # (even if it was generated by another widget).
 # Do this also if there is an old list and it was generated by the
 # completer named by the oldlist_list key.
-if [[ -n $compstate[old_list] && $compconfig[oldlist_list] != never ]]; then
-  if [[ $WIDGET = *list* &&
-        ( $compconfig[oldlist_list] = always ||
-	  $compstate[old_list] != shown ) ]]; then
+
+if [[ -n $compstate[old_list] && $list != never ]]; then
+  if [[ $WIDGET = *list* && ( $list = always || $list != shown ) ]]; then
     compstate[old_list]=keep
     return 0
-  elif [[ $compconfig[oldlist_list] = *${_lastcomp[completer]}* ]]; then
+  elif [[ $list = *${_lastcomp[completer]}* ]]; then
     [[ "$_lastcomp[insert]" = unambig* ]] && compstate[to_end]=single
     compstate[old_list]=keep
     if [[ -o automenu ]]; then
@@ -25,16 +33,16 @@ if [[ -n $compstate[old_list] && $compconfig[oldlist_list] != never ]]; then
 fi
 
 # If this is a completion widget, and we have a completion inserted already,
-# and the compconfig key oldlist_menu is not never, then we cycle through the
+# and the style :oldlist:menu is not never, then we cycle through the
 # existing list (even if it was generated by another widget).
 
-if [[ $compconfig[oldlist_menu] = verbose &&
+if [[ $menu = verbose &&
       $LASTWIDGET = _verbose_list && $WIDGET != _verbose_list &&
       -z $compstate[old_insert] &&
       -n $compstate[old_list] ]]; then
   compstate[old_list]=keep
 elif [[ $WIDGET = *complete(|-prefix|-word) &&
-      $compconfig[oldlist_menu] != (never|verbose) ]]; then
+        $menu != (never|verbose) ]]; then
   if [[ -n $compstate[old_insert] ]]; then
     compstate[old_list]=keep
     if [[ $WIDGET = *reverse* ]]; then
diff --git a/Completion/Core/_options b/Completion/Core/_options
index 0dd92cf69..8664e239e 100644
--- a/Completion/Core/_options
+++ b/Completion/Core/_options
@@ -4,8 +4,6 @@
 
 local expl
 
-_tags any zsh-options || return 1
-
-_description expl 'zsh option'
-compadd "$expl[@]" "$@" -M 'L:|[nN][oO]= M:_= M:{A-Z}={a-z}' - \
-    "${(@k)options}"
+_wanted zsh-options expl 'zsh option' &&
+    compadd "$expl[@]" "$@" -M 'L:|[nN][oO]= M:_= M:{A-Z}={a-z}' - \
+        "${(@k)options}"
diff --git a/Completion/Core/_parameters b/Completion/Core/_parameters
index da479097e..3735702df 100644
--- a/Completion/Core/_parameters
+++ b/Completion/Core/_parameters
@@ -5,16 +5,13 @@
 
 local pars expl
 
-_tags any parameters || return 1
-
-_description expl parameter
+_wanted parameters expl parameter || return 1
 
 pars=( ${(k)parameters[(R)^*local*]} )
 
 compadd "$expl[@]" "$@" - $pars
 
 
-
 # The `-e' option does everything for parameter expansions of us. If
 # we wouldn't have it, we would use something like:
 
diff --git a/Completion/Core/_path_files b/Completion/Core/_path_files
index 6468215cc..41956d543 100644
--- a/Completion/Core/_path_files
+++ b/Completion/Core/_path_files
@@ -331,11 +331,11 @@ for prepath in "$prepaths[@]"; do
 	SUFFIX="${tsuf}"
       fi
 
-tmp4="$testpath"
-compquote tmp1 tmp4
+      tmp4="$testpath"
+      compquote tmp1 tmp4
 
-      if [[ -n $menu || "$compconfig[path_expand]" != *suffix* ]]; then
-        [[ -n "$compconfig[path_cursor]" ]] && compstate[to_end]=''
+      if [[ -n $menu ]] || ! _style paths expand '*suffix*'; then
+        _style paths cursor && compstate[to_end]=''
         if [[ "$tmp3" = */* ]]; then
 	  compadd -Qf -p "$linepath$tmp4" -s "/${tmp3#*/}" \
 	          -W "$prepath$realpath$testpath" "$ignore[@]" \
@@ -423,8 +423,8 @@ done
 
 exppaths=( "${(@)exppaths:#$orig}" )
 
-if [[ "$compconfig[path_expand]" = *prefix* &&
-      $#exppaths -gt 0 && nm -eq compstate[nmatches] ]]; then
+if _style paths expand '*prefix*' &&
+   [[ $#exppaths -gt 0 && nm -eq compstate[nmatches] ]]; then
   PREFIX="${opre}"
   SUFFIX="${osuf}"
   compadd -Q -S '' "$group[@]" "$expl[@]" \
diff --git a/Completion/Core/_requested b/Completion/Core/_requested
index 09c57ee09..6641afdcf 100644
--- a/Completion/Core/_requested
+++ b/Completion/Core/_requested
@@ -1,9 +1,9 @@
 #autoload
 
-# Reset the current context.
+comptags -C _cur_context
 
-_cur_contexts="${_tag_contexts[$tname]}"
-
-# Test if the tag given as argument was requested.
-
-[[ "${_cur_tags[${funcstack[2,-1]}]}" = *:${1}:* ]]
+comptags -R "$1" &&
+    if [[ $# -gt 1 ]]; then
+      _description "${(@)argv[2,-1]}"
+      return 0
+    fi
diff --git a/Completion/Core/_set_options b/Completion/Core/_set_options
index 55388d0c8..ae4d3784e 100644
--- a/Completion/Core/_set_options
+++ b/Completion/Core/_set_options
@@ -6,7 +6,6 @@
 
 local expl
 
-_tags any zsh-options || return 1
-
-_description expl 'set zsh option'
-compadd "$expl[@]" "$@" -M 'L:|[nN][oO]= M:_= M:{A-Z}={a-z}' - $=_set_options
+_wanted zsh-options expl 'set zsh option' &&
+    compadd "$expl[@]" "$@" -M 'L:|[nN][oO]= M:_= M:{A-Z}={a-z}' - \
+            $=_set_options
diff --git a/Completion/Core/_sort_tags b/Completion/Core/_sort_tags
index f1740511d..f44479d56 100644
--- a/Completion/Core/_sort_tags
+++ b/Completion/Core/_sort_tags
@@ -3,18 +3,18 @@
 comptry arguments values
 comptry options
 
-case "$contexts" in
+case "$curcontext" in
 # Some silly examples commented out:
 #
 # *p[bgpn]m*)           # change the order for file-completion
 #   comptry globbed-files directories
 #   comptry all-files
 #   ;;
-# *:dvips,-o*)          # automatic context set by _arguments
+# *:dvips:-o*)          # automatic context set by _arguments
 #   comptry all-files
 #   return
 #   ;;
-# *:kill,*)
+# *:kill:*)
 #   comptry processes
 #   return              # this return ensures that we use only processes
 #   ;;
diff --git a/Completion/Core/_style b/Completion/Core/_style
index a3b54686f..6e2de23df 100644
--- a/Completion/Core/_style
+++ b/Completion/Core/_style
@@ -1,50 +1,44 @@
 #autoload
 
-local all get val i
+local val ret
 
 # Should we return the value?
 
-if [[ "$1" = -g ]]; then
-  get=yes
-  shift
-fi
-
-# Get all styles defined for this context.
-
-all=()
-for i in "${(s.:.)_cur_contexts}"; do
-  all=("$all[@]" "${(@)_compstyles[(K)${i},${1}]}" )
-done
-all=":${(j.:.)${(@o)all:#}##??}:"
+case "$1" in
+-b)
+  compstyles -S "$context" "$2" val
+  ret="$?"
 
-if [[ "$all" = *:${2}[:\=]* ]]; then
-
-  # We have a definition for the style.
+  if [[ "$val" = (#I)(yes|true|1|on) ]]; then
+    eval "${3}=yes"
+  else
+    eval "${3}=no"
+  fi
 
+  return ret;
+  ;;
+-s)
+  compstyles -S "${curcontext}${2:+:${2}}" "$3" "$4"
+  return
+  ;;
+-a)
+  compstyles -A "${curcontext}${2:+:${2}}" "$3" "$4"
+  return
+  ;;
+-h)
+  compstyles -H "${curcontext}${2:+:${2}}" "$3" "$4"
+  return
+  ;;
+esac
+
+[[ "$1" = -(|-) ]] && shift
+
+if compstyles -S "${curcontext}${1:+:${1}}" "$2" val; then
   if [[ $# -eq 3 ]]; then
-    if [[ -n "$get" ]]; then
-
-      # We have to return the value.
-
-      if [[ "$all" = *,${2}\=* ]]; then
-        eval "${3}=\"${${all#*:${2}\=}%%:*}\""
-      else
-        eval "${3}=''"
-      fi
-    else
-
-      # We have to test the value.
-
-      if [[ "$all" = *:${2}\=* ]]; then
-        [[ "${${all#*:${2}\=}%%:*}" = ${~3} ]]
-      else
-        [[ '' -eq ${~3} ]]
-      fi
-
-      return
-    fi
+    [[ "$val" = ${~3} ]]
+  else
+    [[ "$val" = (#I)(yes|true|1|on) ]]
   fi
-  return 0
+else
+  return 1
 fi
-
-return 1
diff --git a/Completion/Core/_tags b/Completion/Core/_tags
index 5ed56df6e..5294ab3c7 100644
--- a/Completion/Core/_tags
+++ b/Completion/Core/_tags
@@ -1,40 +1,26 @@
 #autoload
 
-# We use the funcstack names to communicate to neighboring functions.
-
-local tname="$funcstack[2,-1]"
-
 if (( $# )); then
 
   # We have arguments: the tags supported in this context.
 
-  local command="${_tag_context:-${words[1]}}" _tags contexts name
+  local curcontext="$curcontext"
 
-  # We are given the `-c command-name' option.
-
-  if [[ "$1" = -c?* ]]; then
-    command="${1[3,-1]}"
+  if [[ "$1" = -C?* ]]; then
+    curcontext="${curcontext}:${1[3,-1]}"
     shift
-  elif [[ "$1" = -c ]]; then
-    command="$2"
+  elif [[ "$1" = -C ]]; then
+    curcontext="${curcontext}:${2}"
     shift 2
+  else
+    targs=()
   fi
 
   [[ "$1" = -(|-) ]] && shift
 
-  # Get the context names.
-
-  if [[ -n "$_sub_context" ]]; then
-    contexts="${1}:${_sub_context}"
-  else
-    contexts="${1}"
-  fi
-  contexts=":${command},${${contexts//::/:}//:/:${command},}:"
-  shift
+  # Set and remember offered tags.
 
-  _tags=()
-
-  # Remember offered tags.
+  comptags -i "$curcontext" "$@"
 
   _offered_tags=( "$_offered_tags[@]" "$@" )
   _last_tags=()
@@ -43,46 +29,35 @@ if (( $# )); then
 
   "${_sort_tags:-_sort_tags}" "$@"
 
-  # The sets are reported in $_tags, one element per set. Remove 
-  # tags that weren't requested.
-
-  _tags=( "${(M@)_tags:#*:(${(j:|:)~argv}):*}" )
-
-  # Store the sets in a `hidden' array.
-
-  name="_prio_arr$(( _prio_num++ ))"
-  _prio_names[$tname]="$name"
-  eval "${name}=( \"\$_tags[@]\" )"
-
   # Also store the context (used below and in _requested).
 
-  _cur_contexts="$contexts[2,-2]"
-  _tag_contexts[$tname]="$_cur_contexts"
+  _cur_context="$curcontext"
 
   # Return non-zero if at least one set of tags should be used.
 
-  return \!$#_tags
+  comptags -T
+
+  return
 fi
 
 # The other mode: switch to the next set of tags.
 
-local prios="$_prio_names[$tname]"
+local tags
 
 # Reset the current context.
 
-_cur_contexts="${_tag_contexts[$tname]}"
+comptags -C _cur_context
 
-_failed_tags=( "$_failed_tags[@]" "$_last_tags" )
+_failed_tags=( "$_failed_tags[@]" "$_last_tags[@]" )
 
 # Return failure if no sets remaining.
 
-(( ${(P)#prios} )) || return 1
+comptags -N || return 1
 
 # Otherwise get the next tags.
 
-_cur_tags[$tname]="${(@)${(@P)prios}[1]}:"
+comptags -S _last_tags
 
-_last_tags=( "${(@)${(@s.:.)${(@P)prios}[1]}:#}" )
 _tried_tags=( "$_tried_tags[@]" "$_last_tags[@]" )
 
 shift 1 "$prios"
diff --git a/Completion/Core/_unset_options b/Completion/Core/_unset_options
index 0c7b91b7a..8c8ed780d 100644
--- a/Completion/Core/_unset_options
+++ b/Completion/Core/_unset_options
@@ -6,7 +6,6 @@
 
 local expl
 
-_tags any zsh-options || return 1
-
-_description expl 'unset zsh option'
-compadd "$expl[@]" "$@" -M 'L:|[nN][oO]= M:_= M:{A-Z}={a-z}' - $=_unset_options
+_wanted zsh-options expl 'unset zsh option' &&
+    compadd "$expl[@]" "$@" -M 'L:|[nN][oO]= M:_= M:{A-Z}={a-z}' - \
+            $=_unset_options
diff --git a/Completion/Core/_wanted b/Completion/Core/_wanted
new file mode 100644
index 000000000..7baa3e724
--- /dev/null
+++ b/Completion/Core/_wanted
@@ -0,0 +1,21 @@
+#autoload
+
+local targs
+
+if [[ "$1" = -C?* ]]; then
+  targs=( -C "${1[3,-1]}" )
+  shift
+elif [[ "$1" = -C ]]; then
+  targs=( -C "$2" )
+  shift 2
+else
+  targs=()
+fi
+
+[[ "$1" = -(|-) ]] && shift
+
+if [[ $# -gt 1 ]]; then
+  _tags "$targs[@]" "$1" && _description "${(@)argv[2,-1]}"
+else
+  _tags "$targs[@]" "$1"
+fi
diff --git a/Completion/Core/compdump b/Completion/Core/compdump
index b4530ea8e..67b6e0865 100644
--- a/Completion/Core/compdump
+++ b/Completion/Core/compdump
@@ -17,7 +17,7 @@ emulate -L zsh
 
 typeset _d_file _d_f _d_bks _d_line _d_als
 
-_d_file=${compconfig[dumpfile]-${0:h}/compinit.dump}.$HOST.$$
+_d_file=${_comp_dumpfile-${0:h}/compinit.dump}.$HOST.$$
 
 typeset -U _d_files
 _d_files=( ${^~fpath:/.}/_(|*[^~])(N:t) )
diff --git a/Completion/Core/compinit b/Completion/Core/compinit
index 0f614f322..6f2f39fcb 100644
--- a/Completion/Core/compinit
+++ b/Completion/Core/compinit
@@ -91,27 +91,14 @@ _postpatcomps=()
 
 typeset -gA _lastcomp
 
-# This is the associative array used for configuration.
-
-typeset -gA compconfig
-
-# Standard initialisation for `compconfig'.
+# Remember dumpfile.
 if [[ -n $_i_dumpfile ]]; then
   # Explicitly supplied dumpfile.
-  compconfig[dumpfile]="$_i_dumpfile"
+  _comp_dumpfile="$_i_dumpfile"
 else
-  compconfig[dumpfile]="${ZDOTDIR:-$HOME}/.zcompdump"
+  _comp_dumpfile="${ZDOTDIR:-$HOME}/.zcompdump"
 fi
 
-(( ${+compconfig[correct_accept]} )) || compconfig[correct_accept]=2n
-(( ${+compconfig[correct_prompt]} )) ||
-  compconfig[correct_prompt]='correct to:'
-(( ${+compconfig[completer]} )) || compconfig[completer]=_complete
-
-# This holds the style definitions.
-
-typeset -gA _compstyles
-
 # This can hold names of functions that are to be called after all
 # matches have been generated.
 
@@ -321,119 +308,181 @@ compdef() {
   fi
 }
 
-# Functional interface to configuration. This takes its arguments
-# and sets the according values in `compconfig'.
-# Arguments may be `foo=bar' to set key `foo' to `bar' or `baz' to
-# set key `baz' to the empty string.
-# If no arguments are given, all configurations keys set are displayed.
-# With the option `-l' as the first argument, the other arguments are
-# taken to be key names and the values for theses keys are printed, one
-# per line.
-# When listing is done and the `-L' option is given, the keys and
-# values are printed as invocations for this function, usable to be put
-# inte a setup script.
+# Do *not* use this...
 
 compconf() {
-  local i opt list
 
-  while getopts "lL" opt; do
-    if [[ "$opt" = l ]]; then
-      [[ -z "$list" ]] && list=yes
-    else
-      list=long
-    fi
-  done
-  shift OPTIND-1
+  local style name val i tmp cmt
 
-  if (( $# )); then
-    if [[ -n $list ]]; then
-      for i; do
-        if [[ $list = long ]]; then
-	  (( ${+compconfig[$i]} )) && print "compconf $i='$compconfig[$i]'"
-	else
-          print $compconfig[$i]
-	fi
-      done
-    else
-      for i; do
-        if [[ "$i" = *\=* ]]; then
-          compconfig[${i%%\=*}]="${i#*\=}"
-        else
-          compconfig[$i]=''
-        fi
-      done
-    fi
-  else
-    for i in ${(ok)compconfig}; do
-      if [[ $list = long ]]; then
-	print "compconf $i='$compconfig[$i]'"
-      else
-        print ${(r:25:)i} "$compconfig[$i]"
-      fi
-    done
+  if [[ -z "$_compconf_warn" ]]; then
+    _compconf_warn=yep
+
+    print "
+
+Hello
+
+\`compconf' will be removed in the near future. The \`styles' form of
+your setup should be available in the file:
+
+    \`${HOME}/.zsh-styles'
+
+
+Have fun
+
+   Sven
+" 1>&2
+    command rm -f ${HOME}/.zsh-styles
   fi
+
+  for i; do
+    name="${i%%\=*}"
+    val="${i#*\=}"
+
+    tmp=''
+    cmt=''
+
+    case "$name" in
+    urls_path)
+      tmp="'*:urls' path '$val'"
+      ;;
+    urls_localhttp)
+      tmp="'*:urls' local '${val//:/ }'"
+      ;;
+    describe_options)
+      tmp="'*:options' description '$val'"
+      ;;
+    describe_values)
+      tmp="'*:values' description '$val'"
+      ;;
+    autodescribe_options)
+      tmp="'*:options' auto-description '$val'"
+      ;;
+    description_format)
+      tmp="'*:descriptions' format '$val'"
+      ;;
+    message_format)
+      tmp="'*:messages' format '$val'"
+      ;;
+    warning_format)
+      tmp="'*:warnings' format '$val'"
+      ;;
+    option_prefix)
+      tmp="'*:options' prefix-needed yes"
+      [[ "$val" = hide* ]] &&
+          tmp="$tmp
+compstyle '*:options' prefix-hidden yes"
+      ;;    
+    group_matches)
+      tmp="'*:matches' group 'yes'"
+      ;;
+    colors_path)
+      tmp="'*:colors' path '$val'"
+      ;;
+    path_expand)
+      tmp="'*:paths' expand '$val'"
+      ;;
+    path_cursor)
+      tmp="'*:paths' cursor '$val'"
+      ;;
+    (approximate|incremental|predict|list|oldlist|match)_*)
+      tmp="':${name%%_*}' ${${name#*_}//_/-} '$val'"
+      ;;
+    correct_*)
+      cmt="# This one is a bit ugly. You may want to use only \`*:correct'
+# if you also have the \`correctword_*' or \`approximate_*' keys.
+"
+      tmp="':(correct(|-word)|approximate)' ${name#*_} '$val'"
+      ;;
+    correctword_*)
+      tmp="':correct-word' ${name#correctword_} '$val'"
+      ;;
+    expand_*)
+      cmt="# This one is a bit ugly. You may want to use only \`*:expand'
+# if you also have the \`expandword_*' keys.
+"
+      tmp="':expand(|expand-word)' ${name#*_} '$val'"
+      ;;
+    expandword_*)
+      tmp="':expand-word' ${name#expandword_} '$val'"
+      ;;
+    history_*)
+      tmp="'*:history-entries' ${name#history_} '$val'"
+      ;;
+    completer)
+      tmp="'*' completer ${val//:/ }"
+      ;;
+    last_prompt)
+      tmp="'*' last-prompt '$val'"
+      ;;
+    esac
+    [[ -n "$tmp" ]] && style="${style}${cmt}compstyle ${tmp}
+"
+  done
+
+  eval "${style}"
+
+  print "$style" >> ${HOME}/.zsh-styles
 }
 
 # Very simple interface for setting styles:
 #
 #   compstyle context -styles... context -styles ...
 #
-# Where context is of the form cmd-pat:ctxt-pat:tag-pat.
+# Where context is of the form :ctxt-pats:...:tag-pat.
 #
 # This will be improved if needed. Promised.
 
 compstyle() {
   if (( ! $# )); then
-    local pat
+    local pats styles vals pat style
+
+    compstyles -G pats
 
-    for pat in "${(@k)_compstyles}"; do
-      print -- "${(r:20:: :)pat} -- ${_compstyles[$pat]#??}"
+    for pat in "$pats[@]"; do
+      print "$pat"
+      compstyles -G styles "$pat"
+      for style in "$styles[@]"; do
+        compstyles -G vals "$pat" "$style"
+        print "    $style = $vals"
+      done
     done
 
     return 0
   fi
 
-  local sep pat test
-  typeset -Z 2 num
-
-  while (( $# )); do
-    num=0
-    for pat in "${(s:,:)1}"; do
-      if [[ "$pat" = \* ]]; then
-        (( num += 3 ))
-      elif [[ "$pat" = any ]]; then
-        (( num += 2 ))
-      elif [[ "$pat" != "$pat:q" ]]; then
-        (( num++ ))
-      fi
-    done
+  if [[ "$1" = -d ]]; then
+    case "$#" in
+    1) compstyles -d ;;
+    2) compstyles -d "$2" ;;
+    *) 
+      local pat="$2" style
 
-    pat="$1"
-    shift
+      shift
+
+      for style; do
+        compstyles -d "$pat" "$style"
+      done
+      ;;
+    esac
 
-    sep=$argv[(I)[^-]*]
+    return 0
+  fi
 
-    if (( sep )); then
-      _compstyles[$pat]="${num}${(j.:.)${(@)argv[1,sep-1]#-}}"
-      shift sep-1
-    else
-      _compstyles[$pat]="${num}${(j.:.)${(@)argv#-}}"
-      break
-    fi
-  done
+  [[ "$1" = -(|-) ]] && shift
+
+  compstyles -a "$@"
 
   return 0
 }
 
-# Default styles.
-
-compstyle '*,*,*' -description=yes -prefix-needed=yes -prefix-hidden=no
+# Default styles. This should be executed conditionally somehow.
 
-# Helper function for `_tags'. Will be moved into C-code.
-
-comptry() {
-  _tags=( "$_tags[@]" ":${(j.:.)argv}:" )
-}
+compstyle '*'        description   'yes'
+compstyle '*'        prefix-needed 'yes'
+compstyle '*'        prefix-hidden 'no'
+compstyle ':correct' accept        '2n'
+compstyle ':correct' prompt        'correct to:'
+compstyle '*'        completer     '_complete'
 
 # Utility function to call a function if it exists.
 #
@@ -506,10 +555,10 @@ autoload -U compdump compinstall
 
 # If we have a dump file, load it.
 
-if [[ -f "$compconfig[dumpfile]" ]]; then
-  read -rA _i_line < "$compconfig[dumpfile]"
+if [[ -f "$_comp_dumpfile" ]]; then
+  read -rA _i_line < "$_comp_dumpfile"
   if [[ _i_autodump -eq 1 && $_i_line[2] -eq $#_i_files ]]; then
-    builtin . "$compconfig[dumpfile]"
+    builtin . "$_comp_dumpfile"
     _i_done=yes
   fi
 fi
diff --git a/Completion/Core/compinstall b/Completion/Core/compinstall
index bd58d643b..f7cf94209 100644
--- a/Completion/Core/compinstall
+++ b/Completion/Core/compinstall
@@ -29,7 +29,7 @@ emulate -L zsh
 
 typeset _ci_options _ci_f _ci_fdir _ci_files _ci_dumpfile _ci_lines
 typeset _ci_type _ci_completer _ci_accept _ci_cprompt _ci_startline
-typeset _ci_endline _ci_ifile _ci_tmpf _ci_compconf _ci_warn
+typeset _ci_endline _ci_ifile _ci_tmpf _ci_compstyle _ci_warn
 typeset _ci_dtype _ci_existing _ci_line _ci_end
 
 # Look for the defaults.
@@ -45,14 +45,14 @@ typeset -A _ci_defaults
 if [[ -f $_ci_ifile ]]; then
   # This assumes the lines haven't been altered by the user too much
   # after they were added.
-  _ci_compconf=0
+  _ci_compstyle=0
   sed -n "/^$_ci_startline/,/^$_ci_endline/p" $_ci_ifile |
   while read -rA _ci_line; do
-    if (( $_ci_compconf )); then
-      # parse a compconf component as first argument
+    if (( $_ci_compstyle )); then
+      # parse a compstyle component as first argument
       if [[ $_ci_line[-1] != \\ ]]; then
 	_ci_end=-1
-	_ci_compconf=0
+	_ci_compstyle=0
       else
 	_ci_end=-2
       fi
@@ -72,11 +72,11 @@ if [[ -f $_ci_ifile ]]; then
       [[ $_ci_line[-2] = -d ]] && _ci_dumpfile=$_ci_line[-1]
     elif [[ $_ci_line[1] = _compdir=* ]]; then
       _ci_fdir=${_ci_line[1]##_compdir=}
-    elif [[ $_ci_line[1] = compconf ]]; then
-      # parse a compconf component as second argument (should be completer)
-      [[ $_ci_line[2] = completer=* ]] &&
-        _ci_completer=${_ci_line[2]#completer=}
-      [[ $_ci_line[-1] == \\ ]] && _ci_compconf=1
+    elif [[ $_ci_line[1] = compstyle ]]; then
+      # parse a compstyle component as second argument (should be completer)
+      [[ $_ci_line[3] = completer ]] &&
+        _ci_completer=${_ci_line[3,-1]}
+      [[ $_ci_line[-1] == \\ ]] && _ci_compstyle=1
       _ci_existing="${_ci_existing}$_ci_line
 "
     elif [[ $_ci_line[1] != \#* && $_ci_line[1] != (autoload|\[\[) ]]; then
@@ -208,7 +208,7 @@ approximate completion if that fails.  Would you like:
   A:  Approximate completion
   B:  Both"
   if [[ -n $_ci_completer ]]; then
-    print "  Default: use the current completer:\n$_ci_completer"
+    print "  Default: use the current completers:\n$_ci_completer"
   else
     print "Please type one of the keys above."
   fi
@@ -218,13 +218,13 @@ approximate completion if that fails.  Would you like:
       0*) _ci_completer=_complete
 	  break
 	  ;;
-      [cC]*) _ci_completer=_complete:_correct
+      [cC]*) _ci_completer='_complete _correct'
 	     break
 	     ;;
-      [aA]*) _ci_completer=_complete:_approximate
+      [aA]*) _ci_completer='_complete _approximate'
 	     break;
 	     ;;
-      [bB]*) _ci_completer=_complete:_correct:_approximate
+      [bB]*) _ci_completer='_complete _correct _approximate'
 	     break
 	     ;;
       *) [[ -n $_ci_completer ]] && break
@@ -233,7 +233,7 @@ approximate completion if that fails.  Would you like:
     esac
   done
 
-  _ci_lines="${_ci_lines}compconf completer=$_ci_completer"
+  _ci_lines="${_ci_lines}compstyle '*' completer $_ci_completer"
 
 
   if [[ $_ci_completer = *(correct|approx)* ]]; then
diff --git a/Completion/Debian/_apt b/Completion/Debian/_apt
index b0effba77..47c9f7e8c 100644
--- a/Completion/Debian/_apt
+++ b/Completion/Debian/_apt
@@ -75,7 +75,7 @@ _apt_arguments () {
   nul=$'\0'
   qnul="\$'\\0'"
 
-  comp_bool='compadd "$expl_bool[@]" '"$bool"
+  comp_bool='_tags values && compadd "$expl_bool[@]" '"$bool"
   comp_intlevel= #"_message 'intlevel'"
   comp_configfile='_files "$expl_configfile[@]"'
   comp_arbitem= #"_message 'Foo::Bar=bar'"
@@ -106,7 +106,7 @@ tmp2=("$tmp2[@]" $_ra_left${(M)^short_bool:#$~tmp1} $_ra_left${(M)^short_intleve
 tmp3=("$tmp3[@]" $_ra_left${(M)^short_hasarg:#$~tmp1} $_ra_left${(M)^short_configfile:#$~tmp1} $_ra_left${(M)^short_arbitem:#$~tmp1})
 _describe -o option tmp2 -- tmp3 -S='
 
-  comp_opt='[[ -prefix - || -z "$compconfig[option_prefix]" || "$compconfig[option_prefix]" = *\!$words[1]* ]]'" && { $comp_short; $comp_long }"
+  comp_opt='{ ! _style options prefix-needed || [[ "$PREFIX" = -* ]] } && { $comp_short; $comp_long }"
 
   regex_short=()
   regex_long=()
@@ -384,7 +384,7 @@ _apt-get () {
     /$'check\0'/ \| \
     /$'source\0'/ /$'[^\0]#\0'/ :'_deb_packages avail "$expl_packages[@]"' \# \| \
     /$'help\0/' \| \
-    /"[]"/	:'compadd "$expl_action[@]" update upgrade install remove dist-upgrade dselect-upgrade clean autoclean check source help'
+    /"[]"/	:'_tags actions && compadd "$expl_action[@]" update upgrade install remove dist-upgrade dselect-upgrade clean autoclean check source help'
 
   _apt-get () {
     local expl_action expl_packages
@@ -422,7 +422,7 @@ _apt-cache () {
     /$'search\0'/ \| \
     /$'show\0'/ /$'[^\0]#\0'/ :'_deb_packages avail "$expl_packages[@]"' \# \| \
     /$'depends\0'/ \| \
-    /"[]"/ :'compadd "$expl_action[@]" help add gencaches showpkg stats dump dumpavail unmet check search show depends'
+    /"[]"/ :'_tags actions && compadd "$expl_action[@]" help add gencaches showpkg stats dump dumpavail unmet check search show depends'
 
   _apt-cache () {
     local expl_action expl_packages expl_pkg_cache expl_src_cache
@@ -451,7 +451,7 @@ _apt-cdrom () {
     -o,--option:arbitem \
     -- \
     /$'add\0'/ \| \
-    /"[]"/	:'compadd "$expl_action[@]" add'
+    /"[]"/	:'_tags actions && compadd "$expl_action[@]" add'
 
   _apt-cdrom () {
     local expl_action expl_mount_point
@@ -473,11 +473,11 @@ _apt-config () {
     -- \
     /$'shell\0'/ \
       \( \
-	/$'[^\0]#\0'/ :'compadd "$expl_shell_var[@]" - "${(@k)parameters}"' \
-	/$'[^\0]#\0'/ :'compadd "$expl_config_key[@]" - ${${(f)"$(apt-config dump 2>&1)"}% *}' \
+	/$'[^\0]#\0'/ :'_tags parameters && compadd "$expl_shell_var[@]" - "${(@k)parameters}"' \
+	/$'[^\0]#\0'/ :'_tags configuration-keys && compadd "$expl_config_key[@]" - ${${(f)"$(apt-config dump 2>&1)"}% *}' \
       \) \# \| \
     /$'dump\0'/ \| \
-    /"[]"/	:'compadd "$expl_action[@]" shell dump'
+    /"[]"/	:'_tags actions && compadd "$expl_action[@]" shell dump'
 
   _apt-config () {
     local expl_action expl_shell_var expl_config_key
diff --git a/Completion/Debian/_deb_packages b/Completion/Debian/_deb_packages
index cb74137bf..dd39d055d 100644
--- a/Completion/Debian/_deb_packages
+++ b/Completion/Debian/_deb_packages
@@ -17,11 +17,12 @@ if (( ! $+_deb_cache_dpkg_get_selections )); then
   )
 fi
 
-local command="$1"
+local command="$1" expl
 shift
 
-case "$command" in
-  installed) compadd "$@" - $_deb_cache_installed;;
-  uninstalled) compadd "$@" - $_deb_cache_uninstalled;;
-  avail) compadd "$@" - $_deb_cache_avail;;
-esac
+_wanted packages expl packages &&
+    case "$command" in
+    installed) compadd "$@" - $_deb_cache_installed;;
+    uninstalled) compadd "$@" - $_deb_cache_uninstalled;;
+    avail) compadd "$@" - $_deb_cache_avail;;
+    esac
diff --git a/Completion/Linux/_rpm b/Completion/Linux/_rpm
index 15f154db9..eb30924dc 100644
--- a/Completion/Linux/_rpm
+++ b/Completion/Linux/_rpm
@@ -43,14 +43,14 @@ local ret=1 tmp expl
 
 # Used by `_arguments', made local here.
 
-local context state lstate line
+local curcontext="$curcontext" state lstate line
 typeset -A opt_args
 
 state=''
 
 # Do simple completions or get the first state.
 
-_arguments -s \
+_arguments -C -s \
   '--rcfile:resource file:_files' \
   '--ftpproxy:FTP proxy server:_hosts' \
   '--ftpport:FTP port number:' \
@@ -187,32 +187,23 @@ while [[ -n "$state" ]]; do
     state=package_file
     ;&
   package)
-    _tags "$context" packages || return 1
-
-    _description expl 'RPM package'
-    compadd "$expl[@]" -M 'r:|-=* r:|=*' - $(rpm -qa) && ret=0
+    _wanted packages expl 'RPM package' &&
+        compadd "$expl[@]" -M 'r:|-=* r:|=*' - $(rpm -qa) && ret=0
     ;;
   package_file)
     if compset -P ftp://; then
-      _tags "$context" hosts || return 1
-
-      _hosts -S/ && ret=0
+      _tags hosts && _hosts -S/ && ret=0
     else
-      _tags "$context" files || return 1
-
-      _description expl 'RPM package file'
-      _files "$expl[@]" -g '*.(#i)rpm' && ret=0
-      _description expl 'ftp URL prefix'
-      compadd "$expl[@]" ftp://
+      _alternative \
+          'files:RPM package file:_files -g \*.\(\#i\)rpm' \
+	  'prefixes:ftp URL prefix:compadd ftp://' && ret=0
     fi
     ;;
   tags)
     if compset -P '*\{'; then
-      _tags "$context" tags || return 1
-
-      _description expl 'RPM tag'
-      compadd "$expl[@]" -M 'm:{a-z}={A-Z}' -S '}' - \
-              "${(@)${(@f)$(rpm --querytags)}#RPMTAG_}" && ret=0
+      _wanted tags expl 'RPM tag' &&
+          compadd "$expl[@]" -M 'm:{a-z}={A-Z}' -S '}' - \
+                  "${(@)${(@f)$(rpm --querytags)}#RPMTAG_}" && ret=0
     else
       _message 'RPM format'
     fi
@@ -227,7 +218,7 @@ while [[ -n "$state" ]]; do
       _description expl 'old path'
     fi
 
-    _tags "$context" directories || return 1
+    _tags directories || return 1
 
     _files "$expl[@]" -/ && ret=0
     ;;
diff --git a/Completion/User/_archie b/Completion/User/_archie
index 640fbc4ed..e1c9156fa 100644
--- a/Completion/User/_archie
+++ b/Completion/User/_archie
@@ -1,9 +1,9 @@
 #compdef archie
 
-local context state line expl
+local curcontext="$curcontext" state line expl
 typeset -A opt_args
 
-_arguments -s \
+_arguments -C -s \
   '-D+[debug level]:debug level:' \
   '-v[print version]' \
   '-V[verbose mode]' \
@@ -26,9 +26,6 @@ case "$state" in
 serverhost)
   : ${(A)archie_servers:=${(M)$(archie -L):#archie.*}}
 
-  _tags "${context}:server" hosts || return 1
-
-  _description expl 'archie servers'
-  compadd "$expl[@]" -  $archie_servers
+  _wanted hosts expl 'archie servers' && compadd "$expl[@]" -  $archie_servers
   ;;
 esac
diff --git a/Completion/User/_cvs b/Completion/User/_cvs
index 61435a9cf..cac9132b7 100644
--- a/Completion/User/_cvs
+++ b/Completion/User/_cvs
@@ -33,8 +33,11 @@ _cvs_command () {
 	watchers "")
 
   if (( CURRENT == 1 )); then
-    compadd "$@" ${(k)cmds} || compadd "$@" ${(kv)=cmds}
+    _tags commands && { compadd "$@" ${(k)cmds} || compadd "$@" ${(kv)=cmds} }
   else
+    local curcontext="$curcontext"
+
+    curcontext="${curcontext%:*}:$words[1]"
     _cvs_"${${(k)cmds[(R)* $words[1] *]}:-${(k)cmds[(i)$words[1]]}}"
   fi
 }
@@ -351,22 +354,24 @@ _cvs_update () {
 
 (( $+functions[_cvs_watch] )) ||
 _cvs_watch () {
+  local expl
+
   if (( CURRENT == 2 )); then
-    compadd on off add remove
+    _wanted values expl 'watch comamnd' && compadd on off add remove
   else
     case "$words[2]" in
       on|off) # "+lR"
 	_arguments -s \
-	-{l,R} \
-	':watch command:' \
-	':*:file:_cvs_files'
+	    -{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'
+	    -{l,R} \
+	    '*-a+:action:(edit unedit commit all none)' \
+	    ':watch command:' \
+	    ':*:file:_cvs_files'
 	;;
     esac
   fi
@@ -376,18 +381,18 @@ _cvs_watch () {
 _cvs_watchers () {
   # "+lR"
   _arguments -s \
-    -{l,R} \
-    ':*:file:_cvs_files'
+      -{l,R} \
+      ':*:file:_cvs_files'
 }
 
 (( $+functions[_cvs_root] )) ||
 _cvs_root () {
-  compadd "$@" $_cvs_roots || _files "$@" -/
+  _tags files && { compadd "$@" $_cvs_roots || _files "$@" -/ }
 }
 
 (( $+functions[_cvs_tempdir] )) ||
 _cvs_tempdir () {
-  compadd "$@" $TMPPREFIX:h $TMPDIR /tmp
+  _tags directories && compadd "$@" $TMPPREFIX:h $TMPDIR /tmp
 }
 
 (( $+functions[_cvs_user_variable] )) ||
@@ -403,29 +408,29 @@ _cvs_user_variable () {
 
 (( $+functions[_cvs_bindir] )) ||
 _cvs_bindir () {
-  compadd "$@" /usr/local/bin || _files "$@" -/
+  _tags directories && { compadd "$@" /usr/local/bin || _files "$@" -/ }
 }
 
 (( $+functions[_cvs_editor] )) ||
 _cvs_editor () {
-  compadd "$@" vi
+  _tags commands && compadd "$@" vi
 }
 
 (( $+functions[_cvs_gzip_level] )) ||
 _cvs_gzip_level () {
-  compadd "$@" 9
+  _tags values && compadd "$@" 9
 }
 
 # define completion functions for cvs common options and arguments.
 
 (( $+functions[_cvs_D] )) ||
 _cvs_D () {
-  compadd "$@" today yesterday week\ ago month\ ago
+  _tags values && compadd "$@" today yesterday week\ ago month\ ago
 }
 
 (( $+functions[_cvs_k] )) ||
 _cvs_k () {
-  compadd "$@" kv kvl k o b v
+  _tags values && compadd "$@" kv kvl k o b v
 }
 
 (( $+functions[_cvs_m] )) ||
@@ -435,21 +440,26 @@ _cvs_m () {
 
 (( $+functions[_cvs_modules] )) ||
 _cvs_modules () {
-  local root=$CVSROOT
+  local root=$CVSROOT expl
+
   [[ -f CVS/Root ]] && root=$(<CVS/Root)
 
   if [[ $root = :* || ! -d $root ]]; then
     _message "module name"
   else
-    compadd - \
-      $root/^CVSROOT(:t) \
-      ${${(M)${(f)"$(<$root/CVSROOT/modules)"}:#[^#]*}%%[ 	]*}
+    _wanted modules expl module &&
+        compadd "$expl[@]" - \
+            $root/^CVSROOT(:t) \
+            ${${(M)${(f)"$(<$root/CVSROOT/modules)"}:#[^#]*}%%[ 	]*}
   fi
 }
 
 (( $+functions[_cvs_revisions] )) ||
 _cvs_revisions () {
-  compadd - ${${${(M)${(f)"$(cvs -q status -vl .)"}:#	*}##[ 	]##}%%[ 	]*}
+  local expl
+
+  _wanted values expl revision &&
+      compadd - ${${${(M)${(f)"$(cvs -q status -vl .)"}:#	*}##[ 	]##}%%[ 	]*}
 }
 
 # define completion functions for files maintained by cvs.
@@ -477,8 +487,7 @@ _cvs_extract_file_entries () {
 
 (( $+functions[_cvs_extract_modifiedfile_entries] )) ||
 _cvs_extract_modifiedfile_entries () {
-  if [[ -n "$compconfig[cvs_disable_stat]" ]] ||
-    ! { zmodload -e stat || zmodload stat }; then
+  if _style cvs disable-stat || ! { zmodload -e stat || zmodload stat }; then
     _cvs_extract_file_entries
     return
   fi
@@ -566,7 +575,7 @@ _cvs_files_removed () {
     local omit
     omit=(${pref}*(D:t))
     eval 'entries=(${entries:#('${(j:|:)${(@)omit:q}}')})'
-    compadd "$@" -P "$qpref" - ${entries:q} ||
+    _tags direcories && compadd "$@" -P "$qpref" - ${entries:q} ||
     _cvs_directories "$@"
   else
     _files "$@"
diff --git a/Completion/User/_dd b/Completion/User/_dd
index 9bcdc876d..3a980b48d 100644
--- a/Completion/User/_dd
+++ b/Completion/User/_dd
@@ -6,9 +6,9 @@ if compset -P 1 'conv\='; then
   # If there's a comma present, ignore up to the last one.  The
   # test alone will have that effect.
   compset -p '*,'
-  _description expl conversion
-  compadd "$expl[@]" -qS, -q \
-          ascii ebcdic ibm block unblock lcase ucase swab noerror sync
+  _wanted values expl conversion &&
+      compadd "$expl[@]" -qS, -q \
+              ascii ebcdic ibm block unblock lcase ucase swab noerror sync
 elif compset -P 1 'if\='; then
   _description expl 'input file'
   _files "$expl[@]"
@@ -16,6 +16,6 @@ elif compset -P 1 'of\='; then
   _description expl 'output file'
   _files "$expl[@]"
 else
-  _description expl option
-  compadd "$expl[@]" -S '=' if of ibs obs bs cbs skip files seek count conv
+  _wanted values expl option &&
+      compadd "$expl[@]" -S '=' if of ibs obs bs cbs skip files seek count conv
 fi
diff --git a/Completion/User/_flex b/Completion/User/_flex
index 5d5d55f7a..714e5b9d5 100644
--- a/Completion/User/_flex
+++ b/Completion/User/_flex
@@ -1,9 +1,9 @@
 #compdef flex
 
-local context state line ret=1
+local curcontext="$curcontext" state line ret=1
 typeset -A opt_args
 
-_arguments -s \
+_arguments -C -s \
   --help --version \
   '-b[generate backing-up information]' \
   '-d[make scanner running in debug mode]' \
diff --git a/Completion/User/_gcc b/Completion/User/_gcc
index 88f70ad52..7292a933c 100644
--- a/Completion/User/_gcc
+++ b/Completion/User/_gcc
@@ -1,6 +1,6 @@
 #compdef gcc
 
-local context state line ret=1 expl args
+local curcontext="$curcontext" state line ret=1 expl args
 typeset -A opt_args
 
 args=()
@@ -163,7 +163,7 @@ h8/300)
 esac
 
 
-_arguments -M 'L:|-{fW}no-=-{fW} r:|[_-]=* r:|=*' \
+_arguments -C -M 'L:|-{fW}no-=-{fW} r:|[_-]=* r:|=*' \
   "$args[@]" \
   -c -S -E -v -a -w -C -H -P -s '(-pg)-p' '(-p)-pg' \
   '-o:output file:_files' \
@@ -273,10 +273,8 @@ dump)
     'p[annotate assembler output]' && ret=0
   ;;
 library)
-  _tags "${context}" libraries || return 1
-
-  _description expl library
-  compadd "$expl[@]" - ${^=LD_LIBRARY_PATH:-/usr/lib /usr/local/lib}/lib*.(a|so*)(:t:fr:s/lib//) && ret=0
+  _wanted libraries expl library &&
+      compadd "$expl[@]" - ${^=LD_LIBRARY_PATH:-/usr/lib /usr/local/lib}/lib*.(a|so*)(:t:fr:s/lib//) && ret=0
   ;;
 esac
 
diff --git a/Completion/User/_gdb b/Completion/User/_gdb
index dab301b39..d037b83d9 100644
--- a/Completion/User/_gdb
+++ b/Completion/User/_gdb
@@ -10,19 +10,19 @@ local cur="$words[CURRENT]" prev w list ret=1 expl
 if compset -P '-(cd|directory)='; then
   _files -/
 elif compset -P '-tty='; then
-  _description expl 'terminal device'
-  compadd "$expl[@]" - /dev/tty*
+  _wanted devices expl 'terminal device' && compadd "$expl[@]" - /dev/tty*
 elif compset -P '-(exec|se)='; then
   _description expl executable
   _files "$expl[@]" -g '*(*)'
 elif compset -P '-(symbols|core|command)='; then
   _files
 elif [[ "$PREFIX" = -* ]]; then
-  _description expl option
-  compadd "$expl[@]" -QS '' - -symbols\= -exec\= -se\= -core\= -command\= \
-                              -directory\= -cd\= -tty\=
-  compadd "$expl[@]"        - -help -h -s -e -c -x -d -nx -n -quiet -q \
-			      -batch -fullname -f -b
+  if _wanted options expl option; then
+    compadd "$expl[@]" -QS '' - -symbols\= -exec\= -se\= -core\= -command\= \
+                                -directory\= -cd\= -tty\=
+    compadd "$expl[@]"        - -help -h -s -e -c -x -d -nx -n -quiet -q \
+	  		        -batch -fullname -f -b
+  fi
 else
   prev="$words[CURRENT-1]"
 
@@ -31,10 +31,10 @@ else
   (-[csx]) _files && return 0 ;;
   (-e)     _description expl executable
            _files "$expl[@]" -g '*(*)' && return 0 ;;
-  (-b)     _description -V expl 'baud rate'
-           compadd "$expl[@]" 0 50 75 110 134 150 200 300 600 1200 1800 \
-			      2400 4800 9600 19200 38400 57600 115200 \
-			      230400 && return 0 ;;
+  (-b)     _wanted values expl -V expl 'baud rate' &&
+               compadd "$expl[@]" 0 50 75 110 134 150 200 300 600 1200 1800 \
+			          2400 4800 9600 19200 38400 57600 115200 \
+			          230400 && return 0 ;;
   esac
 
   w=( "${(@)words[2,-1]}" )
@@ -44,10 +44,7 @@ else
   done
 
   if [[ $#w -gt 1 ]]; then
-    _files               && ret=0
-    _pids -m "${w[1]:t}" && ret=0
-
-    return ret
+    _alternative 'files:: _files' "processes:: _pids -m ${w[1]:t}"
   else
     _description expl executable
     _files "$expl[@]" -g '*(*)'
diff --git a/Completion/User/_gprof b/Completion/User/_gprof
index cbc362331..a69a078ba 100644
--- a/Completion/User/_gprof
+++ b/Completion/User/_gprof
@@ -1,9 +1,9 @@
 #compdef gprof
 
-local context state line ret=1
+local curcontext="$curcontext" state line ret=1
 typeset -A opt_args
 
-_arguments -s -{a,b,c,D,h,i,l,L,s,T,v,w,x,y,z} \
+_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:->pair' \
@@ -17,7 +17,7 @@ _arguments -s -{a,b,c,D,h,i,l,L,s,T,v,w,x,y,z} \
 if [[ -n "$state" ]]; then
   local cmd pair expl
 
-  _tags "${context}" functions || return 1
+  _tags functions || return 1
 
   [[ "$state" = pair ]] && pair=yes
 
diff --git a/Completion/User/_groups b/Completion/User/_groups
index bc955a8d2..f1963a8e7 100644
--- a/Completion/User/_groups
+++ b/Completion/User/_groups
@@ -2,15 +2,14 @@
 
 local expl
 
-_tags any groups || return 1
+_wanted groups expl group || return 1
 
 if (( ! $+groups )); then
-  if whence -p ypcat > /dev/null; then
-    : ${(A)groups:=${${(s: :)$(ypcat group.byname)}%%:*}} # If you use NIS
+  if (( ${+commands[ypcat]} )); then
+    : ${(A)groups:=${${(s: :)$(ypcat group.byname)}%%:*}} # If you use YP
   else
     : ${(A)groups:=${${(s: :)$(</etc/group)}%%:*}}
   fi
 fi
 
-_description expl group
 compadd "$@" "$expl[@]" - $groups
diff --git a/Completion/User/_gs b/Completion/User/_gs
index 0c9c11e10..2eebb8d23 100644
--- a/Completion/User/_gs
+++ b/Completion/User/_gs
@@ -8,10 +8,10 @@ if compset -N --; then
     return 1
   fi
 else
-  local context state line ret=1
+  local curcontext="$curcontext" state line ret=1
   typeset -A opt_args
 
-  _x_arguments \
+  _x_arguments -C \
     '-q[quiet startup]' \
     '-g-[set device size]:device size (<width>x<height>):' \
     '-r-[set resolution]:resolution (<val> or <x>x<y>):' \
@@ -25,38 +25,31 @@ else
     if [[ "$PREFIX" = *\=* ]]; then
       _message 'systemdict definition value'
     else
-      _tags "$context" names || return 1
-
-      _description expl 'systemdict definition name'
-      compadd "$expl[@]" -M 'm:{a-z}={A-Z}' - \
-              DISKFONTS NOCACHE NOBIND NODISPLAY NOPAUSE PLATFONTS SAFER \
-              WRITESYSTEMDICT && ret=0
+      _wanted names expl 'systemdict definition name' &&
+          compadd "$expl[@]" -M 'm:{a-z}={A-Z}' - \
+                  DISKFONTS NOCACHE NOBIND NODISPLAY NOPAUSE PLATFONTS SAFER \
+                  WRITESYSTEMDICT && ret=0
     fi
     ;;
   sname)
     if compset -P '*\='; then
       case "$IPREFIX" in
       *DEVICE\=)
-        _tags "$context" devices || return 1
-
-        _description expl 'ghostscript device'
-        compadd "$expl[@]" - "${(@)${=${$(gs -h)##* devices:}%%Search path:*}:#}" && ret=0
+        _wanted devices expl 'ghostscript device' &&
+            compadd "$expl[@]" - "${(@)${=${$(gs -h)##* devices:}%%Search path:*}:#}" && ret=0
         ;;
       *OutputFile\=)
-        _tags "$context" files || return 1
-
         _description expl 'output file'
-        _files && ret=0
+        _files "$expl[@]" && ret=0
         ;;
       *)
         _message 'systemdict value'
         return 1
       esac
     else
-      _tags "$context" names || return 1
-
-      _description expl 'systemdict name'
-      compadd "$expl[@]" -S\= -M 'm:{a-z}={A-Z}' - DEVICE OutputFile && ret=0
+      _wanted names expl 'systemdict name' &&
+          compadd "$expl[@]" -S\= -M 'm:{a-z}={A-Z}' - DEVICE OutputFile &&
+              ret=0
     fi
     ;;
   esac
diff --git a/Completion/User/_hosts b/Completion/User/_hosts
index d577c83ab..83480efe4 100644
--- a/Completion/User/_hosts
+++ b/Completion/User/_hosts
@@ -2,9 +2,7 @@
 
 local expl
 
-_tags any hosts || return 1
-
 : ${(A)hosts:=${(s: :)${(ps:\t:)${${(f)"$(</etc/hosts)"}%%\#*}##[:blank:]#[^[:blank:]]#}}}
 
-_description expl host
-compadd -M 'm:{a-zA-Z}={A-Za-z} r:|.=* r:|=*' "$@" "$expl[@]" - "$hosts[@]"
+_wanted hosts expl host &&
+    compadd -M 'm:{a-zA-Z}={A-Za-z} r:|.=* r:|=*' "$@" "$expl[@]" - "$hosts[@]"
diff --git a/Completion/User/_killall b/Completion/User/_killall
index 5df1acbb9..ebe02f10c 100644
--- a/Completion/User/_killall
+++ b/Completion/User/_killall
@@ -1,6 +1,4 @@
 #compdef killall
 
-if compset -P 1 -; then
-  _description expl signal
-  compadd "$expl[@]" $signals[1,-3]
-fi
+compset -P 1 - && _wanted -C - signals expl signal &&
+    compadd "$expl[@]" $signals[1,-3]
diff --git a/Completion/User/_lynx b/Completion/User/_lynx
index 8399c4735..e3b57a9b4 100644
--- a/Completion/User/_lynx
+++ b/Completion/User/_lynx
@@ -1,9 +1,9 @@
 #compdef lynx
 
-local context state line
+local curcontext="$curcontext" state line
 typeset -A opt_args
 
-_arguments \
+_arguments -C \
   '-accept_all_cookies' \
   '-anonymous' \
   '-assume_charset=:MIMENAME:' \
diff --git a/Completion/User/_mailboxes b/Completion/User/_mailboxes
index 06906628e..97628ef9a 100644
--- a/Completion/User/_mailboxes
+++ b/Completion/User/_mailboxes
@@ -1,7 +1,7 @@
 #autoload
 
-emulate -L zsh
-setopt nullglob
+#emulate -L zsh
+setopt localoptions nullglob
 
 # This is still needlessly mutt-biased and should be fixed.
 
@@ -12,35 +12,31 @@ local maildirectory="${maildirectory:-~/Mail}"
 
 if (( ! $+_mailbox_cache )) then
 
-[[ -f ${~muttrc:-.} ]] && muttboxes=( ${$(grep mailboxes ${~muttrc})[2,-1]} )
+  [[ -f ${~muttrc:-.} ]] && muttboxes=( ${$(grep mailboxes ${~muttrc})[2,-1]} )
 
-mboxes=( ${~maildirectory}/*(^/) ${~pinedirectory}/**/*(.) )
-dirboxes=( ${~maildirectory}/*(/) )
+  mboxes=( ${~maildirectory}/*(^/) ${~pinedirectory}/**/*(.) )
+  dirboxes=( ${~maildirectory}/*(/) )
 
-while (( $#dirboxes ))
-do 
+  while (( $#dirboxes )); do
     i=$dirboxes[1]
     shift dirboxes
-    if [[ -d "$i/cur" ]]
-    then
-	maildirboxes=( $maildirboxes $i )
-    elif j=( $i/<1-> ) && [[ -n "$j" ]]
-    then
-	MHboxes=( $MHboxes $i )
+    if [[ -d "$i/cur" ]]; then
+      maildirboxes=( $maildirboxes $i )
+    elif j=( $i/<1-> ) && [[ -n "$j" ]]; then
+      MHboxes=( $MHboxes $i )
     else
-	mboxes=( $mboxes $i/*(.) )
-	dirboxes=( $dirboxes $i/*(/) )
+      mboxes=( $mboxes $i/*(.) )
+      dirboxes=( $dirboxes $i/*(/) )
     fi
-done
+  done
 
-[[ -n "$muttboxes" || -d ~/.elm || -d ~/.mutt ]] &&
-    _mailbox_cache=(\! \< \> $muttboxes)
-[[ -n "$mailpath" ]] &&
-    _mailbox_cache=($_mailbox_cache ${mailpath//\?*/})
-
-_mailbox_cache=($_mailbox_cache $mboxes $maildirboxes $MHboxes)
+  [[ -n "$muttboxes" || -d ~/.elm || -d ~/.mutt ]] &&
+      _mailbox_cache=(\! \< \> $muttboxes)
+  [[ -n "$mailpath" ]] &&
+      _mailbox_cache=($_mailbox_cache ${mailpath//\?*/})
 
+  _mailbox_cache=($_mailbox_cache $mboxes $maildirboxes $MHboxes)
 fi
 
-_description expl 'mailbox specification'
-compadd "$@" "$expl[@]" - "$_mailbox_cache[@]"
+_wanted files expl 'mailbox specification' &&
+    compadd "$@" "$expl[@]" - "$_mailbox_cache[@]"
diff --git a/Completion/User/_make b/Completion/User/_make
index f6544ffb0..1531b34d6 100644
--- a/Completion/User/_make
+++ b/Completion/User/_make
@@ -18,12 +18,11 @@ else
     file=''
   fi
 
-  _description expl 'make target'
-  [[ -n "$file" ]] &&
-    compadd "$expl[@]" - \
-      $(awk '/^[a-zA-Z0-9][^\/ \t]+:/ {print $1}
-	     /^\.include  *<bsd\.port\.(subdir\.|pre\.)?mk>/ || /^\.include  *".*mk\/bsd\.pkg\.(subdir\.)?mk"/ {
-	       print "fetch fetch-list extract patch configure build install reinstall deinstall package describe checkpatch checksum makesum" }' \
-	    FS=: $file) && ret=0
+  [[ -n "$file" ]] && _wanted targets expl 'make target' &&
+      compadd "$expl[@]" - \
+          $(awk '/^[a-zA-Z0-9][^\/ \t]+:/ {print $1}
+	         /^\.include  *<bsd\.port\.(subdir\.|pre\.)?mk>/ || /^\.include  *".*mk\/bsd\.pkg\.(subdir\.)?mk"/ {
+	           print "fetch fetch-list extract patch configure build install reinstall deinstall package describe checkpatch checksum makesum" }' \
+	        FS=: $file) && ret=0
   (( ret )) && { compset -P 1 '*\='; _files }
 fi
diff --git a/Completion/User/_man b/Completion/User/_man
index 60bd23dd7..18b74d30b 100644
--- a/Completion/User/_man
+++ b/Completion/User/_man
@@ -22,7 +22,7 @@ if (( ! $#manpath )); then
 fi
 
 (( $#manpath )) || manpath=( ${(s.:.)$(manpath 2>/dev/null)} ) ||
-  manpath=( /usr/man(-/N) /(opt|usr)/(dt|share|X11R6|local)/(cat|)man(-/N) )
+    manpath=( /usr/man(-/N) /(opt|usr)/(dt|share|X11R6|local)/(cat|)man(-/N) )
 
 # `sman' is the SGML manual directory for Solaris 7.
 
@@ -33,5 +33,5 @@ else
   rep=( $manpath/(sman|man|cat)*/${~approx}$PREFIX${~star}$SUFFIX.<->*(N:t) )
 fi
 
-_description expl 'manual page'
-(( $#rep )) && compadd "$expl[@]" - ${rep%%.[^.]##(.gz|)}
+(( $#rep )) && _wanted manuals expl 'manual page' &&
+    compadd "$expl[@]" - ${rep%%.[^.]##(.gz|)}
diff --git a/Completion/User/_mh b/Completion/User/_mh
index 87ab8a18e..e4d042dc2 100644
--- a/Completion/User/_mh
+++ b/Completion/User/_mh
@@ -17,12 +17,12 @@ 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.
-  _description expl option
-  compadd "$expl[@]" - $($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";
-  }')
+  _wanted options expl option &&
+      compadd "$expl[@]" - $($words[1] -help | perl -ne 'if (/^\s*-\(?(\S+)/) {
+            $n = $1;
+            $n =~ s/\)//g;
+            print $n =~ s/^\[([a-z]+)\]// ? "$n\n$1$n\n" : "$n\n";
+          }')
   return
 elif compset -P 1 '[+@]' || [[ "$prev" = -draftfolder ]]; then
   # Complete folder names.
@@ -53,11 +53,11 @@ elif [[ "$prev" = -(form|audit|filter) ]]; then
   _description expl 'MH template file'
   _files "$expl[@]" -W mhfpath -g '*(.)'
 elif [[ "$prev" = -(no|)cc ]]; then
-  _description expl 'CC address'
-  compadd "$expl[@]" all to cc me
+  _wanted -C "$prev" values expl 'CC address' &&
+      compadd "$expl[@]" all to cc me
 elif [[ "$prev" = -[rw]cache ]]; then
-  _description expl cache
-  compadd "$expl[@]" public private never ask
+  _wanted -C "$prev" values expl cache &&
+      compadd "$expl[@]" public private never ask
 else
   # Generate sequences.
   local foldnam folddir f ret
@@ -74,11 +74,11 @@ else
     # leaving foldnam empty works here
   fi
 
-  _description expl sequence
-  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
-
+  if _wanted sequences expl sequence; then
+    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
+  fi
   return ret
 fi
diff --git a/Completion/User/_mount b/Completion/User/_mount
index 39e31ee35..a68260ae7 100644
--- a/Completion/User/_mount
+++ b/Completion/User/_mount
@@ -5,7 +5,9 @@
 # arguments for the `mount' command for different operating systems
 # are below these table.
 
-local context state line ret=1 args fss deffs=iso9660 descr tmp
+local curcontext="$curcontext" state line ret=1
+local args fss deffs=iso9660 descr tmp
+
 typeset -A opt_args
 
 if (( ! $+_fs_any )); then
@@ -209,13 +211,13 @@ if [[ "$words[1]" = mount ]]; then
     ;;
   esac
 
-  _arguments "$args[@]" && ret=0
+  _arguments -C "$args[@]" && ret=0
 
 else
 
   # Completion for umount.
 
-  _arguments -s \
+  _arguments -C -s \
     '-h[show help]' \
     '-V[show version]' \
     '-v[verbose mode]' \
@@ -228,14 +230,13 @@ fi
 
 case "$state" in
 fstype)
-  _tags "$context" types || return 1
-
   compset -P '*,'
-  _description expl 'file system type'
-  compadd "$expl[@]" -qS, -M 'L:|no=' - "$fss[@]" && ret=0
+
+  _wanted types expl 'file system type' &&
+      compadd "$expl[@]" -qS, -M 'L:|no=' - "$fss[@]" && ret=0
   ;;
 fsopt)
-  _tags "$context" options || return 1
+  _tags options || return 1
 
   eval 'tmp=(' '"$_fs_'${(s:,:)^${opt_args[-t]:-${deffs}}}'[@]"' ')'
   tmp=( "$_fs_any[@]" "${(@)tmp:#}" )
@@ -245,7 +246,7 @@ devordir)
   if (( $+opt_args[-a] )); then
     _message "no device or directory with option \`-a'"
   else
-    _alternative "$context" \
+    _alternative \
         'devices:device:compadd /dev/\*' \
 	'directories:mount point:_files -/' && ret=0
   fi
@@ -260,7 +261,7 @@ udevordir)
     dev_tmp=( "${(@)${(@)tmp%% *}:#none}" )
     mp_tmp=( "${(@)${(@)tmp#* }%% *}" )
 
-    _alternative "$context" \
+    _alternative \
         'devices:device:compadd - $dev_tmp[@]' \
 	'directories:mount point:compadd - $mp_tmp[@]' && ret=0
   fi
diff --git a/Completion/User/_mutt b/Completion/User/_mutt
index 16b1b0c6d..98c59b2e0 100644
--- a/Completion/User/_mutt
+++ b/Completion/User/_mutt
@@ -1,8 +1,8 @@
 #compdef mutt
 
-local context state line muttrc="~/.muttrc" ret=1
+local curcontext="$curcontext" state line muttrc="~/.muttrc" ret=1
 
- _arguments \
+ _arguments -C \
  '::recipient:->userhost' \
  '-a:MIME attachment:_files' \
  '-b:BCC recipient:->userhost' \
@@ -25,7 +25,7 @@ local context state line muttrc="~/.muttrc" ret=1
  '-Z+:open first mailbox with new mail:' && ret=0
 
 if [[ "$state" = userhost ]]; then
-  _tags "$context" hosts || return 1
+  _tags hosts || return 1
 
   if compset -P '*@'; then
     _description expl 'remote host name'
diff --git a/Completion/User/_netscape b/Completion/User/_netscape
index 3caaad05e..2f0537133 100644
--- a/Completion/User/_netscape
+++ b/Completion/User/_netscape
@@ -1,9 +1,9 @@
 #compdef netscape
 
-local context state line ret=1
+local curcontext="$curcontext" state line ret=1
 typeset -A opt_args
 
-_x_arguments \
+_x_arguments -C \
   '-xrm:resource:_x_resource' \
   '-help[show usage message]' \
   '-version[show the version number and build date]' \
@@ -25,7 +25,7 @@ _x_arguments \
   '*:location:->urls' && ret=0
 
 [[ "$state" = "urls" ]] &&
-  _tags "$context" files && _files "$@" && return 0
+  _files "$@" && return 0
 
 
 # Handle netscape remote commands
@@ -40,35 +40,33 @@ if [[ "$state" = "remote" ]]; then
     openFile*) _files -W ~;;
     saveAs*) 
       if compset -P "*,"; then
-        if _tags "$context" types; then
-          _description expl 'data type'
-          compadd -s")" -M 'm:{a-zA-Z}={A-Za-z}' HTML Text PostScript &&
-              ret=0
+        _wanted types expl 'data type' &&
+            compadd -s")" -M 'm:{a-zA-Z}={A-Za-z}' HTML Text PostScript &&
+                ret=0
         fi
       else
-        _tags "$context" files && _path_files -W ~ && ret=0
+        _tags files && _path_files -W ~ && ret=0
       fi
     ;;
     mailto*)
       compset -P "*,"
       if compset -P '*@'; then
-        if _tags "$context" hosts; then
-          _description expl 'remote host name'
-          _hosts "$expl[@]" -q -S, && ret=0
+        _wanted hosts expl 'remote host name' &&
+            _hosts "$expl[@]" -q -S, && ret=0
         fi
       else
-        if _tags "$context" users; then
-          _description expl 'login name'
-          _users "$expl[@]" -q -S@ && ret=0
+        _wanted users expl 'login name' && _users "$expl[@]" -q -S@ && ret=0
         fi
       fi
     ;;
     *)
-      if _tags "$context" commands; then
+      if _wanted commands expl 'remote commands'; then
         if [[ "$QIPREFIX" ]]; then
-          compadd -q -S '(' -M 'm:{a-zA-Z}={A-Za-z}' $remote_commands && ret=0
+          compadd "$expl[@]" -qS '(' -M 'm:{a-zA-Z}={A-Za-z}' - \
+                  $remote_commands && ret=0
         else
-	  compadd -s'(' -S '' -M 'm:{a-zA-Z}={A-Za-z}' $remote_commands && ret=0
+	  compadd "$expl[@]" -s'(' -S '' -M 'm:{a-zA-Z}={A-Za-z}' - \
+                  $remote_commands && ret=0
 	fi
       fi
     ;;
@@ -77,15 +75,12 @@ fi
 
 if [[ "$state" = "urls" ]]; then
   # Complete netscape urls
-  if [[ -prefix about: ]]; then
-    if _tags "$context" values; then
-      _description expl 'about what'
-      compset -P about:
-      compadd authors blank cache document fonts global hype image-cache \
-          license logo memory-cache mozilla plugins && ret=0
-    fi
+  if compset about: ; then
+    _wanted values expl 'about what' &&
+        compadd authors blank cache document fonts global hype image-cache \
+            license logo memory-cache mozilla plugins && ret=0
   else
-    if _tags "$context" prefixes; then
+    if _tags prefixes; then
       _description expl 'URL prefix'
       compadd "$expl[@]" -S '' about: mocha: javascript:
       _urls "$@" && ret=0
diff --git a/Completion/User/_nslookup b/Completion/User/_nslookup
index f3e290505..495a0e3de 100644
--- a/Completion/User/_nslookup
+++ b/Completion/User/_nslookup
@@ -19,7 +19,7 @@
 # other characters than lower case letters, we try to call the function
 # `_nslookup_host'.
 
-local context state expl ret=1 setopts
+local context curstate="$curcontext" expl ret=1 setopts
 
 setopts=(
   'all[print current values]' \
@@ -52,17 +52,15 @@ if [[ -n "$compcontext" ]]; then
 
     funcall ret _nslookup_command && return ret
 
-    _tags any commands || return 1
-
-    _description expl 'command'
-    compadd "$expl[@]" - server lserver root finger ls view help set && ret=0
-    _hosts && ret=0
+    _alternative \
+        'commands:command:compadd server lserver root finger ls view help set' \
+	'hosts:: _host' && ret=0
     return ret
   elif [[ "$compstate[context]" = redirect ]]; then
 
     funcall ret _nslookup_redirect && return ret
 
-    _tags redirection files || return 1
+    _tags -C redirection files || return 1
 
     if [[ "$words[1]" != (finger|ls) ]]; then
       _message "redirection not allowed for command \`$words[1]'"
@@ -88,10 +86,7 @@ if [[ -n "$compcontext" ]]; then
 
   case "$words[1]" in
   (|l)server)
-    _tags argument hosts || return 1
-
-    _description expl 'new default server'
-    _hosts "$expl[@]"
+    _wanted hosts expl 'new default server' && _hosts "$expl[@]"
     return
     ;;
   root|exit|help|\?)
@@ -112,8 +107,6 @@ if [[ -n "$compcontext" ]]; then
     return
     ;;
   view)
-    _tags argument files || return 1
-
     _description expl 'view file'
     _files "$expl[@]"
     return
@@ -126,10 +119,7 @@ if [[ -n "$compcontext" ]]; then
     [[ -z "$state" ]] && return ret
     ;;
   *)
-    _tags argument hosts || return 1
-
-    _description expl 'server'
-    _hosts "$expl[@]"
+    _wanted hosts expl 'server' && _hosts "$expl[@]"
     return
   esac
 fi
@@ -140,7 +130,7 @@ if [[ -z "$state" ]]; then
   local line
   typeset -A opt_args
 
-  _arguments \
+  _arguments -C \
     "-${(@)^${(@M)setopts:#*\]:*}/\[/=[}" \
     "-${(@)^setopts:#(\(|*\]:)*}" \
     "${(@)^${(@)${(@M)setopts:#\(*}/\)/)-}/\(/(-}" \
@@ -151,7 +141,7 @@ fi
 # This is completion after `srchlist' for both types.
 
 if [[ -n "$state" ]]; then
-  _tags "$context" hosts || return 1
+  _tags hosts || return 1
 
   if compset -P '*/'; then
     _description expl 'search list entry'
diff --git a/Completion/User/_pbm b/Completion/User/_pbm
index c697ebaa6..9eecd0390 100644
--- a/Completion/User/_pbm
+++ b/Completion/User/_pbm
@@ -254,8 +254,7 @@ pgmtoppm)
     fi
     _x_color && ret=0
   
-    _description expl option
-    compadd "$expl[@]" - -map && ret=0
+    _wanted options expl option && compadd "$expl[@]" - -map && ret=0
   
     return ret
   elif [[ CURRENT -eq 3 && "$words[2]" = -map ]]; then
@@ -591,12 +590,12 @@ ppmquant)
   fi
   
   if [[ CURRENT -eq 2 ]]; then
-    _description expl option
-    if [[ -n "$opt" ]]; then
-      compadd "$expl[@]" - -map -fs -floyd && ret=0
-    else
-      compadd "$expl[@]" - -map && ret=0
-    fi
+    _wanted options expl option &&
+        if [[ -n "$opt" ]]; then
+          compadd "$expl[@]" - -map -fs -floyd && ret=0
+        else
+          compadd "$expl[@]" - -map && ret=0
+        fi
     _message 'number of colors'
   
     return ret
diff --git a/Completion/User/_perl_basepods b/Completion/User/_perl_basepods
index 2dc0874f0..7f257aed3 100644
--- a/Completion/User/_perl_basepods
+++ b/Completion/User/_perl_basepods
@@ -15,18 +15,19 @@ if [[ ${+_perl_basepods} -eq 0 ]]; then
     _perl_basepods=( ${$(basepods):t:r} )
   else
     local podpath
+
     podpath=$(perl -MConfig -e 'print "$Config{installprivlib}/pod"')
+
     if [[ ! -e $podpath/perl.pod ]]; then
       echo "Couldn't find perl.pod from Config.pm; giving up."
       return 1
     else
-      cd $podpath
-      _perl_basepods=( *.pod(:r:t) )
-      cd $OLDPWD
+      _perl_basepods=( ${podpath}/*.pod(:r:t) )
     fi
   fi
 fi
 
 local expl
-_description expl "Perl base pods"
-compadd "$expl[@]" - $_perl_basepods
+
+_wanted pods expl 'Perl base pods' &&
+    compadd "$expl[@]" - $_perl_basepods
diff --git a/Completion/User/_perl_builtin_funcs b/Completion/User/_perl_builtin_funcs
index 804488db9..7ac69828d 100644
--- a/Completion/User/_perl_builtin_funcs
+++ b/Completion/User/_perl_builtin_funcs
@@ -27,5 +27,6 @@ if [[ ${+_perl_builtin_funcs} -eq 0 ]]; then
 fi
 
 local expl
-_description expl "Perl built-in functions"
-compadd "$expl[@]" - $_perl_builtin_funcs
+
+_wanted functions expl 'Perl built-in functions' &&
+    compadd "$expl[@]" - $_perl_builtin_funcs
diff --git a/Completion/User/_perl_modules b/Completion/User/_perl_modules
index ef5c00628..272ebb5e4 100644
--- a/Completion/User/_perl_modules
+++ b/Completion/User/_perl_modules
@@ -42,5 +42,5 @@ if [[ ${+_perl_modules} -eq 0 ]]; then
 fi
 
 local expl
-_description expl "Perl modules"
-compadd "$expl[@]" - $_perl_modules
+
+_wanted modules expl 'Perl modules' && compadd "$expl[@]" - $_perl_modules
diff --git a/Completion/User/_ports b/Completion/User/_ports
index 9012dfd5e..ffd04ce5e 100644
--- a/Completion/User/_ports
+++ b/Completion/User/_ports
@@ -2,9 +2,6 @@
 
 local expl
 
-_tags any ports || return 1
-
 : ${(A)ports:=${${(M)${${(f)"$(</etc/services)"}:#\#*}#*/tcp}%%[ 	]*}}
 
-_description expl port
-compadd "$@" "$expl[@]" - "$ports[@]"
+_wanted ports expl port && compadd "$@" "$expl[@]" - "$ports[@]"
diff --git a/Completion/User/_rcs b/Completion/User/_rcs
index 272e54681..0831b1d0b 100644
--- a/Completion/User/_rcs
+++ b/Completion/User/_rcs
@@ -8,6 +8,5 @@ if [[ $compstate[nmatches] -eq nm && -d RCS && $words[1] != ci ]]; then
   local rep expl
 
   rep=(RCS/$PREFIX*$SUFFIX,v(:t:s/\,v//))
-  _description expl 'RCS file'
-  (( $#rep )) && compadd "$expl[@]" - $rep
+  (( $#rep )) && _wanted files expl 'RCS file' && compadd "$expl[@]" - $rep
 fi
diff --git a/Completion/User/_rlogin b/Completion/User/_rlogin
index 898f10870..d732cf8a9 100644
--- a/Completion/User/_rlogin
+++ b/Completion/User/_rlogin
@@ -38,25 +38,21 @@ _rlogin () {
     return ret
     ;;
   rcp)
-    local state line ret=1
+    local curcontext="$curcontext" state line ret=1
     typeset -A opt_args
 
-    _arguments -s \
+    _arguments -C -s \
       '-p[preserve modification times]' \
       '-r[recursively copy directories]' \
       '*:files:->files' && ret=0
 
     if [[ -n "$state" ]]; then
       if compset -P '*:'; then
-        _tags "$context" files || return 1
-
 	_files && ret=0
       elif compset -P '*@'; then
-        _tags "$context" hosts || return 1
-
-	_rlogin_hosts -S: -q && ret=0
+        _tags hosts && _rlogin_hosts -S: -q && ret=0
       else
-        _alternative "$context" \
+        _alternative \
 	    'files:: _files' \
 	    'hosts:: _rlogin_all_hosts -qS:' \
 	    'users:: _rlogin_users -qS@' && ret=0
@@ -68,24 +64,21 @@ _rlogin () {
 }
 
 _rlogin_users () {
-  _tags any users && _combination accounts_users_hosts users "$@"
+  _tags users && _combination accounts_users_hosts users "$@"
 }
 
 _rlogin_hosts () {
-  _tags any hosts || return 1
-
-  if [[ "$IPREFIX" == *@ ]]; then
-    _combination accounts_users_hosts "users=${IPREFIX/@}" hosts "$@"
-  else
-    _combination accounts_users_hosts \
-      ${opt_args[-l]:+"users=${opt_args[-l]:q}"} hosts "$@"
-  fi
+  _tags hosts &&
+      if [[ "$IPREFIX" == *@ ]]; then
+        _combination accounts_users_hosts "users=${IPREFIX/@}" hosts "$@"
+      else
+        _combination accounts_users_hosts \
+            ${opt_args[-l]:+"users=${opt_args[-l]:q}"} hosts "$@"
+      fi
 }
 
 _rlogin_all_hosts () {
-  _tags any hosts || return 1
-
-  _combination accounts_users_hosts hosts "$@"
+  _tags hosts && _combination accounts_users_hosts hosts "$@"
 }
 
 _rlogin "$@"
diff --git a/Completion/User/_socket b/Completion/User/_socket
index ad9232af9..b155e7ad4 100644
--- a/Completion/User/_socket
+++ b/Completion/User/_socket
@@ -5,19 +5,14 @@
 #  socket_hosts_ports
 #    The array that contains paris `host:port'.
 
-local context state line expl
+local curcontext="$curcontext" state line expl
 typeset -A opt_args
 
-if _tags any options &&
-   [[ $CURRENT -eq 2 && (
-      -z "$compconfig[option_prefix]" ||
-      "$compconfig[option_prefix]" = *\!${words[1]}* ||
-      "$PREFIX" = -* ) ]]; then
-  _description expl option
-  compadd -M 'r:|[_-]=* r:|=*' "$expl[@]" - -version
-fi
+[[ $CURRENT -eq 2 ]] && _wanted options expl option &&
+    { ! _style options prefix-needed || [[ "$PREFIX" = -* ]] } &&
+    compadd -M 'r:|[_-]=* r:|=*' "$expl[@]" - -version
 
-_arguments -s \
+_arguments -C -s \
   '-b[background]' \
   '-c[crlf]' \
   '-f[fork]' \
@@ -43,24 +38,17 @@ command)
 
 arg1)
   if (( $+opt_args[-s] )); then
-    _tags "$context" ports || return 1
-
-    _description expl 'port to listen'
-    _ports "$expl[@]"
+    _wanted ports expl 'port to listen' && _ports "$expl[@]"
   else
-    _tags "$context" hosts || return 1
-
-    _description expl 'host'
-    _combination socket_hosts_ports hosts "$expl[@]"
+    _wanted hosts expl 'host' &&
+        _combination socket_hosts_ports hosts "$expl[@]"
   fi
   ;;
 
 arg2)
   if (( ! $+opt_args[-s] )); then
-    _tags "$context" ports || return 1
-
-    _description expl 'port to connect'
-    _combination socket_hosts_ports hosts="${line[2]:q}" ports "$expl[@]"
+    _wanted ports expl 'port to connect' &&
+        _combination socket_hosts_ports hosts="${line[2]:q}" ports "$expl[@]"
   fi
   ;;
 esac
diff --git a/Completion/User/_ssh b/Completion/User/_ssh
index 2c71b49a0..e7c6d37f6 100644
--- a/Completion/User/_ssh
+++ b/Completion/User/_ssh
@@ -1,7 +1,7 @@
 #compdef ssh slogin scp ssh-add ssh-agent ssh-keygen
 
 _ssh () {
-  local context state lstate line ret=1 expl args tmp
+  local curcontext="$curcontext" state lstate line ret=1 expl args tmp
   typeset -A opt_args
 
   local accounts_users_hosts
@@ -27,7 +27,7 @@ _ssh () {
     )
     ;&
   ssh-opt)
-    _arguments -s \
+    _arguments -C -s \
       '-a[disable forwarding of authentication agent connection]' \
       '-c[select encryption cipher]:encryption cipher:(idea des 3des blowfish arcfour tss none)' \
       '-e[set escape character]:escape character (or `none'"'"'):' \
@@ -58,31 +58,25 @@ _ssh () {
         if compset -P '*[= ]'; then
           case "$IPREFIX" in
           *(#i)(batchmode|compression|fallbacktorsh|forward(agent|x11)|keepalive|passwordauthentication|rhosts(|rsa)authentication|rsaauthentication|usersh|kerberos(authetication|tgtparsing)|usepriviledgedport)*)
-	    _tags "$context" values && compadd yes no && ret=0
+	    _wanted values expl 'truth value' && compadd "$expl[@]" yes no &&
+                ret=0
             ;;
           *(#i)cipher*)
-	    if _tags "$context" values; then
-              _description expl 'encryption cipher'
-              compadd "$expl[@]" idea des 3des blowfish arcfour tss none && ret=0
-	    fi
+	    _wanted values expl 'encryption cipher' &&
+                compadd "$expl[@]" idea des 3des blowfish arcfour tss none && \
+                    ret=0
             ;;
           *(#i)globalknownhostsfile*)
-	    if _tags "$context" files; then
-              _description expl 'global file with known hosts'
-              _files "$expl[@]" && ret=0
-	    fi
+            _description expl 'global file with known hosts'
+            _files "$expl[@]" && ret=0
             ;;
           *(#i)hostname*)
-	    if _tags "$context" hosts; then
-              _description expl 'real host name to log into'
-              _ssh_hosts "$expl[@]" && ret=0
-	    fi
+	    _wanted hosts expl 'real host name to log into' &&
+                _ssh_hosts "$expl[@]" && ret=0
             ;;
           *(#i)identityfile*)
-	    if _tags "$context" files; then
-              _description expl 'SSH identity file'
-              _files "$expl[@]" && ret=0
-	    fi
+            _description expl 'SSH identity file'
+            _files "$expl[@]" && ret=0
             ;;
           *(#i)(local|remote)forward*)
             state=forward
@@ -94,44 +88,36 @@ _ssh () {
             _normal && ret=0
             ;;
           *(#i)stricthostkeychecking*)
-            _tags "$context" values && compadd yes no ask
+            _wanted values expl 'checking type' &&
+	        compadd "$expl[@]" yes no ask
             ;;
           *(#i)userknownhostsfile*)
-	    if _tags "$context" files; then
-              _description expl 'user file with known hosts'
-              _files "$expl[@]" && ret=0
-	    fi
+            _description expl 'user file with known hosts'
+            _files "$expl[@]" && ret=0
             ;;
           *(#i)user*)
-	    if _tags "$context" files; then
-              _description expl 'user to log in as'
-              _ssh_users "$expl[@]" && ret=0
-	    fi
+	    _wanted users expl 'user to log in as' &&
+                _ssh_users "$expl[@]" && ret=0
             ;;
           *(#i)xauthlocation*)
-	    if _tags "$context" files; then
-              _description expl 'xauth program'
-              _files "$expl[@]" -g '*(*)' && ret=0
-	    fi
+            _description expl 'xauth program'
+            _files "$expl[@]" -g '*(*)' && ret=0
             ;;
           esac
         else
-          if _tags "$context" values; then
-            _description expl 'configure file option'
-            compadd "$expl[@]" -M 'm:{a-z}={A-Z}' -S '=' - \
-                BatchMode ClearAllForwardings Cipher Compression \
-                CompressionLevel Host ConnectionAttempts EscapeChar \
-                FallBackToRsh ForwardAgent ForwardX11 \
-                GlobalKnownHostsFile HostName IdentityFile KeepAlive \
-                KerberosAuthentication KerberosTgtPassing LocalForward \
-                NumberOfPasswordPrompts PasswordAuthentication Port \
-                ProxyCommand RemoteForward RhostsAuthentication \
-                RhostsRSAAuthentication RSAAuthentication \
-                StrictHostKeyChecking TISAuthentication \
-                UsePriviledgedPort User UserKnownHostsFile UseRsh \
-                XAuthLocation \
-              && ret=0
-	  fi
+          _wanted values expl 'configure file option' &&
+              compadd "$expl[@]" -M 'm:{a-z}={A-Z}' -S '=' - \
+                  BatchMode ClearAllForwardings Cipher Compression \
+                  CompressionLevel Host ConnectionAttempts EscapeChar \
+                  FallBackToRsh ForwardAgent ForwardX11 \
+                  GlobalKnownHostsFile HostName IdentityFile KeepAlive \
+                  KerberosAuthentication KerberosTgtPassing LocalForward \
+                  NumberOfPasswordPrompts PasswordAuthentication Port \
+                  ProxyCommand RemoteForward RhostsAuthentication \
+                  RhostsRSAAuthentication RSAAuthentication \
+                  StrictHostKeyChecking TISAuthentication \
+                  UsePriviledgedPort User UserKnownHostsFile UseRsh \
+                  XAuthLocation && ret=0
         fi
         ;;
       forward)
@@ -139,7 +125,7 @@ _ssh () {
           if compset -P '*:'; then
             _message 'port number'
           else
-	    _tags "$context" hosts && _ssh_hosts -S: -q
+	    _wanted hosts expl host && _ssh_hosts -qS: "$expl[@]"
           fi
         else
           _message 'listen-port number'
@@ -154,17 +140,15 @@ _ssh () {
         ;;
       userhost)
         if compset -P '*@'; then
-	  if _tags "$context" hosts; then
-            _description expl 'remote host name'
-            _ssh_hosts "$expl[@]" && ret=0
-	  fi
+	  _wanted hosts expl 'remote host name' &&
+              _ssh_hosts "$expl[@]" && ret=0
         else
           if (( $+opt_args[-l] )); then
 	    tmp=()
 	  else
 	    tmp=( 'users:login name:_ssh_users -qS@' )
 	  fi
-	  _alternative "$context" \
+	  _alternative \
 	      'hosts:remote host name:_ssh_hosts' \
 	      "$tmp[@]" && ret=0
         fi
@@ -177,7 +161,7 @@ _ssh () {
     return ret
     ;;
   scp)
-    _arguments -s \
+    _arguments -C -s \
       '-c[select encryption cipher]:encryption cipher:(idea des 3des blowfish arcfour tss none)' \
       '-P[specify port on remote host]:port number on remote host:' \
       '-i[select identity file]:SSH identity file:_files' \
@@ -198,14 +182,14 @@ _ssh () {
       return
     elif [[ -n "$state" ]]; then
       if compset -P '*:'; then
-        _tags "$context" files && _files && ret=0
+        _files && ret=0
       elif compset -P '*@'; then
-        _tags "$context" hosts && _ssh_hosts -S: && ret=0
+        _wanted hosts expl host && _ssh_hosts -S: "$expl[@]" && ret=0
       else
-        _alternative "$context" \
+        _alternative \
 	    'files:: _files' \
-	    'hosts:: _ssh_hosts -S:' \
-	    'users:: _ssh_users -S@' && ret=0
+	    'hosts:host:_ssh_hosts -S:' \
+	    'users:user:_ssh_users -S@' && ret=0
       fi
     fi
     return ret
@@ -243,12 +227,10 @@ _ssh () {
 }
 
 _ssh_users () {
-  _tags any users && _combination accounts_users_hosts users "$@"
+  _combination accounts_users_hosts users "$@"
 }
 
 _ssh_hosts () {
-  _tags any hosts || return 1
-
   if [[ "$IPREFIX" == *@ ]]; then
     _combination accounts_users_hosts "users=${IPREFIX/@}" hosts "$@"
   else
diff --git a/Completion/User/_stty b/Completion/User/_stty
index 45408fbc1..06d0bf851 100644
--- a/Completion/User/_stty
+++ b/Completion/User/_stty
@@ -3,18 +3,19 @@
 local expl
 
 if [[ "$words[CURRENT-1]" = \
-  (*erase|discard|status|dsusp|intr|kill|lnext|quit|reprint|start|s*p) ]]
-then
-  _description expl 'control character'
-  compadd "$expl[@]" '^-' '^h' '^?' '^c' '^u'
+  (*erase|discard|status|dsusp|intr|kill|lnext|quit|reprint|start|s*p) ]]; then
+  _wanted characters expl 'control character' &&
+      compadd "$expl[@]" '^-' '^h' '^?' '^c' '^u'
 else
-  _description expl setting
   compset -P '[-+]'
-  compadd "$expl[@]" rows columns intr quit erase kill eof eol \
-    eol2 start stop susp dsusp reprint discard werase lnext \
-    parenb parodd cs8 cstopb hupcl cread clocal parext \
-    ignbrk brkint ignpar parmrk inpck istrip inlcr igncr icrnl iuclc \
-    ixon ixany ixoff imaxbel isig icanon xcase echo echoe echok \
-    echonl noflsh tostop echoctl echoprt echoke flusho pending iexten \
-    opost olcuc onlcr ocrnl onocr onlret ofill ofdel 
+  _wanted values expl setting &&
+      compadd "$expl[@]" rows columns intr quit erase kill eof eol \
+                         eol2 start stop susp dsusp reprint discard \
+			 werase lnext parenb parodd cs8 cstopb hupcl \
+			 cread clocal parext ignbrk brkint ignpar \
+			 parmrk inpck istrip inlcr igncr icrnl iuclc \
+			 ixon ixany ixoff imaxbel isig icanon xcase \
+			 echo echoe echok echonl noflsh tostop echoctl \
+			 echoprt echoke flusho pending iexten opost \
+			 olcuc onlcr ocrnl onocr onlret ofill ofdel 
 fi
diff --git a/Completion/User/_tar b/Completion/User/_tar
index d779f6cf1..defaaf39a 100644
--- a/Completion/User/_tar
+++ b/Completion/User/_tar
@@ -37,10 +37,10 @@ if [[ "$words[2]" = *[txcdruA]*~-* ]]; then
 elif [[ $_tar_cmd != *[txcdruA]* && CURRENT -gt 2 ]]; then
   # look for more obscure long options: these aren't all handled.
   (( $words[(I)--(diff|compare)] )) && _tar_cmd="d$_tar_cmd"
-  (( $words[(I)--append] )) && _tar_cmd="r$_tar_cmd"
-  (( $words[(I)--update] )) && _tar_cmd="u$_tar_cmd"
+  (( $words[(I)--append] ))         && _tar_cmd="r$_tar_cmd"
+  (( $words[(I)--update] ))         && _tar_cmd="u$_tar_cmd"
   (( $words[(I)--(con|)catenate] )) && _tar_cmd="A$_tar_cmd"
-  (( $words[(I)--delete] )) && del=1
+  (( $words[(I)--delete] ))         && del=1
 fi
 
 # Next, we try to find the archive name and store it in `tf'. The name 
@@ -107,8 +107,8 @@ elif [[ ( "$_tar_cmd" = *[xt]* || -n $del ) && -n "$tf" ]]; then
     _tar_cache_name=$tf
   fi
 
-  _description expl 'file from archive'
-  _multi_parts "$expl[@]" / _tar_cache_list
+  _wanted archived-files expl 'file from archive' &&
+      _multi_parts "$expl[@]" / _tar_cache_list
 else
   
   # See if we should use a path prefix.  We have to use eval as the dir can
diff --git a/Completion/User/_telnet b/Completion/User/_telnet
index 8e584b040..597c0a021 100644
--- a/Completion/User/_telnet
+++ b/Completion/User/_telnet
@@ -5,7 +5,7 @@
 #  telnet_hosts_ports_users
 #    The array that contains 3-tuples `host:port:user'.
 
-local context state line expl
+local curcontext="$curcontext" state line expl
 typeset -A opt_args
 
 if (( ! $+_telnet_short )); then
@@ -52,44 +52,36 @@ if (( ! $+_telnet_short )); then
   done
 fi
 
-if _tags any options && (( $#_telnet_long )) &&
-   { ! _style options prefix-needed yes || [[ "$PREFIX" = [-+]* ]] } ; then
-  _description expl 'option'
-  _describe -o option _telnet_long "$expl[@]"
-fi
+(( $#_telnet_long )) && _wanted options expl option &&
+   { ! _style options prefix-needed || [[ "$PREFIX" = [-+]* ]] } &&
+    _describe -o option _telnet_long "$expl[@]"
 
-_arguments -s \
+_arguments -C -s \
   "$_telnet_short[@]" \
   ':host:->hosts' \
   ':port:->ports'
 
 case "$state" in
 hosts)
-  _tags "$context" hosts || return 1
-
-  _description expl 'host'
-  _combination telnet_hosts_ports_users \
-    ${opt_args[-l]:+users=${opt_args[-l]:q}} \
-    hosts "$expl[@]"
+  _wanted hosts expl host &&
+      _combination telnet_hosts_ports_users \
+          ${opt_args[-l]:+users=${opt_args[-l]:q}} \
+          hosts "$expl[@]"
   ;;
 
 ports)
-  _tags "$context" ports || return 1
-
-  _description expl 'port'
-  _combination telnet_hosts_ports_users \
-    ${opt_args[-l]:+users=${opt_args[-l]:q}} \
-    hosts="${line[2]:q}" \
-    ports "$expl[@]"
+  _wanted ports expl port &&
+      _combination telnet_hosts_ports_users \
+          ${opt_args[-l]:+users=${opt_args[-l]:q}} \
+          hosts="${line[2]:q}" \
+          ports "$expl[@]"
   ;;
 
 users)
-  _tags "$context" users || return 1
-
-  _description expl 'user'
-  _combination telnet_hosts_ports_users \
-    ${line[2]:+hosts="${line[2]:q}"} \
-    ${line[3]:+ports="${line[3]:q}"} \
-    users "$expl[@]"
+  _wanted users expl user &&
+      _combination telnet_hosts_ports_users \
+      ${line[2]:+hosts="${line[2]:q}"} \
+      ${line[3]:+ports="${line[3]:q}"} \
+      users "$expl[@]"
   ;;
 esac
diff --git a/Completion/User/_tiff b/Completion/User/_tiff
index e3a023c24..27ab33227 100644
--- a/Completion/User/_tiff
+++ b/Completion/User/_tiff
@@ -19,12 +19,12 @@ fi
 
 local _in_tiff=yes
 
-local context state line ret=1
+local curcontext="$curcontext" state line ret=1
 typeset -A opt_args
 
 case "$words[1]" in
 tiff2bw)
-  _arguments \
+  _arguments -C \
     '-c[specify compression scheme]:compression scheme:->compress' \
     '-r[specify rows per strip]:rows per strip:' \
     '-R[specify percentage of red channel]:percentage of red channel:' \
@@ -59,7 +59,7 @@ tiffcmp)
     ':second input TIFF file:_files -g \*.\(\#i\)' && ret=0
   ;;
 tiffcp)
-  _arguments \
+  _arguments -C \
     '-B[write output in bin-endian byte order]' \
     '-c[specify compression scheme]:compression scheme:->compress' \
     '-o[set initial TIFF directory (file offset)]:file offset:' \
@@ -74,7 +74,7 @@ tiffcp)
     '*:input TIFF file:_files -g \*.\(\#i\)' && ret=0
   ;;
 tiffdither)
-  _arguments \
+  _arguments -C \
     '-c[specify compression scheme]:compression scheme:->compress' \
     '-f[specify fill order]:fill order:(lsb2msb msb2lsb)' \
     '-r[specify rows per strip]:rows per strip:' \
@@ -102,7 +102,7 @@ tiffinfo)
     '*:input TIFF file:_files -g \*.\(\#i\)' && ret=0
   ;;
 tiffmedian)
-  _arguments \
+  _arguments -C \
     '-r[specify rows per strip]:rows per strip:' \
     '-C[specify number of colormap entries]:number of colormap entries:' \
     '-c[specify compression scheme]:compression scheme:->compress' \
@@ -135,14 +135,14 @@ fax2tiff)
     ':FAX input file:_files -g \*.\(\#i\)\(g\[34\]\|fax\)' && ret=0
   ;;
 gif2tiff)
-  _arguments \
+  _arguments -C \
     '-r[specify rows per strip]:rows per strip:' \
     '-c[specify compression scheme]:compression scheme:->compress' \
     ':input GIF file:_files -g \*.\(\#i\)gif' \
     ':output file:_files -g \*.\(\#i\)tiff' && ret=0
   ;;
 ppm2tiff)
-  _arguments \
+  _arguments -C \
     '-r[specify rows per strip]:rows per strip:' \
     '-c[specify compression scheme]:compression scheme:->compress' \
     '-R[specify resolution]:resolution:' \
@@ -150,14 +150,14 @@ ppm2tiff)
     ':output file:_files -g \*.\(\#i\)tiff' && ret=0
   ;;
 ras2tiff)
-  _arguments \
+  _arguments -C \
     '-r[specify rows per strip]:rows per strip:' \
     '-c[specify compression scheme]:compression scheme:->compress' \
     ':input raster image file:_files -g \*.\(\#i\)ras\(\|t\)' \
     ':output file:_files -g \*.\(\#i\)tiff' && ret=0
   ;;
 pal2rgb)
-  _arguments \
+  _arguments -C \
     '-C[specify number of bits for colormap entries]:bits for colormap entries:(8 16)' \
     '-p[set sample packing]:sample packing:(contig separate)' \
     '-c[specify compression scheme]:compression scheme:->compress' \
@@ -194,11 +194,10 @@ if [[ -n "$state" ]]; then
       ;;
     esac
   else
-    _tags "$context" values || return 1
-
-    _description expl 'compression scheme'
-    compadd "$expl[@]" - none g4 packbits && ret=0
-    compadd "$expl[@]" -qS: - lzw zip jpeg g3 && ret=0
+    if _wanted values expl 'compression scheme'; then
+      compadd "$expl[@]" - none g4 packbits && ret=0
+      compadd "$expl[@]" -qS: - lzw zip jpeg g3 && ret=0
+    fi
   fi
 fi
 
diff --git a/Completion/User/_urls b/Completion/User/_urls
index 8c0c6f8d8..787f3c0ca 100644
--- a/Completion/User/_urls
+++ b/Completion/User/_urls
@@ -4,9 +4,9 @@
 # Options:
 #  -f : complete files first.
 #
-# Configuration keys used:
+# Configuration styles used:
 #
-#  urls_path
+#  urls:path
 #    The path to a directory containing a URL database, such as:
 #
 #      % cd ~/.zsh/urls
@@ -29,90 +29,91 @@
 #      % cat bookmark/zsh/meta
 #      http://www.zsh.org/
 #
-#  urls_localhttp
-#    Specify a local web server in the form:
-#      hostname:doc root:user area
+#  urls:local
+#    Specify a local web server as an array with three elements:
+#      <hostname> <doc root> <user area>
 #    where hostname is the name of the web server, doc root is the path to
 #    the default web pages for the server and user area is the directory
 #    name used by a user placing web pages within their home area.
-#    e.g. compconf urls_localhttp=www:/usr/local/apache/htdocs:public_html
+#    E.g.:
+#      compstyle '*:urls:local' www /usr/local/apache/htdocs public_html
 
 local ipre scheme host user uhosts ret=1 expl
-local urls_path="${compconfig[urls_path]:-${ZDOTDIR:-$HOME}/.zsh/urls}"
-local localhttp_servername="${${(@s.:.)compconfig[urls_localhttp]}[1]}"
-local localhttp_documentroot="${${(@s.:.)compconfig[urls_localhttp]}[2]}"
-local localhttp_userdir="${${(@s.:.)compconfig[urls_localhttp]}[3]}"
+local urls_path localhttp
+_style -s urls path urls_path || urls_path="${ZDOTDIR:-$HOME}/.zsh/urls"
+_style -a urls local localhttp
+local localhttp_servername="$localhttp[1]"
+local localhttp_documentroot="$localhttp[2]"
+local localhttp_userdir="$localhttp[3]"
 
 if [[ "$1" = -f ]]; then
   shift
-  _tags argument:-f files && _files "$@" && return
+  _tags -C -f files && _files "$@" && return
 fi
 
 ipre="$IPREFIX"
 
 if ! compset -P '(#b)([-+.a-z0-9]#):' &&
-   _tags argument prefixes; then
-  _description expl 'URL prefix'
+   _wanted argument prefixes expl 'URL prefix'; then
   [[ -d $urls_path/bookmark ]] &&
     compadd "$@" "$expl[@]" -S '' bookmark: && ret=0
   compadd "$@" "$expl[@]" -S '' file: ftp:// gopher:// http:// && ret=0
-  return $ret
+  return ret
 fi
 scheme="$match[1]"
 
 case "$scheme" in
   http|ftp|gopher)
     if ! compset -P //; then
-      _tags "$scheme" slashes && compadd "$@" -S '' //
+      _wanted -C "$scheme" slashes expl 'end of prefix' &&
+          compadd "$expl[@]" "$@" -S '' //
       return
     fi
   ;;
   file)
     if ! compset -P //; then
-      _tags file files || return 1
+      _wanted -C file files expl 'local file' || return 1
 
       if [[ -prefix / ]]; then
-	_path_files "$@" -S '' -g '*(^/)' && ret=0
-	_path_files "$@" -S/ -r '/' -/ && ret=0
+	_path_files "$expl[@]" "$@" -S '' -g '*(^/)' && ret=0
+	_path_files "$expl[@]" "$@" -S/ -r '/' -/ && ret=0
       elif [[ -z "$PREFIX" ]]; then
-	compadd -S '/' -r '/' - "${PWD%/}"
-	ret=0
+	compadd "$expl[@]" -S '/' -r '/' - "${PWD%/}" && ret=0
       fi
-      return $ret
+      return ret
     fi
   ;;
   bookmark)
     if [[ -f "$urls_path/$scheme/$PREFIX$SUFFIX" &&
 	  -s "$urls_path/$scheme/$PREFIX$SUFFIX" ]]; then
-      _tags bookmark caches || return 1
-
-      compadd "$@" -QU -- "$ipre$(<"$urls_path/$scheme/$PREFIX$SUFFIX")" && ret=0
+      _wanted -C bookmark caches expl biikmarks &&
+          compadd "$expl[@]" "$@" -QU - \
+              "$ipre$(<"$urls_path/$scheme/$PREFIX$SUFFIX")" && ret=0
     else
-      _tags bookmark files || return 1
-
-      _description expl 'bookmark'
-      _path_files -W "$urls_path/$scheme" "$expl[@]" -S '' -g '*(^/)' && ret=0
-      _path_files -W "$urls_path/$scheme" -S/ -r '/' -/ && ret=0
+      if _wanted -C bookmark files 'bookmark'; then
+        _path_files -W "$urls_path/$scheme" "$expl[@]" -S '' -g '*(^/)' && 
+            ret=0
+        _path_files -W "$urls_path/$scheme" -S/ -r '/' -/ && ret=0
+      fi
     fi
-    return $ret
+    return ret
   ;;
 esac
 
 # Complete hosts
 if ! compset -P '(#b)([^/]#)/' &&
-   _tags argument hosts; then
+   _wanted hosts expl host; then
   uhosts=($urls_path/$scheme/$PREFIX*$SUFFIX(/:t))
   (( $#uhosts )) || _hosts -S/ && ret=0
   [[ "$scheme" = http ]] && uhosts=($uhosts $localhttp_servername)
-  _description expl host
   compadd "$expl[@]" "$@" -QS/ - $uhosts && ret=0
-  return $ret
+  return ret
 fi
 host="$match[1]"
 
 # Complete part after hostname
 
-_tags local files || return 1
+_wanted -C local files expl 'local file' || return 1
 
 if [[ "$localhttp_servername" = "$host" ]]; then
   if compset -P \~; then
@@ -121,14 +122,14 @@ if [[ "$localhttp_servername" = "$host" ]]; then
       return
     fi
     user="$match[1]"
-    _path_files -W ~$user/$localhttp_userdir -g '*(^/)' && ret=0
-    _path_files -W ~$user/$localhttp_userdir -S/ -r '/' -/ && ret=0
+    _path_files "$expl[@]" -W ~$user/$localhttp_userdir -g '*(^/)' && ret=0
+    _path_files "$expl[@]" -W ~$user/$localhttp_userdir -S/ -r '/' -/ && ret=0
   else
-    _path_files -W $localhttp_documentroot -g '*(^/)' && ret=0
-    _path_files -W $localhttp_documentroot -S/ -r '/' -/ && ret=0
+    _path_files "$expl[@]" -W $localhttp_documentroot -g '*(^/)' && ret=0
+    _path_files "$expl[@]" -W $localhttp_documentroot -S/ -r '/' -/ && ret=0
   fi
 else
-  _path_files -W $urls_path/$scheme/$host -g '*(^/)' && ret=0
-  _path_files -W $urls_path/$scheme/$host -S/ -r '/' -/ && ret=0
+  _path_files "$expl[@]" -W $urls_path/$scheme/$host -g '*(^/)' && ret=0
+  _path_files "$expl[@]" -W $urls_path/$scheme/$host -S/ -r '/' -/ && ret=0
 fi
 return $ret
diff --git a/Completion/User/_use_lo b/Completion/User/_use_lo
index 56651dd67..5f2210997 100644
--- a/Completion/User/_use_lo
+++ b/Completion/User/_use_lo
@@ -3,6 +3,4 @@
 # This is for GNU-like commands which understand the --help option,
 # but which do not otherwise require special completion handling.
 
-[[ "$PREFIX" = --* ]] && _arguments -- && return 0
-
-_default
+_arguments || _default
diff --git a/Completion/User/_user_at_host b/Completion/User/_user_at_host
index c33a024d9..1f93daacc 100644
--- a/Completion/User/_user_at_host
+++ b/Completion/User/_user_at_host
@@ -1,17 +1,13 @@
 #autoload
 
 if [[ -prefix 1 *@ ]]; then
-
-  _tags any:user-at hosts || return 1
-
   local user=${PREFIX/@}
 
   compset -P 1 '*@'
-  _description expl "hostnames for $user"
-  _combination accounts_users_hosts users="$user" hosts "$expl[@]" "$@"
-else
-  _tags any users || return 1
 
-  _description expl "usernames"
-  _combination accounts_users_hosts users -S@ -q "$expl[@]" "$@"
+  _wanted -C user-at hosts expl "hostnames for $user" &&
+      _combination accounts_users_hosts users="$user" hosts "$expl[@]" "$@"
+else
+  _wanted users expl "usernames" &&
+      _combination accounts_users_hosts users -S@ -q "$expl[@]" "$@"
 fi
diff --git a/Completion/User/_users b/Completion/User/_users
index 9f2751c11..fdef36073 100644
--- a/Completion/User/_users
+++ b/Completion/User/_users
@@ -5,9 +5,7 @@
 
 local expl
 
-_tags any users || return 1
-
-_description expl user
+_wanted users expl user || return 1
 
 [[ "${(t)users}" = *array* ]] &&
     compadd "$expl[@]" "$@" - "$users[@]" && return 0
diff --git a/Completion/User/_users_on b/Completion/User/_users_on
index 221ebb0fd..3d35af02b 100644
--- a/Completion/User/_users_on
+++ b/Completion/User/_users_on
@@ -2,7 +2,7 @@
 
 local expl
 
-_tags any users || return 1
+_tags users || return 1
 
 if which users >/dev/null; then
   _description expl 'users logged on'
diff --git a/Completion/User/_wget b/Completion/User/_wget
index 3a15d3867..8e73bd45d 100644
--- a/Completion/User/_wget
+++ b/Completion/User/_wget
@@ -1,11 +1,11 @@
 #compdef wget
 
-local context state line
+local curcontext="$curcontext" state line
 typeset -A opt_args
 
 local tmp1 tmp2
 
-_arguments -s \
+_arguments -C -s \
   '(--version)-V[version]' '(-V)--version' \
   '(--help)-h[help]' '(-h)--help' \
   '(--background)-b[background]' '(-b)--background' \
diff --git a/Completion/User/_whois b/Completion/User/_whois
index 1e0f7707c..97306871e 100644
--- a/Completion/User/_whois
+++ b/Completion/User/_whois
@@ -102,7 +102,7 @@ _whois_setup () {
       if (( $#opts )); then opts="($opts)"; else opts=; fi
       if [[ $opt = h ]]; then
 	_whois_arguments=("$_whois_arguments[@]"
-	  "${opts}${hostopt}[specify host]:host:_whois_hosts")
+	  "${opts}${hostopt}:host:_whois_hosts")
       else
 	_whois_arguments=("$_whois_arguments[@]"
 	  "${opts}-${opt}[${${(@M)_whois_servers:#*:$opt}%:?}]")
@@ -112,11 +112,11 @@ _whois_setup () {
 }
 
 _whois_single () {
-  local context state line expl
+  local curcontext="$curcontext" state line expl
   typeset -A opt_args
   local tmp host
 
-  _arguments \
+  _arguments -C \
     "$_whois_arguments[@]" \
     ':identifier:->identifier'
 
@@ -144,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'
 
@@ -189,14 +189,14 @@ _whois_fwhois () {
 }
 
 _whois_hosts () {
-  _tags any hosts &&
+  _tags hosts &&
     compadd "$@" \
       -M 'm:{a-zA-Z}={A-Za-z} r:|.=* r:|=*' \
       - ${_whois_servers%:?} || _hosts "$@"
 }
 
 _whois_ports () {
-  _tags any ports && compadd "$@" - whois || _ports "$@"
+  _tags ports && compadd "$@" - whois || _ports "$@"
 }
 
 (( $+functions[_whois:whois.internic.net] )) ||
@@ -204,10 +204,7 @@ _whois:whois.internic.net () {
   if (( CURRENT == 1 )); then
     local expl
 
-    _tags any string || return 1
-
-    _description expl string
-    compadd "$expl[@]" HELP DOMAIN HOST
+    _wanted string expl string && compadd "$expl[@]" HELP DOMAIN HOST
   else
     _message 'string'
   fi
@@ -218,10 +215,7 @@ _whois:whois.nic.ad.jp () {
   if (( CURRENT == 1 )); then
     local expl
 
-    _tags any string || return 1
-
-    _description expl string
-    compadd HELP DOM NET HOST PERSON CONN COM
+    _wanted string expl string && compadd HELP DOM NET HOST PERSON CONN COM
   else
     _message 'string'
   fi
diff --git a/Completion/User/_yp b/Completion/User/_yp
index d0876f6dd..1e86bf278 100644
--- a/Completion/User/_yp
+++ b/Completion/User/_yp
@@ -1,6 +1,6 @@
 #compdef ypcat ypmatch yppasswd ypwhich ypset ypserv ypbind yppush yppoll ypxfr domainname
 
-local context line state ret=1
+local curcontext="$curcontext" line state ret=1
 typeset -A opt_args
 
 if (( ! $+_yp_cache_maps )); then
@@ -16,17 +16,17 @@ fi
 
 case "$words[1]" in
 ypcat)
-  _arguments -s "$_yp_args[@]" ':map name:->map' && ret=0
+  _arguments -C -s "$_yp_args[@]" ':map name:->map' && ret=0
   ;;
 ypmatch)
-  _arguments -s "$_yp_args[@]" '*::key map:->keymap' && ret=0
+  _arguments -C -s "$_yp_args[@]" '*::key map:->keymap' && ret=0
   ;;
 yppasswd)
   _users
   return
   ;;
 ypwhich)
-  _arguments \
+  _arguments -C \
     '(-x)-d[specify domain]:domain name:' \
     '(-x -V2 -m -t)-V1[identify version 1 servers]' \
     '(-x -V1 -m -t)-V2[identify version 2 servers]' \
@@ -36,7 +36,7 @@ ypwhich)
     ':host:_hosts' && ret=0
   ;;
 ypset)
-  _arguments \
+  _arguments -C \
     '(-V2)-V1[bind version 1 servers]' \
     '(-V1)-V2[bind version 2 servers]' \
     '-d[specify domain]:domain name:' \
@@ -44,30 +44,30 @@ ypset)
     ':server:_hosts' && ret=0
     ;;
 ypserv)
-  _arguments \
+  _arguments -C \
     '-a[specify database routines]:database routines:((b\:btree d\:dbm/ndbm h\:hash))' && ret=0
   ;;
 ypbind)
-  _arguments \
+  _arguments -C \
     '-s[allow secure mode for ypbind]' \
     '-S[set domain and servers]:domain:->servers' \
     '(-ypsetme)-ypset[accept all ypset requests]' \
     '(-ypset)-ypsetme[accept only local ypset requests]' && ret=0
   ;;
 yppush)
-  _arguments \
+  _arguments -C \
     '-d[specify domain]:domain name:' \
     '-v[print messages]' \
     ':map name:->map' && ret=0
   ;;
 yppoll)
-  _arguments \
+  _arguments -C \
     '-d[specify domain]:domain name:' \
     '-h[specify host]:ask server on host:_hosts' \
     ':map name:->map' && ret=0
   ;;
 ypxfr)
-  _arguments \
+  _arguments -C \
     '-a[specify database routines]:database routines:((b\:btree d\:dbm/ndbm h\:hash))' \
     '-f[force transfer]' \
     '-c[don'"'"'t clear current map]' \
@@ -88,30 +88,22 @@ if [[ "$state" = map* ]]; then
   local expl
 
   if [[ $+opt_args[-t] -eq 0 && "$state" != maponly ]]; then
-    _tags "$context" maps nicknames
+    _tags maps nicknames
   else
-    _tags "$context" maps
+    _tags maps
   fi
 
   while _tags; do
-    if _requested maps; then
-      # The `-M ...' allows `pa.n<TAB>' to complete to `passwd.byname'.
-
-      _description expl 'map name'
-      compadd "$expl[@]" -M 'l:.|by=by l:.|=by r:|.=* r:|=*' - \
-              "$_yp_cache_maps[@]" && ret=0
-    fi
-    if _requested nicknames; then
-      _description expl 'nicknames'
-      compadd "$expl[@]" - "$_yp_cache_nicks[@]" && ret=0
-    fi
+    # The `-M ...' allows `pa.n<TAB>' to complete to `passwd.byname'.
+    _requested maps expl 'map name' &&
+        compadd "$expl[@]" -M 'l:.|by=by l:.|=by r:|.=* r:|=*' - \
+                "$_yp_cache_maps[@]" && ret=0
+    _requested nicknames expl nicknames &&
+        compadd "$expl[@]" - "$_yp_cache_nicks[@]" && ret=0
   done
 elif [[ "$state" = servers ]]; then
   if compset -P '*,'; then
-    if _tags "$context" hosts; then
-      _description expl 'server'
-      _hosts -qS, && ret=0
-    fi
+    _wanted hosts expl server && _hosts -qS, && ret=0
   else
     _message 'domain name'
   fi
diff --git a/Completion/X/_x_arguments b/Completion/X/_x_arguments
index 396a39ea2..b820b50b0 100644
--- a/Completion/X/_x_arguments
+++ b/Completion/X/_x_arguments
@@ -1,11 +1,20 @@
 #compdef -P */X11/*
 
-local ret
+local ret long xargs
 
-_arguments \
-  '-display:display:_x_display' \
-  '-geometry:geometry:_x_geometry' \
-  "$@"
+xargs=(
+  '-display:display:_x_display'
+  '-geometry:geometry:_x_geometry'
+)
+
+long=$argv[(I)--]
+if (( long )); then
+  argv[long]=( "$xargs[@]" -- )
+else
+  set -- "$@" "$xargs[@]"
+fi
+
+_arguments "$@"
 
 ret=$?
 
diff --git a/Completion/X/_x_color b/Completion/X/_x_color
index 4c1c73bf4..2daeb51d6 100644
--- a/Completion/X/_x_color
+++ b/Completion/X/_x_color
@@ -15,8 +15,9 @@ if (( ! $+_color_cache )); then
 
   # Cache of color names doesn't exist yet, create it.
 
-  if [[ -n "$compconfig[colors_path]" ]]; then
-    _color_cache=( "${(@)${(@f)$(< $compconfig[colors_path])}[2,-1]##*		}" )
+  _style -s colors path file
+  if [[ -n "$file" ]]; then
+    _color_cache=( "${(@)${(@f)$(< $file)}[2,-1]##*		}" )
   else
     file=( /usr/{lib,{{X11R6,openwin},local{,/X11{,R6}}}/lib}/X11/rgb.txt(N) )
 
@@ -29,8 +30,6 @@ if (( ! $+_color_cache )); then
   (( $#_color_cache )) || _color_cache=(white black gray red blue green)
 fi
 
-_tags any colors || return 1
-
-_description expl 'color specification'
-compadd "$@" "$expl[@]" -M 'm:{a-z}={A-Z} m:-=\  r:|[ A-Z0-9]=* r:|=*' - \
-        "$_color_cache[@]"
+_wanted colors expl 'color specification' &&
+    compadd "$@" "$expl[@]" -M 'm:{a-z}={A-Z} m:-=\  r:|[ A-Z0-9]=* r:|=*' - \
+            "$_color_cache[@]"
diff --git a/Completion/X/_x_cursor b/Completion/X/_x_cursor
index a22189f9d..8b057a537 100644
--- a/Completion/X/_x_cursor
+++ b/Completion/X/_x_cursor
@@ -14,7 +14,5 @@ if (( ! $+_cursor_cache )); then
   fi
 fi
 
-_tags any cursors || return 1
-
-_description expl 'cursor name'
-compadd "$@" "$expl[@]" -M 'm:-=_ r:|_=*' - "$_cursor_cache[@]"
+_wanted cursors expl 'cursor name' &&
+    compadd "$@" "$expl[@]" -M 'm:-=_ r:|_=*' - "$_cursor_cache[@]"
diff --git a/Completion/X/_x_display b/Completion/X/_x_display
index 7b9fbab9a..f547a64fa 100644
--- a/Completion/X/_x_display
+++ b/Completion/X/_x_display
@@ -1,5 +1,3 @@
 #autoload
 
-_tags any displays || return 1
-
-_hosts -S ':0 ' -r :
+_tags displays && _hosts -S ':0 ' -r :
diff --git a/Completion/X/_x_extension b/Completion/X/_x_extension
index 44e47d956..9321f4951 100644
--- a/Completion/X/_x_extension
+++ b/Completion/X/_x_extension
@@ -2,12 +2,10 @@
 
 local expl
 
-_tags any extensions || return 1
+_wanted extensions expl 'X extensions' || return 1
 
 (( $+_xe_cache )) || _xe_cache=( "${(@)${(@f)$(xdpyinfo)}[(r)number of extensions:*,-1][2,(r)default screen number:*][1,-2]//[      ]}" )
 
-_description expl 'X extension'
-
 if [[ "$1" = -a ]]; then
   shift
 
diff --git a/Completion/X/_x_font b/Completion/X/_x_font
index f4dfef79c..59c628d6d 100644
--- a/Completion/X/_x_font
+++ b/Completion/X/_x_font
@@ -2,7 +2,7 @@
 
 local expl
 
-_tags any fonts || return 1
+_wanted fonts expl font || return 1
 
 # This *has* to be improved some day...
 
@@ -12,5 +12,4 @@ if (( ! $+_font_cache )); then
  _font_cache=( "${(@)^${(@f)$(xlsfonts)}%%--*}--" )
 fi
 
-_description expl font
 compadd -M 'r:|-=* r:|=*' "$expl[@]" "$@" -S '' - "$_font_cache[@]"
diff --git a/Completion/X/_x_keysym b/Completion/X/_x_keysym
index fc2847c57..2e8f037b1 100644
--- a/Completion/X/_x_keysym
+++ b/Completion/X/_x_keysym
@@ -2,7 +2,7 @@
 
 local expl
 
-_tags any keysyms || return 1
+_wanted keysyms expl 'key symbol' || return 1
 
 if (( ! $+_keysym_cache )); then
   local file
@@ -18,5 +18,4 @@ if (( ! $+_keysym_cache )); then
   fi
 fi
 
-_description expl 'key symbol'
 compadd "$@" "$expl[@]" -M 'm:{a-z}={A-Z} r:|-=* r:|=*' - $_keysym_cache
diff --git a/Completion/X/_x_modifier b/Completion/X/_x_modifier
index 345243835..01052da65 100644
--- a/Completion/X/_x_modifier
+++ b/Completion/X/_x_modifier
@@ -2,8 +2,6 @@
 
 local expl
 
-_tags any modifiers || return 1
-
-_description expl modifier
-compadd "$@" "$expl[@]" -M 'm:{a-z}={A-Z}' - \
-        Shift Lock Control Mod1 Mod2 Mod3 Mod4 Mod5
+_wanted modifiers expl modifier &&
+    compadd "$@" "$expl[@]" -M 'm:{a-z}={A-Z}' - \
+            Shift Lock Control Mod1 Mod2 Mod3 Mod4 Mod5
diff --git a/Completion/X/_x_window b/Completion/X/_x_window
index 6d6e3112e..bf0ad4d33 100644
--- a/Completion/X/_x_window
+++ b/Completion/X/_x_window
@@ -2,7 +2,7 @@
 
 local list expl
 
-_tags any windows || return 1
+_tags windows || return 1
 
 list=( "${(@)${(M@)${(@f)$(xwininfo -root -tree)}:#[ 	]#0x[0-9a-f]# \"*}##[ 	]#}" )
 
diff --git a/Completion/X/_xmodmap b/Completion/X/_xmodmap
index d8ba420ce..e1594b949 100644
--- a/Completion/X/_xmodmap
+++ b/Completion/X/_xmodmap
@@ -1,9 +1,9 @@
 #compdef xmodmap
 
-local context state line ret=1
+local curcontext="$curcontext" state line ret=1
 typeset -A opt_args
 
-_x_arguments \
+_x_arguments -C \
   -{help,grammar,verbose,quiet} \
   '-n[only show what would be done]' \
   '*-e[specify expression]:expression:->expr' \
@@ -82,8 +82,7 @@ if [[ -n "$state" ]]; then
     [[ "$what" = *ksym* ]] && _x_keysym "$suf[@]" && ret=0
 
   else
-    if _tags any commands; then
-      _description expl command
+    if _wanted commands expl command; then
       compadd "$expl[@]" -S ' ' keycode keysym clear add remove && ret=0
       compadd "$expl[@]" -S ' = ' pointer && ret=0
     fi
diff --git a/Completion/X/_xt_arguments b/Completion/X/_xt_arguments
index 2604cfa83..4b40500f3 100644
--- a/Completion/X/_xt_arguments
+++ b/Completion/X/_xt_arguments
@@ -20,30 +20,39 @@
 
 # cf. XrmParseCommand(3X11), X11R6.4/xc/lib/Xt/Initialize.c, X(5)
 
-local ret
-
-_arguments \
-  -+{rv,synchronous} \
-  -{reverse,iconic} \
-  '-background:background color:_x_color' \
-  '-bd:border color:_x_color' \
-  '-bg:background color:_x_color' \
-  '-bordercolor:border color:_x_color' \
-  '-borderwidth:border width:_x_borderwidth' \
-  '-bw:border width:_x_borderwidth' \
-  '-display:display:_x_display' \
-  '-fg:foreground color:_x_color' \
-  '-font:font:_x_font' \
-  '-fn:font:_x_font' \
-  '-foreground:foreground color:_x_color' \
-  '-geometry:geometry:_x_geometry' \
-  '-name:name:_x_name' \
-  '-selectionTimeout:selection timeout (milliseconds):_x_selection_timeout' \
-  '-title:title:_x_title' \
-  '-xnllanguage:locale:_x_locale' \
-  '-xrm:resource:_x_resource' \
-  '-xtsessionID:session ID:_xt_session_id' \
-  "$@"
+local ret long xargs
+
+xargs=(
+  -+{rv,synchronous}
+  -{reverse,iconic}
+  '-background:background color:_x_color'
+  '-bd:border color:_x_color'
+  '-bg:background color:_x_color'
+  '-bordercolor:border color:_x_color'
+  '-borderwidth:border width:_x_borderwidth'
+  '-bw:border width:_x_borderwidth'
+  '-display:display:_x_display'
+  '-fg:foreground color:_x_color'
+  '-font:font:_x_font'
+  '-fn:font:_x_font'
+  '-foreground:foreground color:_x_color'
+  '-geometry:geometry:_x_geometry'
+  '-name:name:_x_name'
+  '-selectionTimeout:selection timeout (milliseconds):_x_selection_timeout'
+  '-title:title:_x_title'
+  '-xnllanguage:locale:_x_locale'
+  '-xrm:resource:_x_resource'
+  '-xtsessionID:session ID:_xt_session_id'
+)
+
+long=$argv[(I)--]
+if (( long )); then
+  argv[long]=( "$xargs[@]" -- )
+else
+  set -- "$@" "$xargs[@]"
+fi
+
+_arguments "$@"
 
 ret=$?
 
diff --git a/Completion/X/_xutils b/Completion/X/_xutils
index 27518e0cf..ed208dfe5 100644
--- a/Completion/X/_xutils
+++ b/Completion/X/_xutils
@@ -49,9 +49,9 @@ xhost)
   local expl type ret=1
 
   if compset -P '-'; then
-    _description expl 'disallow access'
-    compadd "$expl[@]" -M 'm:{a-z}={A-Z} r:|[:.]=* r:|=*' - \
-        "${${(@M)${(@f)$(xhost)}[2,-1]:#LOCAL:*}#INET:}"
+    _wanted displays expl 'disallow access' &&
+        compadd "$expl[@]" -M 'm:{a-z}={A-Z} r:|[:.]=* r:|=*' - \
+                "${${(@M)${(@f)$(xhost)}[2,-1]:#LOCAL:*}#INET:}"
   else
     compset -P +
 
@@ -66,9 +66,9 @@ xhost)
       krb)  _message 'Kerberos V5 principal';;
       esac
     else
-      _description expl 'name family'
-      compadd -S: - inet dnet nis krb && ret=0
-      _hosts && ret=0
+      _alternative \
+          'families:name family:compadd -S: - inet dnet nis krb' \
+	  'hosts:: _hosts' && ret=0
     fi
     return ret
   fi
diff --git a/Doc/Zsh/compsys.yo b/Doc/Zsh/compsys.yo
index e973c93e8..9e5a4cdcd 100644
--- a/Doc/Zsh/compsys.yo
+++ b/Doc/Zsh/compsys.yo
@@ -949,6 +949,17 @@ first description. The string will be used as the match specification
 when completing option names and values instead of the default
 `tt(r:|[_-]=* r:|=*)'. 
 
+Finally, the option tt(-C) can be given to make tt(_arguments) modify
+the tt(curcontext) parameter when a action of the form
+`tt(->)var(state)' is used. This parameter is used to keep track of
+the current context and in this case it (and not the parameter
+tt(context) as explained above) has to be made local to make sure that 
+calling functions don't use the modified value. Also, the local
+version of tt(curcontext) has to be initialised with the old value as
+in:
+
+example(local curcontext="$curcontext")
+
 The function can also be made to automatically complete long options
 for commands that support the `tt(-)tt(-help)' option as, for example,
 most of the GNU commands do. For this, the string `tt(-)tt(-)' must be
@@ -1100,6 +1111,10 @@ typeset -A val_args)
 when using an action of the form `tt(->)var(string)'. With this
 function the tt(context) parameter will be set to the name of the
 value whose argument is to be completed.
+
+Like tt(_arguments', tt(_values) also supports the tt(-C) option in
+which case you have to make the parameter tt(curcontext) local instead 
+of tt(context) (as described above).
 )
 item(tt(_regex_arguments))(
 This function is a compiler to generate a completion function.  The
diff --git a/Doc/Zsh/mod_computil.yo b/Doc/Zsh/mod_computil.yo
index 541f81605..1a3bceb3c 100644
--- a/Doc/Zsh/mod_computil.yo
+++ b/Doc/Zsh/mod_computil.yo
@@ -61,4 +61,10 @@ to access the state information to decide what should be completed.
 item(tt(compvalues))(
 Like tt(comparguments), but for the tt(_values) function.
 )
+item(tt(compstyle))(
+This builtin implements the internals of the style mechanism.
+)
+item(tt(comptags), tt(comptry))(
+This implements the internals of the tags mechanism.
+)
 enditem()
diff --git a/Etc/completion-style-guide b/Etc/completion-style-guide
index 286cb2a71..f5ec8ff14 100644
--- a/Etc/completion-style-guide
+++ b/Etc/completion-style-guide
@@ -1,91 +1,359 @@
-For now this is just a list of things one should or shouldn't do.
-
-1)  Use the functions `_files' and `_path_files' instead of `compgen'
-    with the `-f', `-/', or `-g' options.
-2)  *Never* use `compgen' with the `-s' option. This can always be done 
-    by a call to `compadd' which is faster.
-3)  Using `compgen' with the `-k' option should only be done if a) the
-    array is already existent or b) it is very large (several hundred
-    or thousend elements). In other cases using `compadd' is faster.
-4)  Supply match specifications to `compadd' and `compgen' if there are 
-    sensible ones.
-5)  Use `_description' when adding matches with `compadd' or
-    `compgen'. Use `_message' in places where no matches can be
-    generated. If you want to add different types of matches, add them
-    with multiple calls to `compadd' or `compgen', supplying different
-    descriptions.
-6)  Use helper functions that do option completion for you (like
+Contexts, tags and all that
+---------------------------
+
+The completion system keeps track of the current context in the
+parameter `curcontext'. It's content is the hierarchical name for the
+current context sans the tag currently tried. The tags represent
+different types of matches. So, whenever you are about to add matches, 
+you should use a tag for them and test if the user wants this type of
+matches to be generated. However, this only really needs to be done if 
+no other function in the call chain has tested that already or if you
+can offer different types of matches.
+
+Most of the utility functions do the testing themselves, so you don't
+have to worry about that at all. For example if you are adding matches 
+with `_files', `_hosts' or functions like these, you can just call
+them and they do the tests needed. The functions `_arguments' and
+`_values' do that too, but there is a small difference. These
+functions effectively add a new component to the hierarchical context
+name and if you are using the `->state' form for actions, this new
+component has to be reported back to the function calling `_arguments'
+or `_values'. This is done with the parameter `context', so you have
+to make that local in the calling function in the same way as you have 
+to make local `line', `state', and `{opt,val}_args'. This parameter
+`context' should then be used when you start adding matches by giving
+it to functions like `_tags' via the `-C' options, as in:
+
+  local context ...
+  ...
+  _arguments ... '-foo:foo:->foo'
+  ...
+  if [[ "$state" = foo ]]; then
+    _tags -C "$context" ...
+    ...
+  fi
+
+This will append the context name given to the `curcontext' parameter
+(preceding it with a colon) and this context will then be used to look 
+up styles for the tags.
+
+But since this is often used, `_arguments' and `_values' have support
+to make your life easier in such cases. With the `-C' option, these
+functions set the parameter `curcontext', thus modifying the globally
+used hierarchical context name. This means, that you have to make that 
+local, but then you don't have to worry about giving the context name
+reported back to functions you call. E.g.:
+
+  local curcontext="$curcontext" ...
+  ...
+  _arguments ... 'foo:foo:->foo'
+  ...
+  if [[ "$state" = foo ]]; then
+    _tags ...
+    ...
+  fi
+
+In this case the parameter `context' is not set, so you don't have to
+make that local. But make sure that `curcontext' is local so that the
+value changed by `_arguments' and `_values' is only used in your
+function (and make sure to initialise it to its old value as in the
+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 `_tags' 
+or the function `_wanted' for this. `_tags' is normally used to offer
+multiple types of matche by giving the tags for them as arguments. But 
+it any case its return value is zero only if at least one of these
+types is requested by the user, so you can just do:
+
+  _tags names || return 1
+
+  _description expl 'name'
+  compadd "$expl[@]" - alice bob
+
+Since this sequence of command is used so often, the `_wanted'
+function was added which just calls `_tags' with its first argument
+(i.e. the first argument os a tag) and then calls `_description' with
+all other arguments. The return value is as for `_tags' -- zero if the 
+matches should be added. So the example becomes:
+
+  _wanted names expl 'name' && compadd "$expl[@]" alice bob
+
+Note that you can also give the `-J' and `-V' options with the
+optional `1' or `2' following them supported by `_description':
+
+  _wanted names -V2 expl 'name' && compadd ...
+
+The more complicated case is where you can offer multiple types of
+matches. In this case the user should be able to say which types he
+wants to see at all and of those which he wants to see he should be
+able to say which types should be tried first. The generic solution
+for this uses `_tags' and `_requested':
+
+  local expl ret=1
+
+  _tags friends users hosts
+
+  while _tags; do
+    if _requested friends; then
+      _description expl friend
+      compad "$expl[@]" alice bob && ret=0
+    fi
+    _requested users && _users && ret=0
+    _requested hosts && _hosts && ret=0
+
+    (( ret )) || break   # leave the loop if matches were added
+  done
+
+`_tags' with tags as arguments registers those tags and calls
+`_sort_tags' so that the user can say which in which order the tags
+are to be tried. This means that internally these tags are stored in
+multiple sets. The types of matches represented by the tags from the
+first set should be tried first. If that generates no matches, the
+second set is tried and so on. `_tags' without arguments just makes
+the next set be tried (on the first call it makes the first set be
+used). The function `_requested' then tests if the tag given as its
+first argument is in the set currently used and returns zero if it is, 
+i.e. if matches of that type should be added now.
+
+But `_requested' can do more: since it is very common that you add
+different types of matches in different groups, with each group having 
+its own description the sequence of `_requested' followed by
+`_description' would be used very often. Hence, `_requested' can
+accept extra arguments which will be given to a call to `_description' 
+if the tag given as the first argument is to be used. I.e. we could
+change the example above to:
+
+  local expl ret=1
+
+  _tags friends users hosts
+
+  while _tags; do
+    _requested friends expl friend && compad "$expl[@]" alice bob && ret=0
+    _requested users && _users && ret=0
+    _requested hosts && _hosts && ret=0
+
+    (( ret )) || break   # leave the loop if matches were added
+  done
+
+This looks better already. But in many cases such as this one you can
+also use the function `_laternative' which simply implements a loop
+like this one. It gets arguments of the form `tag:descr:action'. E.g.:
+
+  _alternative \
+      'friends:friend:(alice bob)' \
+      'users:: _users' \
+      'hosts:: _hosts'
+
+Which does the same as the previous examples. (Note the empty
+descriptions in the last two arguments -- the actions start with a
+space so that they are executed without giving the the description
+build by `_alternative', i.e. we just use the description added by
+`_users' and `_hosts').
+
+In cases where you have to keep track of the context yourself, you can 
+give the sub-context you want to use to `_tags', `_wanted' and
+`_alternative' with the `-C' option as described above. You don't need 
+to give it to `_requested' -- that function will work on the context
+used by the corresponding call to `_tags' automatically.
+
+For the names of the tags: choose simple (short, if at all possible)
+names in plural. Also, first have a look at the tag names already used 
+by other functions and if any of these names seem sensible for the
+type of matches you are about to add, the use those names. This will
+allow users to define styles for certain types of matches indepent of
+the place where they are added.
+
+One final comment about when to use your own sub-contexts: do this
+when the command you are writing a completion function for has
+different `modes'. E.g. if it accepts host names after a `-h' option
+and users or hosts after `-u' and for some reason you can't use
+`_arguments' to do the work for you, then use context names as in:
+
+  case "$1" in
+  -h)
+    _tags -C -h hosts && _hosts && ret=0
+    ;;
+  -u)
+    _alternative -C -u 'users:: _users' 'hosts:: _hosts' && ret=0
+    ;;
+  esac
+
+
+Styles
+------
+
+Users can associate patterns for hierarchical context names with
+certain styles using the `compstyle' function. The completion code
+should then use these styles to decide how matches should be added and 
+to get user-configured values. This is done using the function
+`_style'.
+
+Basically styles map names to a bunch of strings (the `value'). In
+many cases you want to treat the value as a boolean, so let's start
+with that. To test if, for example, the style `description' is set for 
+the tag `options' in the context you are currently in, you can just do:
+
+  if _style options description; then
+    # yes, it is set...
+  fi
+
+I.e. with two arguments `_style' takes the first one as a tag and the
+second one as a style name and returns zero if that style has the
+boolean value `true'. Internally it checks if the style is set to one
+of `yes', `true', `on', or `1' and interprets that as `true' and every 
+other value as `false'.
+
+For more complicated style for which you want to test if the value
+matches a certain pattern, you can use `_style' with three arguments:
+
+  if _style foo bar '*baz*'; then
+    ...
+  fi
+
+This tests if the value of the style `bar' for the tag `foo' matches
+the pattern `*baz*' and returns zero if it does.
+
+But sometimes you want to actually get the value stored for a certain
+style instead of just testing it. For this `_style' supports four
+options: `-b', `-s', `-a', and `-h'. After these options, three
+arguments are expected, namely the tag, the style, and a parameter
+name. The parameter will then be set to the value of the style and the 
+option says how the strings stored as a value will be stored in the
+parameter:
+
+  - `-b': the parameter will be set to a either `yes' or `no'
+  - `-s': the parameter will be set to all strings in the value
+          concatenated (separated by spaces) to one string
+  - `-a': the parameter will be set to an array containing the strings 
+          from the value as elements
+  - `-h': the parameter will be set to an association with the strings 
+          from the value being interpreted alternatingly as keys and
+	  values
+
+Note that if you want to test or get styles for a certain context
+name which you have to build yourself, you have to call `_style' after 
+the call to `_tags', `_wanted', or whatever. When you are using
+utility functions like `_alternate' or `_arguments' the context will
+automatically be set up appropriately at the time when you have a
+chance to call `_style'.
+
+Some random comments about style names. Use the ones already in use if 
+possible. Especially, use the `description' style if you can add
+matches in a simple and a verbose way. Use the verbose form only if
+the `description' style is `true' for the current context. Also, if
+the matches you want to add have a common prefix which is somehow
+special, use the `prefix-needed' and `prefix-hidden' styles. The first 
+one says if the user has to give the prefix on the line to make these
+matches be added and the second one says if the prefix should be
+visible in the list.
+
+But, I think, using any number of new style names is ok -- different
+from tag-names where I would like to keep the number of names used
+small.
+
+And finally, if you need a style whose value can sensibly be
+interpreted as a list of words, use array or association styles with
+the `-a' or `-h' options to `_style'. Otherwise you should only make
+sure that an empty value for a style is treated in the same way as if
+the style wasn't set at all (this is use elsewhere and we want to
+keep things consistent).
+
+
+Descriptions
+------------
+
+Always use description. This is important. Really. *Always* use
+descriptions. If you have just written down a `compadd' without a
+"$expl[@]" (or equivalent), you have just made an error. Even in
+helper functions where you use a "$@": if you can't be sure that there 
+is a description in the arguments, add one. You can (and, in most
+cases, should) then give the description you generated after the
+"$@". This makes sure that the, probably more specific, description
+given by the calling function takes precedence over the generic one
+you have just generated.
+
+And it really isn't that complicated, is it? Think about a string
+people might want to see above the matches (in singular -- that's used 
+throughout the completion system) and do:
+
+  local expl
+
+  _description expl <descr>
+  compadd "$expl@]" - <matches ...>
+
+Note that this function also accepts `-V' und `-J', optionally (in the 
+same word) followed by `1' or `2' to describe the type of group you
+want to use. For example:
+
+  _description expl '...'
+  compadd "$expl[@]" -V1 foo - ...    # THIS IS WRONG!!!
+
+is *not* the right way to use a unsorted group. Instead do the
+simpler:
+
+  _description -V1 expl '...'
+  compadd "$expl[@]" - ...
+
+and everything will work fine.
+
+Also, if you are about to add multiple different types of matches, use 
+multiple calls to `_description' and add them with multiple calls to
+`compadd'. But in almost all cases you should then add them using
+different tags anyway, so, see above.
+
+And since often a tag directly corresponds to a group of matches,
+you'll often be using the tags function that allow 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 <tag> [ -V[1,2] | -J[1,2] ] expl <descr>
+
+and
+
+  _requested <tag> [ -V[1,2] | -J[1,2] ] expl <descr>
+
+is all you need to make your function work correctly with both tags
+and description at the same time.
+
+
+Misc. remarks
+-------------
+
+1)  Supply match specifications to `compadd' if there are sensible ones.
+2)  Use helper functions that do option completion for you (like
     `_arguments' and `_values') -- it will make your life much
     easier.
-7)  Use helper functions like `_users' and `_groups' instead of direct
-    calls to `compgen -u' or some ad hoc mechanisms to generate such
-    information. This ensures that users can change the way these things 
-    will be completed everywhere by just using their own implementations 
-    for these functions.
-8)  Make sure that the return value of your functions is correct: zero
+3)  Use helper functions like `_users' and `_groups' instead of some ad hoc
+    mechanisms to generate such information. This ensures that users can
+    change the way these things will be completed everywhere by just using
+    their own implementations for these functions.
+4)  Make sure that the return value of your functions is correct: zero
     if matches where added and non-zero if no matches were found.
     In some cases you'll need to test the value of `$compstate[nmatches]'
     for this. This should always be done by first saving the old value
     (`local nm="$compstate[nmatches]"') and later comparing this with
     the current value after all matches have been added (e.g. by
     writing `[[ nm -ne compstate[nmatches] ]]' at the end of your
-    function). This guarantees that your functions will be re-usable
-    because calling functions may rely on the correct return value.
-9)  In places where different behaviors may be useful, add a
-    configuration key to allow users to select the behavior they
-    prefer. Names for configuration keys should look like `prefix_name',
-    where `prefix' is the (probably abbreviated) name of your function
-    (without any leading underscore) and `name' describes what can be
-    configured.
-    If you want to have this completion function to be included in the
-    distribution, it would help if you describe the configuration key
-    at the end of the `compsys.yo' manual.
-    When testing the values of configuration keys, the empty string
-    should result in the same behavior as if the key were unset. This
-    can be achieved by the test `[[ -n "$compconfig[prefix_name]" ]]'.
-10) When writing helper functions that generate matches, the arguments
+    function).
+    This guarantees that your functions will be re-usable because calling
+    functions may rely on the correct return value.
+5)  When writing helper functions that generate matches, the arguments
     of these should be given unchanged to `compadd' or `compgen' (if
     they are not used by the helper function itself).
-11) When option names are generated as possible matches, add them *with*
-    the `-', `+', or `--' at the beginning. This is the style used 
-    throughout the completion system from the distribution and makes it
-    easier to distinguish options from other matches in completion lists.
-    Also, when adding options as matches, put them in a sorted group
-    named `option'. The best way to do this is by using the `_description'
-    helper function as in:
-
-      local expl
-      _description expl option
-      compadd "$expl[@]" - <option-names ...>
-
-    Also, before adding options as possible matches, test the
-    `option_prefix' configuration key. If it set and it doesn't contain
-    the sub-string `!cmd' (where `cmd' is the name of the command that
-    is completed for) options should only be added if the prefix character
-    (`-' or `+') is on the line or if no other useful matches could be 
-    generated. This can be achieved by first generating these other matches
-    (if any) and then using a test like:
-
-      if [[ nm -eq "$compstate[nmatches]" ||
-            -z "$compconfig[option_prefix]" ||
-            "$compconfig[option_prefix]" = *\!${words[1]}* ||
-            "$PREFIX" = [-+]* ]]; then
-        # Add options...
-      fi
-
-    Finally, it is good style to display descriptions for options that
-    aren't self-explanatory. See the `_display' and `_describe' functions
-    and their uses in `_arguments'.
-
-    All this should make it look like a really good idea to just use the
-    supplied `_arguments' function to complete options.
-12) If at all possible, completion code for a command or a suite of
+6)  When matches with a common prefix such as option names are generated,
+    add them *with* the prefix (like `-', `+', or `--' for options).
+    Then check the `prefix-needed' style to see if the matches are to be
+    added when the prefix is on the line and use the `prefix-hidden'
+    style to see if the prefix should be listed or not.
+7)  If at all possible, completion code for a command or a suite of
     commands should go into only one file. If a command has sub-commands,
-    implementing aa state-machine might be a good idea. See the `_rpm' 
+    implementing a state-machine might be a good idea. See the `_rpm' 
     and `_pbm' files for examples of different styles. Also see the
     documentation for `_arguments' and `_values' for two functions
     that may help you with this.
-13) If a completion function generates completely different types of
+8)  If a completion function generates completely different types of
     completions (for example, because the comamnd has several
     completely different modes), it should allow users to define
     functions that separately override the behavior for these
diff --git a/Src/Zle/computil.c b/Src/Zle/computil.c
index b5b09e732..42de5c65c 100644
--- a/Src/Zle/computil.c
+++ b/Src/Zle/computil.c
@@ -127,7 +127,7 @@ static struct cdstate cd_state;
 static int cd_parsed = 0;
 
 static void
-free_cdsets(Cdset p)
+freecdsets(Cdset p)
 {
     Cdset n;
 
@@ -151,7 +151,7 @@ cd_init(char *nam, char *sep, char **args, int disp)
 
     if (cd_parsed) {
 	zsfree(cd_state.sep);
-	free_cdsets(cd_state.sets);
+	freecdsets(cd_state.sets);
     }
     setp = &(cd_state.sets);
     cd_state.sep = ztrdup(sep);
@@ -270,7 +270,7 @@ cd_get(char **params)
 
 	cd_state.sets = set->next;
 	set->next = NULL;
-	free_cdsets(set);
+	freecdsets(set);
 
 	return 0;
     }
@@ -387,7 +387,7 @@ arrcmp(char **a, char **b)
 }
 
 static void
-free_caargs(Caarg a)
+freecaargs(Caarg a)
 {
     Caarg n;
 
@@ -402,7 +402,7 @@ free_caargs(Caarg a)
 }
 
 static void
-free_cadef(Cadef d)
+freecadef(Cadef d)
 {
     if (d) {
 	Caopt p, n;
@@ -415,11 +415,11 @@ free_cadef(Cadef d)
 	    zsfree(p->name);
 	    zsfree(p->descr);
 	    freearray(p->xor);
-	    free_caargs(p->args);
+	    freecaargs(p->args);
 	    zfree(p, sizeof(*p));
 	}
-	free_caargs(d->args);
-	free_caargs(d->rest);
+	freecaargs(d->args);
+	freecaargs(d->rest);
 	if (d->single)
 	    zfree(d->single, 256 * sizeof(Caopt));
 	zfree(d, sizeof(*d));
@@ -561,7 +561,7 @@ parse_cadef(char *nam, char **args)
 		*p = sav;
 	    }
 	    if (*p != ')') {
-		free_cadef(ret);
+		freecadef(ret);
 		zerrnam(nam, "invalid argument: %s", *args, 0);
 		return NULL;
 	    }
@@ -599,7 +599,7 @@ parse_cadef(char *nam, char **args)
 		    p++;
 	    }
 	    if (!p[1]) {
-		free_cadef(ret);
+		freecadef(ret);
 		zerrnam(nam, "invalid argument: %s", *args, 0);
 		return NULL;
 	    }
@@ -627,7 +627,7 @@ parse_cadef(char *nam, char **args)
 			p++;
 
 		if (!*p) {
-		    free_cadef(ret);
+		    freecadef(ret);
 		    zerrnam(nam, "invalid option definition: %s", *args, 0);
 		    return NULL;
 		}
@@ -637,7 +637,7 @@ parse_cadef(char *nam, char **args)
 		descr = NULL;
 
 	    if (c && c != ':') {
-		free_cadef(ret);
+		freecadef(ret);
 		zerrnam(nam, "invalid option definition: %s", *args, 0);
 		return NULL;
 	    }
@@ -667,8 +667,8 @@ parse_cadef(char *nam, char **args)
 				    p++;
 			}
 			if (*p != ':') {
-			    free_cadef(ret);
-			    free_caargs(oargs);
+			    freecadef(ret);
+			    freecaargs(oargs);
 			    zerrnam(nam, "invalid option definition: %s",
 				    *args, 0);
 			    return NULL;
@@ -726,12 +726,12 @@ parse_cadef(char *nam, char **args)
 	    int type = CAA_REST;
 
 	    if (*++p != ':') {
-		free_cadef(ret);
+		freecadef(ret);
 		zerrnam(nam, "invalid rest argument definition: %s", *args, 0);
 		return NULL;
 	    }
 	    if (ret->rest) {
-		free_cadef(ret);
+		freecadef(ret);
 		zerrnam(nam, "doubled rest argument definition: %s", *args, 0);
 		return NULL;
 	    }
@@ -758,7 +758,7 @@ parse_cadef(char *nam, char **args)
 		anum++;
 
 	    if (*p != ':') {
-		free_cadef(ret);
+		freecadef(ret);
 		zerrnam(nam, "invalid argument: %s", *args, 0);
 		return NULL;
 	    }
@@ -773,8 +773,8 @@ parse_cadef(char *nam, char **args)
 		 pre = tmp, tmp = tmp->next);
 
 	    if (tmp && tmp->num == anum - 1) {
-		free_cadef(ret);
-		free_caargs(arg);
+		freecadef(ret);
+		freecaargs(arg);
 		zerrnam(nam, "doubled argument definition: %s", *args, 0);
 		return NULL;
 	    }
@@ -808,7 +808,7 @@ get_cadef(char *nam, char **args)
     if (i)
 	min = p;
     if ((new = parse_cadef(nam, args))) {
-	free_cadef(*min);
+	freecadef(*min);
 	*min = new;
     }
     return new;
@@ -1412,7 +1412,7 @@ struct cvval {
 static Cvdef cvdef_cache[MAX_CVCACHE];
 
 static void
-free_cvdef(Cvdef d)
+freecvdef(Cvdef d)
 {
     if (d) {
 	Cvval p, n;
@@ -1425,7 +1425,7 @@ free_cvdef(Cvdef d)
 	    zsfree(p->name);
 	    zsfree(p->descr);
 	    freearray(p->xor);
-	    free_caargs(p->arg);
+	    freecaargs(p->arg);
 	    zfree(p, sizeof(*p));
 	}
 	zfree(d, sizeof(*d));
@@ -1493,7 +1493,7 @@ parse_cvdef(char *nam, char **args)
 		*p = sav;
 	    }
 	    if (*p != ')') {
-		free_cvdef(ret);
+		freecvdef(ret);
 		zerrnam(nam, "invalid argument: %s", *args, 0);
 		return NULL;
 	    }
@@ -1514,7 +1514,7 @@ parse_cvdef(char *nam, char **args)
 		p++;
 
 	if (hassep && !sep && name + 1 != p) {
-	    free_cvdef(ret);
+	    freecvdef(ret);
 	    zerrnam(nam, "no multi-letter values with empty separator allowed", NULL, 0);
 	    return NULL;
 	}
@@ -1525,7 +1525,7 @@ parse_cvdef(char *nam, char **args)
 		    p++;
 
 	    if (!*p) {
-		free_cvdef(ret);
+		freecvdef(ret);
 		zerrnam(nam, "invalid value definition: %s", *args, 0);
 		return NULL;
 	    }
@@ -1536,7 +1536,7 @@ parse_cvdef(char *nam, char **args)
 	    descr = NULL;
 	}
 	if (c && c != ':') {
-	    free_cvdef(ret);
+	    freecvdef(ret);
 	    zerrnam(nam, "invalid value definition: %s", *args, 0);
 	    return NULL;
 	}
@@ -1549,7 +1549,7 @@ parse_cvdef(char *nam, char **args)
 	}
 	if (c == ':') {
 	    if (hassep && !sep) {
-		free_cvdef(ret);
+		freecvdef(ret);
 		zerrnam(nam, "no value with argument with empty separator allowed", NULL, 0);
 		return NULL;
 	    }
@@ -1594,7 +1594,7 @@ get_cvdef(char *nam, char **args)
     if (i)
 	min = p;
     if ((new = parse_cvdef(nam, args))) {
-	free_cvdef(*min);
+	freecvdef(*min);
 	*min = new;
     }
     return new;
@@ -1977,12 +1977,592 @@ bin_compquote(char *nam, char **args, char *ops, int func)
     return 0;
 }
 
+typedef struct cspat *Cspat;
+typedef struct cstyle *Cstyle;
+
+struct cspat {
+    Cspat next;
+    char *pat;
+    Patprog prog;
+    int weight;
+    Cstyle styles, lstyles;
+};
+    
+struct cstyle {
+    Cstyle next;
+    char *name;
+    char **vals;
+};
+
+/* List of styles. */
+
+static Cspat compstyles, lcompstyles;
+
+static void
+freecstyle(Cstyle s)
+{
+    Cstyle n;
+
+    while (s) {
+	n = s->next;
+
+	zsfree(s->name);
+	freearray(s->vals);
+	zfree(s, sizeof(*s));
+
+	s = n;
+    }
+}
+
+static void
+freecspat(Cspat p)
+{
+    Cspat n;
+
+    while (p) {
+	n = p->next;
+
+	zsfree(p->pat);
+	freepatprog(p->prog);
+	zfree(p, sizeof(*p));
+
+	p = n;
+    }
+}
+
+static Cspat
+getcspat(char *pat)
+{
+    Cspat p;
+
+    for (p = compstyles; p; p = p->next)
+	if (!strcmp(pat, p->pat))
+	    return p;
+
+    return NULL;
+}
+
+static Cstyle
+getcstyle(Cspat p, char *name)
+{
+    Cstyle s;
+
+    for (s = p->styles; s; s=  s->next)
+	if (!strcmp(name, s->name))
+	    return s;
+
+    return NULL;
+}
+
+static void
+setcstyle(Cspat p, char *name, char **vals)
+{
+    Cstyle s;
+
+    for (s = p->styles; s; s = s->next)
+	if (!strcmp(name, s->name)) {
+	    freearray(s->vals);
+	    PERMALLOC {
+		s->vals = arrdup(vals);
+	    } LASTALLOC;
+
+	    return;
+	}
+    s = (Cstyle) zalloc(sizeof(*s));
+
+    s->name = ztrdup(name);
+    PERMALLOC {
+	s->vals = arrdup(vals);
+    } LASTALLOC;
+    s->next = NULL;
+
+    if (p->lstyles)
+	p->lstyles->next = s;
+    else
+	p->styles = s;
+    p->lstyles = s;
+}
+
+static Cspat
+addcspat(char *pat, Patprog prog)
+{
+    Cspat p, q, qq;
+    int weight, tmp, first;
+    char *s;
+
+    for (weight = 0, tmp = 2, first = 1, s = pat; *s; s++) {
+	if (first && *s == '*' && (!s[1] || s[1] == ':')) {
+	    tmp = 0;
+	    continue;
+	}
+	first = 0;
+
+	if (*s == '(' || *s == '|' || *s == '*' || *s == '[' || *s == '<' ||
+	    *s == '?' || *s == '#' || *s == '^')
+	    tmp = 1;
+
+	if (*s == ':') {
+	    first = 1;
+	    weight += tmp;
+	    tmp = 2;
+	}
+    }
+    weight += tmp;
+
+    p = (Cspat) zalloc(sizeof(*p));
+
+    p->pat = ztrdup(pat);
+    p->weight = weight;
+    p->prog = prog;
+    p->styles = p->lstyles = NULL;
+
+    for (qq = NULL, q = compstyles; q && q->weight >= weight;
+	 qq = q, q = q->next);
+
+    p->next = q;
+    if (qq)
+	qq->next = p;
+    else
+	compstyles = p;
+    if (!q)
+	lcompstyles = p;
+
+    return p;
+}
+
+static void
+deletecstyle(Cspat p, char *name)
+{
+    Cstyle ps, s;
+
+    for (ps = NULL, s = p->styles; s; ps = s, s = s->next)
+	if (!strcmp(name, s->name)) {
+	    if (ps)
+		ps->next = s->next;
+	    else
+		p->styles = s->next;
+	    if (s == p->lstyles)
+		p->lstyles = ps;
+
+	    s->next = NULL;
+	    freecstyle(s);
+
+	    return;
+	}
+}
+
+static void
+deletecspat(Cspat pat)
+{
+    Cspat pp, p;
+
+    for (pp = NULL, p = compstyles; p; pp = p, p = p->next)
+	if (p == pat) {
+	    if (pp)
+		pp->next = p->next;
+	    else
+		compstyles = p->next;
+	    if (p == lcompstyles)
+		lcompstyles = pp;
+
+	    p->next = NULL;
+	    zsfree(p->pat);
+	    freepatprog(p->prog);
+	    freecstyle(p->styles);
+	    zfree(p, sizeof(*p));
+
+	    return;
+	}
+}
+
+static Cstyle
+lookupcstyle(char *ctxt, char *style)
+{
+    Cspat p;
+    Cstyle s;
+
+    for (p = compstyles; p; p = p->next)
+	if (pattry(p->prog, ctxt))
+	    for (s = p->styles; s; s = s->next)
+		if (!strcmp(style, s->name))
+		    return s;
+
+    return NULL;
+}
+
+static int
+bin_compstyles(char *nam, char **args, char *ops, int func)
+{
+    int min, max, n;
+
+    if (args[0][0] != '-' || !args[0][1] || args[0][2]) {
+	zerrnam(nam, "invalid argument: %s", args[0], 0);
+	return 1;
+    }
+    switch (args[0][1]) {
+    case 'a': min = 3; max = -1; break;
+    case 'd': min = 0; max =  2; break;
+    case 'S': min = 3; max =  3; break;
+    case 'A': min = 3; max =  3; break;
+    case 'H': min = 3; max =  3; break;
+    case 'T': min = 2; max =  2; break;
+    case 'G': min = 1; max =  3; break;
+    default:
+	zerrnam(nam, "invalid option: %s", args[0], 0);
+	return 1;
+    }
+    n = arrlen(args) - 1;
+    if (n < min) {
+	zerrnam(nam, "not enough arguments", NULL, 0);
+	return 1;
+    } else if (max >= 0 && n > max) {
+	zerrnam(nam, "too many arguments", NULL, 0);
+	return 1;
+    }
+    switch (args[0][1]) {
+    case 'a':
+	{
+	    Cspat p;
+
+	    if (!(p = getcspat(args[1]))) {
+		Patprog prog;
+		char *pat = dupstring(args[1]);
+
+		tokenize(pat);
+
+		if (!(prog = patcompile(pat, PAT_ZDUP, NULL))) {
+		    zerrnam(nam, "invalid pattern: %s", args[1], 0);
+		    return 1;
+		}
+		p = addcspat(args[1], prog);
+	    }
+	    setcstyle(p, args[2], args + 3);
+	}
+	break;
+    case 'd':
+	{
+	    Cspat p;
+
+	    if (args[1]) {
+		if ((p = getcspat(args[1]))) {
+		    if (args[2]) {
+			deletecstyle(p, args[2]);
+			if (!p->styles)
+			    deletecspat(p);
+		    } else
+			deletecspat(p);
+		}
+	    } else {
+		freecspat(compstyles);
+		compstyles = lcompstyles = NULL;
+	    }
+	}
+	break;
+    case 'S':
+	{
+	    Cstyle s;
+	    char *ret;
+	    int val;
+
+	    if ((s = lookupcstyle(args[1], args[2])) && s->vals[0]) {
+		PERMALLOC {
+		    ret = sepjoin(s->vals, NULL);
+		} LASTALLOC;
+		val = 0;
+	    } else {
+		ret = ztrdup("");
+		val = 1;
+	    }
+	    setsparam(args[3], ret);
+
+	    return val;
+	}
+	break;
+    case 'A':
+    case 'H':
+	{
+	    Cstyle s;
+	    char **ret;
+	    int val;
+
+	    if ((s = lookupcstyle(args[1], args[2]))) {
+		PERMALLOC {
+		    ret = arrdup(s->vals);
+		} LASTALLOC;
+		val = 0;
+	    } else {
+		char *dummy = NULL;
+
+		PERMALLOC {
+		    ret = arrdup(&dummy);
+		} LASTALLOC;
+		val = 1;
+	    }
+	    if (args[0][1] == 'A')
+		setaparam(args[3], ret);
+	    else
+		sethparam(args[3], ret);
+
+	    return val;
+	}
+	break;
+    case 'T':
+	return !lookupcstyle(args[1], args[2]);
+    case 'G':
+	{
+	    LinkList l = newlinklist();
+	    int ret = 1;
+	    Cspat p;
+
+	    if (args[2]) {
+		if ((p = getcspat(args[2]))) {
+		    Cstyle s;
+
+		    if (args[3]) {
+			if ((s = getcstyle(p, args[3]))) {
+			    char **v = s->vals;
+
+			    while (*v)
+				addlinknode(l, *v++);
+
+			    ret = 0;
+			}
+		    } else {
+			for (s = p->styles; s; s = s->next)
+			    addlinknode(l, s->name);
+
+			ret = 0;
+		    }
+		}
+	    } else {
+		for (p = compstyles; p; p = p->next)
+		    addlinknode(l, p->pat);
+
+		ret = 0;
+	    }
+	    set_list_array(args[1], l);
+
+	    return ret;
+	}
+    }
+    return 0;
+}
+
+typedef struct ctags *Ctags;
+typedef struct ctset *Ctset;
+
+struct ctags {
+    char **all;
+    char *context;
+    int init;
+    Ctset sets;
+};
+
+struct ctset {
+    Ctset next;
+    char **tags;
+};
+
+/* Array of tag-set infos. Index is the locallevel. */
+
+#define MAX_TAGS 256
+static Ctags comptags[MAX_TAGS];
+
+/* locallevel at last comptags -i */
+
+static int lasttaglevel;
+
+static void
+freectset(Ctset s)
+{
+    Ctset n;
+
+    while (s) {
+	n = s->next;
+
+	freearray(s->tags);
+	zfree(s, sizeof(*s));
+
+	s = n;
+    }
+}
+
+static void
+freectags(Ctags t)
+{
+    if (t) {
+	freearray(t->all);
+	zsfree(t->context);
+	freectset(t->sets);
+	zfree(t, sizeof(*t));
+    }
+}
+
+static void
+settags(char **tags)
+{
+    Ctags t;
+
+    if (comptags[locallevel])
+	freectags(comptags[locallevel]);
+
+    comptags[locallevel] = t = (Ctags) zalloc(sizeof(*t));
+
+    PERMALLOC {
+	t->all = arrdup(tags + 1);
+    } LASTALLOC;
+    t->context = ztrdup(*tags);
+    t->sets = NULL;
+    t->init = 1;
+}
+
+static int
+arrcontains(char **a, char *s)
+{
+    while (*a)
+	if (!strcmp(s, *a++))
+	    return 1;
+
+    return 0;
+}
+
+static int
+bin_comptags(char *nam, char **args, char *ops, int func)
+{
+    int min, max, n;
+
+    if (incompfunc != 1) {
+	zerrnam(nam, "can only be called from completion function", NULL, 0);
+	return 1;
+    }
+    if (args[0][0] != '-' || !args[0][1] || args[0][2]) {
+	zerrnam(nam, "invalid argument: %s", args[0], 0);
+	return 1;
+    }
+    if (locallevel >= MAX_TAGS) {
+	zerrnam(nam, "nesting level too deep", NULL, 0);
+	return 1;
+    }
+    if (args[0][1] != 'i' && !comptags[locallevel]) {
+	zerrnam(nam, "no tags registered", NULL, 0);
+	return 1;
+    }
+    switch (args[0][1]) {
+    case 'i': min = 2; max = -1; break;
+    case 'C': min = 1; max =  1; break;
+    case 'T': min = 0; max =  0; break;
+    case 'N': min = 0; max =  0; break;
+    case 'R': min = 1; max =  1; break;
+    case 'S': min = 1; max =  1; break;
+    default:
+	zerrnam(nam, "invalid option: %s", args[0], 0);
+	return 1;
+    }
+    n = arrlen(args) - 1;
+    if (n < min) {
+	zerrnam(nam, "not enough arguments", NULL, 0);
+	return 1;
+    } else if (max >= 0 && n > max) {
+	zerrnam(nam, "too many arguments", NULL, 0);
+	return 1;
+    }
+    switch (args[0][1]) {
+    case 'i':
+	settags(args + 1);
+	lasttaglevel = locallevel;
+	break;
+    case 'C':
+	setsparam(args[1], ztrdup(comptags[locallevel]->context));
+	break;
+    case 'T':
+	return !comptags[locallevel]->sets;
+    case 'N':
+	{
+	    Ctset s;
+
+	    if (comptags[locallevel]->init)
+		comptags[locallevel]->init = 0;
+	    else if ((s = comptags[locallevel]->sets)) {
+		comptags[locallevel]->sets = s->next;
+		s->next = NULL;
+		freectset(s);
+	    }
+	    return !comptags[locallevel]->sets;
+	}
+    case 'R':
+	{
+	    Ctset s;
+
+	    return !((s = comptags[locallevel]->sets) &&
+		     arrcontains(s->tags, args[1]));
+	}
+    case 'S':
+	if (comptags[locallevel]->sets) {
+	    char **ret;
+
+	    PERMALLOC {
+		ret = arrdup(comptags[locallevel]->sets->tags);
+	    } LASTALLOC;
+
+	    setaparam(args[1], ret);
+	} else
+	    return 1;
+
+	break;
+    }
+    return 0;
+}
+
+static int
+bin_comptry(char *nam, char **args, char *ops, int func)
+{
+    if (incompfunc != 1) {
+	zerrnam(nam, "can only be called from completion function", NULL, 0);
+	return 1;
+    }
+    if (!lasttaglevel || !comptags[lasttaglevel]) {
+	zerrnam(nam, "no tags registered", NULL, 0);
+	return 1;
+    }
+    if (*args) {
+	char **p, **q, **all;
+
+	args = arrdup(args);
+
+	for (p = q = args, all = comptags[lasttaglevel]->all; *p; p++)
+	    if (arrcontains(all, *p))
+		*q++ = *p;
+	*q = NULL;
+
+	if (*args) {
+	    Ctset s = (Ctset) zalloc(sizeof(*s)), l;
+
+	    PERMALLOC {
+		s->tags = arrdup(args);
+	    } LASTALLOC;
+	    s->next = NULL;
+
+	    if ((l = comptags[lasttaglevel]->sets)) {
+		while (l->next)
+		    l = l->next;
+
+		l->next = s;
+	    } else
+		comptags[lasttaglevel]->sets = s;
+	}
+    }
+    return 0;
+}
+
 static struct builtin bintab[] = {
     BUILTIN("compdisplay", 0, bin_compdisplay, 2, -1, 0, NULL, NULL),
     BUILTIN("compdescribe", 0, bin_compdescribe, 3, -1, 0, NULL, NULL),
     BUILTIN("comparguments", 0, bin_comparguments, 1, -1, 0, NULL, NULL),
     BUILTIN("compvalues", 0, bin_compvalues, 1, -1, 0, NULL, NULL),
     BUILTIN("compquote", 0, bin_compquote, 1, -1, 0, NULL, NULL),
+    BUILTIN("compstyles", 0, bin_compstyles, 1, -1, 0, NULL, NULL),
+    BUILTIN("comptags", 0, bin_comptags, 1, -1, 0, NULL, NULL),
+    BUILTIN("comptry", 0, bin_comptry, 0, -1, 0, NULL, NULL),
 };
 
 
@@ -1993,6 +2573,12 @@ setup_computil(Module m)
     memset(cadef_cache, 0, sizeof(cadef_cache));
     memset(cvdef_cache, 0, sizeof(cvdef_cache));
 
+    compstyles = NULL;
+
+    memset(comptags, 0, sizeof(comptags));
+
+    lasttaglevel = 0;
+
     return 0;
 }
 
@@ -2020,9 +2606,14 @@ finish_computil(Module m)
     int i;
 
     for (i = 0; i < MAX_CACACHE; i++)
-	free_cadef(cadef_cache[i]);
+	freecadef(cadef_cache[i]);
     for (i = 0; i < MAX_CVCACHE; i++)
-	free_cvdef(cvdef_cache[i]);
+	freecvdef(cvdef_cache[i]);
+
+    freecspat(compstyles);
+
+    for (i = 0; i < MAX_TAGS; i++)
+	freectags(comptags[i]);
 
     return 0;
 }
diff --git a/Src/Zle/computil.mdd b/Src/Zle/computil.mdd
index 4789280a9..a66a823d5 100644
--- a/Src/Zle/computil.mdd
+++ b/Src/Zle/computil.mdd
@@ -2,4 +2,4 @@ moddeps="complete"
 
 objects="computil.o"
 
-autobins="compdisplay compdescribe comparguments compvalues compquote"
+autobins="compdisplay compdescribe comparguments compvalues compquote compstyles comptags comptry"