about summary refs log tree commit diff
path: root/Completion
diff options
context:
space:
mode:
authorTanaka Akira <akr@users.sourceforge.net>1999-11-12 15:28:24 +0000
committerTanaka Akira <akr@users.sourceforge.net>1999-11-12 15:28:24 +0000
commite6282df1155e8d9b08b2e518a452c1997973f1ce (patch)
treeb0c8ed7e8512cc4397ae7df6d138ea66147565b3 /Completion
parent167b0ae3b98938f75287dcf2e112d41a03532c5f (diff)
downloadzsh-e6282df1155e8d9b08b2e518a452c1997973f1ce.tar.gz
zsh-e6282df1155e8d9b08b2e518a452c1997973f1ce.tar.xz
zsh-e6282df1155e8d9b08b2e518a452c1997973f1ce.zip
manual/8630
Diffstat (limited to 'Completion')
-rw-r--r--Completion/Base/_arguments41
-rw-r--r--Completion/Base/_brace_parameter2
-rw-r--r--Completion/Base/_command_names45
-rw-r--r--Completion/Base/_condition11
-rw-r--r--Completion/Base/_default7
-rw-r--r--Completion/Base/_describe12
-rw-r--r--Completion/Base/_equal11
-rw-r--r--Completion/Base/_jobs18
-rw-r--r--Completion/Base/_math2
-rw-r--r--Completion/Base/_parameter2
-rw-r--r--Completion/Base/_subscript49
-rw-r--r--Completion/Base/_tilde69
-rw-r--r--Completion/Base/_values35
-rw-r--r--Completion/Base/_vars10
-rw-r--r--Completion/Builtins/_aliases7
-rw-r--r--Completion/Builtins/_arrays2
-rw-r--r--Completion/Builtins/_autoload2
-rw-r--r--Completion/Builtins/_bindkey4
-rw-r--r--Completion/Builtins/_builtin2
-rw-r--r--Completion/Builtins/_cd7
-rw-r--r--Completion/Builtins/_command2
-rw-r--r--Completion/Builtins/_compdef4
-rw-r--r--Completion/Builtins/_disable29
-rw-r--r--Completion/Builtins/_echotc2
-rw-r--r--Completion/Builtins/_enable29
-rw-r--r--Completion/Builtins/_functions2
-rw-r--r--Completion/Builtins/_hash8
-rw-r--r--Completion/Builtins/_kill4
-rw-r--r--Completion/Builtins/_limits2
-rw-r--r--Completion/Builtins/_pids13
-rw-r--r--Completion/Builtins/_popd55
-rw-r--r--Completion/Builtins/_sched11
-rw-r--r--Completion/Builtins/_stat2
-rw-r--r--Completion/Builtins/_trap2
-rw-r--r--Completion/Builtins/_unhash28
-rw-r--r--Completion/Builtins/_wait2
-rw-r--r--Completion/Builtins/_which20
-rw-r--r--Completion/Builtins/_zftp14
-rw-r--r--Completion/Builtins/_zle2
-rw-r--r--Completion/Builtins/_zmodload3
-rw-r--r--Completion/Core/_alternative25
-rw-r--r--Completion/Core/_complete7
-rw-r--r--Completion/Core/_files16
-rw-r--r--Completion/Core/_main_complete5
-rw-r--r--Completion/Core/_message2
-rw-r--r--Completion/Core/_normal1
-rw-r--r--Completion/Core/_options2
-rw-r--r--Completion/Core/_parameters2
-rw-r--r--Completion/Core/_requested10
-rw-r--r--Completion/Core/_set_options2
-rw-r--r--Completion/Core/_sort_tags28
-rw-r--r--Completion/Core/_style55
-rw-r--r--Completion/Core/_tags123
-rw-r--r--Completion/Core/_unset_options2
-rw-r--r--Completion/Core/compinit266
-rw-r--r--Completion/Linux/_rpm12
-rw-r--r--Completion/User/_archie8
-rw-r--r--Completion/User/_flex2
-rw-r--r--Completion/User/_gcc4
-rw-r--r--Completion/User/_gprof6
-rw-r--r--Completion/User/_groups2
-rw-r--r--Completion/User/_gs10
-rw-r--r--Completion/User/_hosts2
-rw-r--r--Completion/User/_lynx2
-rw-r--r--Completion/User/_mount29
-rw-r--r--Completion/User/_mutt23
-rw-r--r--Completion/User/_netscape71
-rw-r--r--Completion/User/_nslookup14
-rw-r--r--Completion/User/_pbm4
-rw-r--r--Completion/User/_ports2
-rw-r--r--Completion/User/_rlogin19
-rw-r--r--Completion/User/_socket17
-rw-r--r--Completion/User/_ssh115
-rw-r--r--Completion/User/_telnet18
-rw-r--r--Completion/User/_tiff4
-rw-r--r--Completion/User/_urls19
-rw-r--r--Completion/User/_user_at_host10
-rw-r--r--Completion/User/_users2
-rw-r--r--Completion/User/_users_on2
-rw-r--r--Completion/User/_wget2
-rw-r--r--Completion/User/_whois23
-rw-r--r--Completion/User/_yp33
-rw-r--r--Completion/X/_x_color2
-rw-r--r--Completion/X/_x_cursor2
-rw-r--r--Completion/X/_x_display2
-rw-r--r--Completion/X/_x_extension2
-rw-r--r--Completion/X/_x_font2
-rw-r--r--Completion/X/_x_keysym2
-rw-r--r--Completion/X/_x_modifier2
-rw-r--r--Completion/X/_x_window2
-rw-r--r--Completion/X/_xmodmap10
91 files changed, 874 insertions, 725 deletions
diff --git a/Completion/Base/_arguments b/Completion/Base/_arguments
index 68b52eef4..fbc7d7875 100644
--- a/Completion/Base/_arguments
+++ b/Completion/Base/_arguments
@@ -3,7 +3,7 @@
 # Complete the arguments of the current command according to the
 # descriptions given as arguments to this function.
 
-local long cmd="$words[1]" descr mesg
+local long cmd="$words[1]" descr mesg subopts
 
 long=$argv[(I)--]
 if (( long )); then
@@ -151,17 +151,30 @@ 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
+
 if comparguments -i "$compconfig[autodescribe_options]" "$@"; then
   local nm="$compstate[nmatches]" action noargs aret expl local
   local next direct odirect equal single match matched ws tmp1 tmp2
-  local opts
+  local opts _sub_context oldsc="${_sub_context}"
 
   if comparguments -D descr action; then
+    comparguments -C _sub_context
+    _sub_context="${oldsc}:${oldsc:+${oldsc}-}${_sub_context}"
+
     if comparguments -O next direct odirect equal; then
       opts=yes
-      _tags argument option
+      _tags "${oldsc}:any" arguments options
     else
-      _tags argument
+      _tags "${oldsc}:any" arguments
     fi
   else
     if comparguments -a; then
@@ -172,12 +185,12 @@ if comparguments -i "$compconfig[autodescribe_options]" "$@"; then
     comparguments -O next direct odirect equal || return 1
 
     opts=yes
-    _tags option
+    _tags "${oldsc}:any" options
   fi
 
   while _tags; do
     while true; do
-      if [[ -n "$matched" ]] || _requested argument; then
+      if [[ -n "$matched" ]] || _requested arguments; then
         _description expl "$descr"
 
         if [[ "$action" = -\>* ]]; then
@@ -207,13 +220,13 @@ if comparguments -i "$compconfig[autodescribe_options]" "$@"; then
 
             eval ws\=\( "${action[3,-3]}" \)
 
-            _describe -c "$cmd" "$descr" ws -M "$match"
+            _describe -c "$cmd" "$descr" ws -M "$match" "$subopts[@]"
 
           elif [[ "$action" = \(*\) ]]; then
 
             # Anything inside `(...)' is added directly.
 
-            compadd "$expl[@]" - ${=action[2,-2]}
+            compadd "$subopts[@]" "$expl[@]" - ${=action[2,-2]}
           elif [[ "$action" = \{*\} ]]; then
 
             # A string in braces is evaluated.
@@ -230,12 +243,13 @@ if comparguments -i "$compconfig[autodescribe_options]" "$@"; then
             # Otherwise we call it with the description-arguments built above.
 
             action=( $=action )
-            ${(e)action[1]} "$expl[@]" ${(e)~action[2,-1]}
+            ${(e)action[1]} "$subopts[@]" "$expl[@]" ${(e)~action[2,-1]}
           fi
         fi
       fi
-      if [[ -z "$matched" ]] && _requested option &&
-          { ! _style option prefix || [[ "$PREFIX" = [-+]* ]] } ; then
+      if [[ -z "$matched" ]] && _requested options &&
+          { ! _style options prefix-needed yes ||
+            [[ "$PREFIX" = [-+]* ]] } ; then
         comparguments -M match
 
         if comparguments -s single; then
@@ -267,7 +281,7 @@ if comparguments -i "$compconfig[autodescribe_options]" "$@"; then
       fi
       if [[ -n "$opts" && -z "$aret$matched" &&
             nm -ne compstate[nmatches] ]] &&
-          _requested argument; then
+          _requested arguments; then
 
         local prefix suffix
 
@@ -282,7 +296,8 @@ if comparguments -i "$compconfig[autodescribe_options]" "$@"; then
 	  SUFFIX="$suffix"
 	  IPREFIX="${IPREFIX}${equal[1]%%:*}="
 	  matched=yes
-	  comparguments -L "$equal[1]" descr action
+	  comparguments -L "$equal[1]" descr action _sub_context
+          _sub_context="${oldsc}:${oldsc+${oldsc}-}${_sub_context}"
 	  continue
         fi
       fi
diff --git a/Completion/Base/_brace_parameter b/Completion/Base/_brace_parameter
index 9ed4867ef..1d1a48c78 100644
--- a/Completion/Base/_brace_parameter
+++ b/Completion/Base/_brace_parameter
@@ -1,6 +1,6 @@
 #compdef -brace-parameter-
 
-_parameters -e
+_tags any 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 889b330bd..8d8f5630f 100644
--- a/Completion/Base/_command_names
+++ b/Completion/Base/_command_names
@@ -4,38 +4,27 @@
 # complete only external commands and executable files. This and a
 # `-' as the first argument is then removed from the arguments.
 
-local nm=$compstate[nmatches] ret=1 expl ext
+local args defs
+
+defs=(
+  'commands:external command:compadd - ${(@k)commands}'
+  'executables:executable file or directory:_path_files -/g \*\(\*\)'
+)
 
 if [[ "$1" = -e ]]; then
-  ext=yes
-  shift
-elif [[ "$1" = - ]]; then
   shift
-fi
+else
+  [[ "$1" = - ]] && shift
 
-# Complete jobs in implicit fg and bg
-if [[ -z "$ext" && "$PREFIX[1]" = "%" ]]; then
-  _jobs
-  [[ nm -ne compstate[nmatches] ]] && return
+  defs=( "$defs[@]"
+    'jobs:: _jobs'
+    'builtins:builtin command:compadd - ${(@k)builtins}'
+    'functions:shell function:compadd - ${(@k)functions}'
+    'aliases:alias:compadd - ${(@k)aliases}'
+    'reserved-words:reserved word:compadd - ${(@k)reswords}'
+  )
 fi
 
-_description expl 'external command'
-compadd "$expl[@]" "$@" - "${(k@)commands}" && ret=0
+args=( "$@" )
 
-if [[ -z "$ext" ]]; then
-  _description expl 'builtin command'
-  compadd "$expl[@]" "$@" - "${(k@)builtins}" && ret=0
-  _description expl 'shell function'
-  compadd "$expl[@]" "$@" - "${(k@)functions}" && ret=0
-  _description expl 'alias'
-  compadd "$expl[@]" "$@" - "${(k@)aliases}" && ret=0
-  _description expl 'reserved word'
-  compadd "$expl[@]" "$@" - "${(k@)reswords}" && ret=0
-fi
-
-if [[ nm -eq compstate[nmatches] ]]; then
-  _description expl 'executable file or directory'
-  _path_files "$expl[@]" "$@" -/g "*(*)"
-else
-  return ret
-fi
+_alternative -O args any "$defs[@]"
diff --git a/Completion/Base/_condition b/Completion/Base/_condition
index 84c9fea20..93bbdc7f4 100644
--- a/Completion/Base/_condition
+++ b/Completion/Base/_condition
@@ -3,14 +3,13 @@
 local prev="$words[CURRENT-1]"
 
 if [[ "$prev" = -o ]]; then
+  _tags - -o options || return 1
+
   _options
 elif [[ "$prev" = -([no]t|ef) ]]; then
+  _tags - "$prev" files || return 1
+
   _files
 else
-  local ret=1
-
-  _files && ret=0
-  _parameters && ret=0
-
-  return ret
+  _alternative any 'files:: _files' 'parameters:: _parameters'
 fi
diff --git a/Completion/Base/_default b/Completion/Base/_default
index 4fb0b36dd..cf4077d3b 100644
--- a/Completion/Base/_default
+++ b/Completion/Base/_default
@@ -14,12 +14,13 @@ local expl
 
 # compcall || return 0
 
+_tags any files || return 1
+
 _description expl file
 _files "$expl[@]" && return
 
 # magicequalsubst allows arguments like <any-old-stuff>=~/foo to do
 # file name expansion after the =.  In that case, it's natural to
 # allow completion to handle file names after any equals sign.
-if [[ -o magicequalsubst ]] && compset -P 1 '*='; then
-  _files "$expl[@]"
-fi
+
+[[ -o magicequalsubst ]] && compset -P 1 '*=' && _files "$expl[@]"
diff --git a/Completion/Base/_describe b/Completion/Base/_describe
index 41c2ba8e5..db2011727 100644
--- a/Completion/Base/_describe
+++ b/Completion/Base/_describe
@@ -2,8 +2,8 @@
 
 # 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
-local type=value
+local cmd opt expl tmps tmpd tmpmd tmpms ret=1 showd _nm hide args
+local type=values
 
 cmd="$words[1]"
 
@@ -11,7 +11,7 @@ cmd="$words[1]"
 
 while getopts 'oc:' opt; do
   if [[ "$opt" = o ]]; then
-    type=option
+    type=options
   else
     cmd="$OPTARG"
   fi
@@ -20,9 +20,9 @@ shift OPTIND-1
 
 # Do the tests. `showd' is set if the descriptions should be shown.
 
-_tags -c "$cmd" "$type" || return 1
+_tags -c "$cmd" any "$type" || return 1
 
-_style "$type" describe && showd=yes
+_style "$type" description yes && showd=yes
 
 _description expl "$1"
 shift
@@ -33,7 +33,7 @@ else
   compdescribe -i "$@"
 fi
 
-[[ "$type" = option ]] && _style option hide && hide=yes
+[[ "$type" = options ]] && _style options prefix-hidden yes && hide=yes
 
 while compdescribe -g args tmpd tmpmd tmps tmpms; do
 
diff --git a/Completion/Base/_equal b/Completion/Base/_equal
index c50741ed4..760f85c68 100644
--- a/Completion/Base/_equal
+++ b/Completion/Base/_equal
@@ -1,8 +1,9 @@
 #compdef -equal-
 
-local expl
+local args
 
-_description expl alias
-compadd "$@" "$expl[@]" - "${(@k)aliases}"
-_description expl command
-compadd "$@" "$expl[@]" - "${(k@)commands}"
+args=( "$@" )
+
+_alternative -O args any \
+    'commands:command:compadd - ${(@k)commands}' \
+    'aliases:alias:compadd - ${(@k)aliases}'
diff --git a/Completion/Base/_jobs b/Completion/Base/_jobs
index 869aeeb8a..ba83d784e 100644
--- a/Completion/Base/_jobs
+++ b/Completion/Base/_jobs
@@ -1,6 +1,12 @@
 #autoload
 
-local expl disp jobs job jids
+local expl disp jobs job jids pfx='%' desc
+
+_tags any jobs || return 1
+
+_style jobs prefix-needed yes && [[ "$PREFIX" != %* ]] && return 1
+_style jobs prefix-hidden yes && pfx=''
+_style jobs description yes   && desc=yes
 
 if [[ "$1" = -r ]]; then
   jids=( "${(@k)jobstates[(R)running*]}" )
@@ -19,9 +25,13 @@ fi
 disp=()
 jobs=()
 for job in "$jids[@]"; do
-  disp=( "$disp[@]" "${(l:3:: ::%:)job} -- ${jobtexts[$job]}" )
+  [[ -n "$desc" ]] &&
+      disp=( "$disp[@]" "${pfx}${(r:2:: :)job} -- ${(r:COLUMNS-8:: :)jobtexts[$job]}" )
   jobs=( "$jobs[@]" "$job" )
 done
 
-compadd "$@" "$expl[@]" -ld disp - "%$^jobs[@]"
-
+if [[ -n "$desc" ]]; then
+  compadd "$@" "$expl[@]" -ld disp - "%$^jobs[@]"
+else
+  compadd "$@" "$expl[@]" - "%$^jobs[@]"
+fi
diff --git a/Completion/Base/_math b/Completion/Base/_math
index b9743d6b4..77d97acf1 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
 
-_parameters
+_tags any parameters && _parameters
diff --git a/Completion/Base/_parameter b/Completion/Base/_parameter
index 1ede49e27..3ed91d620 100644
--- a/Completion/Base/_parameter
+++ b/Completion/Base/_parameter
@@ -1,6 +1,6 @@
 #compdef -parameter-
 
-_parameters -e
+_tags any 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/_subscript b/Completion/Base/_subscript
index 803893912..c5c6ca7e9 100644
--- a/Completion/Base/_subscript
+++ b/Completion/Base/_subscript
@@ -3,10 +3,14 @@
 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
 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]}}"
@@ -14,22 +18,39 @@ elif [[ ${(Pt)${compstate[parameter]}} = assoc* ]]; then
     compadd "$expl[@]" -S ']' - "${(@kP)${compstate[parameter]}}"
   fi
 elif [[ ${(Pt)${compstate[parameter]}} = array* ]]; then
-  local list i j
-
-  _description expl 'array index'
-  ind=( {1..${#${(P)${compstate[parameter]}}}} )
-  list=()
-  for i in "$ind[@]"; do
-    [[ "$i" = ${PREFIX}*${SUFFIX} ]] &&
-        list=( "$list[@]" 
-	  "${(r:4:: ::):)i} $(print -D ${(P)${compstate[parameter]}[$i]})" )
+  local list i j ret=1 disp
+
+  _tags any indexes parameters
+
+  while _tags; do
+    if _requested indexes; then
+      _description -V expl 'array index'
+      ind=( {1..${#${(P)${compstate[parameter]}}}} )
+      if _style indexes description yes; then
+        list=()
+        for i in "$ind[@]"; do
+          [[ "$i" = ${PREFIX}*${SUFFIX} ]] &&
+              list=( "$list[@]" 
+	             "${i}:$(print -D ${(P)${compstate[parameter]}[$i]})" )
+        done
+        compdisplay list ' -- ' "$list[@]"
+	disp=( -d list)
+      else
+        disp=()
+      fi
+
+      if [[ "$RBUFFER" = \]* ]]; then
+        compadd "$expl[@]" -S '' "$disp[@]" - "$ind[@]" && ret=0
+      else
+        compadd "$expl[@]" -S ']' "$disp[@]" - "$ind[@]" && ret=0
+      fi
+    fi
+    _requested parameters && _parameters && ret=0
+
+    (( ret )) || return 0
   done
 
-  if [[ "$RBUFFER" = \]* ]]; then
-    compadd "$expl[@]" -S '' -V default -d list - "$ind[@]"
-  else
-    compadd "$expl[@]" -S ']' -V default -d list - "$ind[@]"
-  fi
+  return 1
 else
   _compalso -math-
 fi
diff --git a/Completion/Base/_tilde b/Completion/Base/_tilde
index 0b81f75a1..afdca1222 100644
--- a/Completion/Base/_tilde
+++ b/Completion/Base/_tilde
@@ -4,40 +4,53 @@
 # for you or if there are too many of them, you may want to use
 # `compadd -qS/ - "$friends[@]"' or something like that.
 
-local d s dirs list lines revlines i
+local expl suf dirs list lines revlines i ret disp
 
 if [[ "$SUFFIX" = */* ]]; then
   ISUFFIX="/${SUFFIX#*/}$ISUFFIX"
   SUFFIX="${SUFFIX%%/*}"
-  s=(-S '')
+  suf=(-S '')
 else
-  s=(-qS/)
+  suf=(-qS/)
 fi
 
-if [[ -prefix [-+] ]]; then
-  lines=("$PWD" "$dirstack[@]")
-  integer i
-  if [[ ( -prefix - && ! -o pushdminus ) ||
-	( -prefix + && -o pushdminus ) ]]; then
-    revlines=( $lines )
-    for (( i = 1; i <= $#lines; i++ )); do
-      lines[$i]="$((i-1)) -- ${revlines[-$i]}"
-    done
-  else
-    for (( i = 1; i <= $#lines; i++ )); do
-      lines[$i]="$((i-1)) -- ${lines[$i]}"
-    done
+_tags any users named-directoriess 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
-  list=(${lines%% *})
-  compset -P '[-+]'
-  _description d 'directory stack'
-  compadd "$d[@]" -V dirs -S/ -ld lines -Q - "$list[@]" 
-else
-  _users "$@"
-  if (( $# )); then
-    d=( "$@" )
-  else
-    _description d 'named directory'
+
+  if _requested directory-stack &&
+     { ! _style directory-stack prefix-needed yes ||
+       [[ "$PREFIX" = [-+]* ]] }; then
+    if _style directory-stack description yes; then
+      integer i
+
+      lines=("${PWD}" "${dirstack[@]}")
+
+      if [[ ( -prefix - && ! -o pushdminus ) ||
+	    ( -prefix + && -o pushdminus ) ]]; then
+        revlines=( $lines )
+        for (( i = 1; i <= $#lines; i++ )); do
+          lines[$i]="$((i-1)) -- ${revlines[-$i]}"
+        done
+      else
+        for (( i = 1; i <= $#lines; i++ )); do
+          lines[$i]="$((i-1)) -- ${lines[$i]}"
+        done
+      fi
+      list=( ${PREFIX[1]}${^lines%% *} )
+      disp=( -ld lines )
+    else
+      list=( ${PREFIX[1]}{0..${#dirstack}} )
+      disp=()
+    fi
+
+    _description -V expl 'directory stack'
+    compadd "$expl[@]" "$suf[@]" "$disp[@]" -Q - "$list[@]" && ret=0
   fi
-  compadd "$d[@]" "$s[@]" - "${(@k)nameddirs}"
-fi
+  (( ret )) || return 0
+done
diff --git a/Completion/Base/_values b/Completion/Base/_values
index aac8b392d..e4d61d288 100644
--- a/Completion/Base/_values
+++ b/Completion/Base/_values
@@ -1,12 +1,27 @@
 #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
+
 if compvalues -i "$@"; then
 
-  local noargs args opts descr action expl sep
+  local noargs args opts descr action expl sep _sub_context oldsc="$_sub_context"
 
   if ! compvalues -D descr action; then
 
-    _tags value || return 1
+    compvalues -C _sub_context
+    _sub_context="${oldsc}:${oldsc+${oldsc}-}${_sub_context}"
+
+    _tags "${_sub_context}" values || return 1
 
     compvalues -V noargs args opts
 
@@ -32,7 +47,8 @@ if compvalues -i "$@"; then
         PREFIX="$prefix"
 	SUFFIX="$suffix"
         IPREFIX="${IPREFIX}${args[1]%%:*}="
-	compvalues -L "${args[1]%%:*}" descr action
+	compvalues -L "${args[1]%%:*}" descr action _sub_context
+        _sub_context="${oldsc}:${oldsc+${oldsc}-}${_sub_context}"
       fi
     else
       compvalues -d descr
@@ -49,9 +65,12 @@ if compvalues -i "$@"; then
 
       return
     fi
+  else
+    compvalues -C _sub_context
+    _sub_context="${oldsc}:${oldsc+${oldsc}-}${_sub_context}"
   fi
 
-  _tags argument || return 1
+  _tags "${oldsc}:any" arguments || return 1
 
   _description expl "$descr"
 
@@ -85,13 +104,13 @@ if compvalues -i "$@"; then
 
       eval ws\=\( "${action[3,-3]}" \)
 
-      _describe "$descr" ws -M 'r:|[_-]=* r:|=*'
+      _describe "$descr" ws -M 'r:|[_-]=* r:|=*' "$subopts[@]"
 
     elif [[ "$action" = \(*\) ]]; then
 
       # Anything inside `(...)' is added directly.
 
-      compadd "$expl[@]" - ${=action[2,-2]}
+      compadd "$subopts[@]" "$expl[@]" - ${=action[2,-2]}
     elif [[ "$action" = \{*\} ]]; then
 
       # A string in braces is evaluated.
@@ -108,13 +127,11 @@ if compvalues -i "$@"; then
       # Otherwise we call it with the description-arguments built above.
 
       action=( $=action )
-      ${(e)action[1]} "$expl[@]" ${(e)~action[2,-1]}
+      ${(e)action[1]} "$subopts[@]" "$expl[@]" ${(e)~action[2,-1]}
     fi
   fi
 
   [[ nm -ne "$compstate[nmatches]" ]]
-  return
-
 else
   return 1;
 fi
diff --git a/Completion/Base/_vars b/Completion/Base/_vars
index a81a49f48..43cdf5d2c 100644
--- a/Completion/Base/_vars
+++ b/Completion/Base/_vars
@@ -4,8 +4,6 @@
 # `vared compconfig[<TAB>'.  However, in this version the [ must be
 # added by hand.
 
-local expl
-
 if [[ $PREFIX = *\[* ]]; then
   local var=${PREFIX%%\[*}
   local elt="${PREFIX#*\]}${SUFFIX%\]}"
@@ -16,9 +14,15 @@ if [[ $PREFIX = *\[* ]]; then
     addclose=(-S ']')
   fi
   if [[ ${(tP)var} = assoc* ]]; then
+    local expl
+
+    _tags subscript association-keys || return 1
+
     _description expl 'association key'
     compadd "$expl[@]" $addclose - ${(kP)var}
   fi
 else
-  _parameter
+  _tags any parameters || return 1
+
+  _parameters
 fi
diff --git a/Completion/Builtins/_aliases b/Completion/Builtins/_aliases
index 8764f7f66..a097d020e 100644
--- a/Completion/Builtins/_aliases
+++ b/Completion/Builtins/_aliases
@@ -2,7 +2,6 @@
 
 local expl
 
-_description expl 'regular alias'
-compadd "$expl[@]" - "${(@k)aliases}"
-_description expl 'global alias'
-compadd "$expl[@]" - "${(@k)galiases}"
+_alternative any:argument \
+  'aliases:regular alias:compadd - ${(@k)aliases}' \
+  'global-aliases:global alias:compadd - ${(@k)galiases}'
diff --git a/Completion/Builtins/_arrays b/Completion/Builtins/_arrays
index a2aa813b6..37eb20bf5 100644
--- a/Completion/Builtins/_arrays
+++ b/Completion/Builtins/_arrays
@@ -2,5 +2,7 @@
 
 local expl
 
+_tags any:argument arrays || return 1
+
 _description expl array
 compadd "$expl[@]" - "${(@k)parameters[(R)*array*]}"
diff --git a/Completion/Builtins/_autoload b/Completion/Builtins/_autoload
index 4a97b2aec..116bb7765 100644
--- a/Completion/Builtins/_autoload
+++ b/Completion/Builtins/_autoload
@@ -2,5 +2,7 @@
 
 local expl
 
+_tags any:argument functions || return 1
+
 _description expl 'shell function'
 compadd "$expl[@]" - ${^fpath}/*(N:t)
diff --git a/Completion/Builtins/_bindkey b/Completion/Builtins/_bindkey
index b60dafbb2..31215a576 100644
--- a/Completion/Builtins/_bindkey
+++ b/Completion/Builtins/_bindkey
@@ -10,9 +10,13 @@
 local expl
 
 if [[ "$words[2]" = -*[DAN]* || "$words[CURRENT-1]" = -*M ]]; then
+  _tags -M keymaps || return 1
+
   _description expl keymap
   compadd "$expl[@]" - "$keymaps[@]"
 else
+  _tags any:argument widgets || return 1
+
   _description expl widget
   compadd "$expl[@]" -M 'r:|-=* r:|=*' - "${(@k)widgets}"
 fi
diff --git a/Completion/Builtins/_builtin b/Completion/Builtins/_builtin
index cf02093bb..fcb20560f 100644
--- a/Completion/Builtins/_builtin
+++ b/Completion/Builtins/_builtin
@@ -7,6 +7,8 @@ if (( $CURRENT > 2 )); then
 else
   local expl
 
+  _tags any:command commands || return 1
+
   _description expl 'builtin command'
   compadd "$expl[@]" "$@" - "${(k@)builtins}"
 fi
diff --git a/Completion/Builtins/_cd b/Completion/Builtins/_cd
index b407b5a85..26846fde2 100644
--- a/Completion/Builtins/_cd
+++ b/Completion/Builtins/_cd
@@ -22,10 +22,13 @@ 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]}})
-  _description expl replacement
-  (( ! $#rep )) || compadd "$expl[@]" $rep
+  if (( $#rep )) && _tags replacement strings; then
+    _description expl replacement
+    compadd "$expl[@]" $rep
+  fi
 elif _popd || [[ $PREFIX != (\~|/|./|../)* && $#cdpath -ne 0 ]]; then
   local tdir tdir2
+
   # With cdablevars, we can convert foo/bar/... to ~foo/bar/... if
   # there is no directory foo.  In that case we could also complete
   # variable names, but it hardly seems worth it.
diff --git a/Completion/Builtins/_command b/Completion/Builtins/_command
index 9f54aae80..23995dbbe 100644
--- a/Completion/Builtins/_command
+++ b/Completion/Builtins/_command
@@ -6,6 +6,8 @@ if [[ CURRENT -ge 3 ]]; then
 else
   local expl
 
+  _tags any:command commands || return 1
+
   _description expl 'external command'
   compadd "$expl[@]" "$@" - "${(k@)commands}"
 fi
diff --git a/Completion/Builtins/_compdef b/Completion/Builtins/_compdef
index 4208c2689..df25d44de 100644
--- a/Completion/Builtins/_compdef
+++ b/Completion/Builtins/_compdef
@@ -12,10 +12,14 @@ while [[ $words[base] = -* ]]; do
 done
 
 if [ "$delete" ]; then
+  _tags any:argument commands || return 1
+
   _description 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)
   else
diff --git a/Completion/Builtins/_disable b/Completion/Builtins/_disable
index af4805c25..33c202864 100644
--- a/Completion/Builtins/_disable
+++ b/Completion/Builtins/_disable
@@ -1,22 +1,15 @@
 #compdef disable
 
-local prev="$words[CURRENT-1]" ret=1 expl
+local prev="$words[CURRENT-1]" args
 
-if [[ "$prev" = -*a* ]]; then
-  _description expl alias
-  compadd "$expl[@]" "$@" - "${(k@)aliases}" && ret=0
-fi
-if [[ "$prev" = -*f* ]]; then
-  _description expl 'shell function'
-  compadd "$expl[@]" "$@" - "${(k@)functions}" && ret=0
-fi
-if [[ "$prev" = -*r* ]]; then
-  _description expl 'reserved word'
-  compadd "$expl[@]" "$@" - "${(k@)reswords}" && ret=0
-fi
-if [[ "$prev" != -* ]]; then
-  _description expl 'builtin command'
-  compadd "$expl[@]" "$@" - "${(k@)builtins}" && ret=0
-fi
+args=()
+[[ "$prev" = -*a* ]] &&
+    tags=( 'aliases:alias:compadd - ${(@k)aliases} ${(@k)galiases} )
+[[ "$prev" = -*f* ]] &&
+    tags=( "$tags[@]" 'functions:shell function:compadd - ${(@k)functions}' )
+[[ "$prev" = -*r* ]] &&
+    tags=( "$tags[@]" 'reserved-words:reserved word:compadd - ${(@k)reswords}' )
+[[ "$prev" != -* ]]  &&
+    tags=( 'builtins:builtin command:compadd - ${(@k)builtins} )
 
-return ret
+_alternative any "$args[@]"
diff --git a/Completion/Builtins/_echotc b/Completion/Builtins/_echotc
index 46bf38261..2193261a1 100644
--- a/Completion/Builtins/_echotc
+++ b/Completion/Builtins/_echotc
@@ -2,6 +2,8 @@
 
 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
diff --git a/Completion/Builtins/_enable b/Completion/Builtins/_enable
index 7d15e9121..ae2bdc38c 100644
--- a/Completion/Builtins/_enable
+++ b/Completion/Builtins/_enable
@@ -1,22 +1,15 @@
 #compdef enable
 
-local prev="$words[CURRENT-1]" ret=1 expl
+local prev="$words[CURRENT-1]" args
 
-if [[ "$prev" = -*a* ]]; then
-  _description expl alias
-  compadd "$expl[@]" "$@" - "${(k@)dis_aliases}" "${(k@)dis_galiases}" && ret=0
-fi
-if [[ "$prev" = -*f* ]]; then
-  _description expl 'shell function'
-  compadd "$expl[@]" "$@" - "${(k@)dis_functions}" && ret=0
-fi
-if [[ "$prev" = -*r* ]]; then
-  _description expl 'reserved word'
-  compadd "$expl[@]" "$@" - "${(k@)dis_reswords}" && ret=0
-fi
-if [[ "$prev" != -* ]]; then
-  _description expl 'builtin command'
-  compadd "$expl[@]" "$@" - "${(k@)dis_builtins}" && ret=0
-fi
+args=()
+[[ "$prev" = -*a* ]] &&
+    tags=( 'aliases:alias:compadd - ${(@k)dis_aliases} ${(@k)dis_galiases} )
+[[ "$prev" = -*f* ]] &&
+    tags=( "$tags[@]" 'functions:shell function:compadd - ${(@k)dis_functions}' )
+[[ "$prev" = -*r* ]] &&
+    tags=( "$tags[@]" 'reserved-words:reserved word:compadd - ${(@k)dis_reswords}' )
+[[ "$prev" != -* ]]  &&
+    tags=( 'builtins:builtin command:compadd - ${(@k)dis_builtins} )
 
-return ret
+_alternative any "$args[@]"
diff --git a/Completion/Builtins/_functions b/Completion/Builtins/_functions
index 81a56eb83..9e6925ce7 100644
--- a/Completion/Builtins/_functions
+++ b/Completion/Builtins/_functions
@@ -2,5 +2,7 @@
 
 local expl
 
+_tags argument:any functions || return 1
+
 _description expl 'shell function'
 compadd "$expl[@]" "$@" - "${(k@)functions}"
diff --git a/Completion/Builtins/_hash b/Completion/Builtins/_hash
index 4cb72b09c..24a9964b9 100644
--- a/Completion/Builtins/_hash
+++ b/Completion/Builtins/_hash
@@ -4,15 +4,23 @@ local expl
 
 if [[ "$words[2]" = -*d* ]]; then
   if compset -P 1 '*\='; then
+    _tags - -d-value files || return 1
+
     _path_files -g '*(-/)'
   else
+    _tags - -d named-directories || return 1
+
     _description 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 '*(*)'
 else
+  _tags any:argument commands || return 1
+
   _description expl command
   compadd "$expl[@]" -q -S '=' - "${(@k)commands}"
 fi
diff --git a/Completion/Builtins/_kill b/Completion/Builtins/_kill
index 43ff40838..e2dc88dac 100644
--- a/Completion/Builtins/_kill
+++ b/Completion/Builtins/_kill
@@ -4,10 +4,10 @@ local list expl
 
 if compset -P 1 -; then
 
-  _tags signal || return 1
+  _tags - -:signal signals || return 1
 
   _description expl signal
   compadd "$expl[@]" $signals[1,-3]
 else
-  _alternative 'job:: _jobs' 'process:: _pids'
+  _alternative argument 'jobs:: _jobs' 'processes:: _pids'
 fi
diff --git a/Completion/Builtins/_limits b/Completion/Builtins/_limits
index 0072438c3..12e90e96a 100644
--- a/Completion/Builtins/_limits
+++ b/Completion/Builtins/_limits
@@ -2,5 +2,7 @@
 
 local expl
 
+_tags any:argument limits || return 1
+
 _description expl 'process limits'
 compadd "$expl[@]" ${${(f)"$(limit)"}%% *}
diff --git a/Completion/Builtins/_pids b/Completion/Builtins/_pids
index 0ffda900b..f96c11e2d 100644
--- a/Completion/Builtins/_pids
+++ b/Completion/Builtins/_pids
@@ -3,7 +3,9 @@
 # If given the `-m <pattern>' option, this tries to complete only pids
 # of processes whose command line match the `<pattern>'.
 
-local list expl match
+local list expl match desc
+
+_tags any processes || return 1
 
 if [[ "$1" = -m ]]; then
   match="${2}*"
@@ -12,7 +14,12 @@ fi
 
 _description expl 'process ID'
 
-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 yes; then
+  list=("${(@Mr:COLUMNS-1:)${(f@)$(ps ${=compconfig[ps_listargs]:-$=compconfig[ps_args]} 2>/dev/null)}[2,-1]:#[ 	]#${PREFIX}[0-9]#${SUFFIX}[ 	]*${~match}}")
+  desc=(-ld list)
+else
+  desc=()
+fi
 
-compadd "$expl[@]" "$@" -ld list - \
+compadd "$expl[@]" "$@" "$desc[@]" - \
   ${${${(M)${(f)"$(ps $=compconfig[ps_args] 2>/dev/null)"}[2,-1]:#*${~match}}## #}%% *}
diff --git a/Completion/Builtins/_popd b/Completion/Builtins/_popd
index 9054befb7..5e4910f48 100644
--- a/Completion/Builtins/_popd
+++ b/Completion/Builtins/_popd
@@ -5,36 +5,39 @@
 # way round if pushdminus is set). Note that this function is also called
 # from _cd for cd and pushd.
 
-emulate -L zsh
 setopt extendedglob nonomatch
 
-[[ $PREFIX = [-+]* ]] || return 1
+_tags any directory-stack || return 1
 
-local expl list lines revlines ret=1 i
+! _style directory-stack prefix-needed yes ||
+    [[ $PREFIX = [-+]* ]] || return 1
 
-IPREFIX=$PREFIX[1]
-PREFIX=$PREFIX[2,-1]
+local expl list lines revlines disp
 
-# get the list of directories with their canonical number
-# and turn the lines into an array, removing the current directory
-lines=( ${${(f)"$(dirs -v)"}##0*} )
-if [[ ( $IPREFIX = - && ! -o pushdminus ) ||
-      ( $IPREFIX = + && -o pushdminus ) ]]; then
-  integer i
-  revlines=( $lines )
-  for (( i = 1; i <= $#lines; i++ )); do
-    lines[$i]="$((i-1)) -- ${revlines[-$i]##[0-9]#[	 ]#}"
-  done
+if _style directory-stack description yes; then
+  # get the list of directories with their canonical number
+  # and turn the lines into an array, removing the current directory
+  lines=("${PWD}" "${dirstack[@]}")
+
+  if [[ ( $PREFIX[1] = - && ! -o pushdminus ) ||
+        ( $PREFIX[1] = + && -o pushdminus ) ]]; then
+    integer i
+    revlines=( $lines )
+    for (( i = 1; i <= $#lines; i++ )); do
+      lines[$i]="$((i-1)) -- ${revlines[-$i]##[0-9]#[	 ]#}"
+    done
+  else
+    for (( i = 1; i <= $#lines; i++ )); do
+      lines[$i]="$i -- ${lines[$i]##[0-9]#[	 ]#}"
+    done
+  fi
+  # get the array of numbers only
+  list=( ${PREFIX[1]}${^lines%% *} )
+  disp=( -ld lines )
 else
-  for (( i = 1; i <= $#lines; i++ )); do
-    lines[$i]="$i -- ${lines[$i]##[0-9]#[	 ]#}"
-  done
+  list=( ${PREFIX[1]}{0..${#dirstack}} )
+  disp=()
 fi
-# get the array of numbers only
-list=(${lines%% *})
-_description expl 'directory stack index'
-compadd "$expl[@]" -ld lines -V dirs -Q - "$list[@]" && ret=0
-[[ -z $compstate[list] ]] && compstate[list]=list && ret=0
-[[ -n $compstate[insert] ]] && compstate[insert]=menu && ret=0
-
-return ret
+
+_description -V expl 'directory stack index'
+compadd "$expl[@]" "$@" -qS/ "$disp[@]" -Q - "$list[@]"
diff --git a/Completion/Builtins/_sched b/Completion/Builtins/_sched
index 38bf44a59..d3245f7ef 100644
--- a/Completion/Builtins/_sched
+++ b/Completion/Builtins/_sched
@@ -1,12 +1,19 @@
 #compdef sched
 
-local expl lines
+local expl lines disp
 
 if [[ CURRENT -eq 2 ]]; then
   if compset -P -; then
+    _tags - - entries || return 1
+
     lines=(${(f)"$(sched)"})
+    if _style entries description yes; then
+      disp=( -ld lines )
+    else
+      disp=()
+    fi
     _description expl 'scheduled jobs'
-    [[ -z $lines ]] || compadd "$expl[@]" -ld lines - {1..$#lines}
+    [[ -z $lines ]] || compadd "$expl[@]" "$disp[@]" - {1..$#lines}
   else
     _message 'time specification'
     return 1
diff --git a/Completion/Builtins/_stat b/Completion/Builtins/_stat
index 322f042ec..3f1b62ca3 100644
--- a/Completion/Builtins/_stat
+++ b/Completion/Builtins/_stat
@@ -5,6 +5,8 @@ local expl
 if [[ "$words[CURRENT-1]" = -[AH] ]]; then
   _arrays
 else
+  _tags any:argument elements || return 1
+
   _description expl 'inode element'
   [[ "$PREFIX[1]" = + ]] &&
       compadd "$expl[@]" - +device +inode +mode +nlink +uid +gid +rdev +size \
diff --git a/Completion/Builtins/_trap b/Completion/Builtins/_trap
index 0f0209914..5dbb2d284 100644
--- a/Completion/Builtins/_trap
+++ b/Completion/Builtins/_trap
@@ -6,6 +6,8 @@ if [[ CURRENT -eq 2 ]]; then
   compset -q
   _normal
 else
+  _tags any:argument signals || return 1
+
   _description expl signal
   compadd "$expl[@]" - "$signals[@]"
 fi
diff --git a/Completion/Builtins/_unhash b/Completion/Builtins/_unhash
index a23fd9025..6ccbc21a4 100644
--- a/Completion/Builtins/_unhash
+++ b/Completion/Builtins/_unhash
@@ -1,22 +1,14 @@
 #compdef unhash
 
-local fl="$words[2]" ret=1 expl
+local fl="$words[2]" args
 
-if [[ "$fl" = -*d* ]]; then
-  _description expl 'named directory'
-  compadd "$expl[@]" - "${(@k)nameddirs}" && ret=0
-fi
-if [[ "$fl" = -*a* ]]; then
-  _description expl alias
-  compadd "$expl[@]" - "${(@k)aliases}" "${(@k)dis_aliases}" \
-                       "${(@k)galiases}" "${(@k)dis_galiases}" && ret=0
-fi
-if [[ "$fl" = -*f* ]]; then
-  _description expl 'shell function'
-  compadd "$expl[@]" - "${(@k)functions}" "${(@k)dis_functions}" && ret=0
-fi
-if [[ "$fl" != -* ]]; then
-  _command_names -e && ret=0
-fi
+args=()
+[[ "$fl" = -*d* ]] &&
+    args=( 'named-directories:named directory:compadd - ${(@k)nameddirs}' )
+[[ "$fl" = -*a* ]] &&
+    args=( "$args[@]"
+           'aliases:alias:compadd - ${(@k)aliases} ${(@k)galiases} ${(@k)dis-aliases} ${(@k)dis-galiases}' )
+[[ "$fl != -* ]] &&
+    args=( 'commands:: _command_names -e' )
 
-return ret
+_alternative any:argument "$args[@]"
diff --git a/Completion/Builtins/_wait b/Completion/Builtins/_wait
index c1022a25f..04ad5e873 100644
--- a/Completion/Builtins/_wait
+++ b/Completion/Builtins/_wait
@@ -1,3 +1,3 @@
 #compdef wait
 
-_alternative 'job:: _jobs' 'process:: _pids'
+_alternative argument:any 'jobs:: _jobs' 'processes:: _pids'
diff --git a/Completion/Builtins/_which b/Completion/Builtins/_which
index 41e7d20fd..6e9e0a460 100644
--- a/Completion/Builtins/_which
+++ b/Completion/Builtins/_which
@@ -1,14 +1,12 @@
 #compdef which whence where type
 
-local expl
+local args
 
-_description expl 'external command'
-compadd "$expl[@]" "$@" - "${(k@)commands}" && ret=0
-_description expl 'builtin command'
-compadd "$expl[@]" "$@" - "${(k@)builtins}" && ret=0
-_description expl 'shell function'
-compadd "$expl[@]" "$@" - "${(k@)functions}" && ret=0
-_description expl 'alias'
-compadd "$expl[@]" "$@" - "${(k@)aliases}" && ret=0
-_description expl 'reserved word'
-compadd "$expl[@]" "$@" - "${(k@)reswords}" && ret=0
+args=( "$@" )
+
+_alternative -O args any:argument \
+  'commands:external command:compadd - ${(k@)commands}' \
+  'builtins:builtin command:compadd - ${(k@)builtins}' \
+  'functions:shell function:compadd - ${(k@)functions}' \
+  'aliases:alias:compadd - ${(k@)aliases}' \
+  'reserved-words:reserved word:compadd - ${(k@)reswords}'
diff --git a/Completion/Builtins/_zftp b/Completion/Builtins/_zftp
index 7aa1d94e8..2728d1747 100644
--- a/Completion/Builtins/_zftp
+++ b/Completion/Builtins/_zftp
@@ -13,6 +13,8 @@ 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 \
@@ -27,26 +29,27 @@ fi
 case $subcom in
   *(cd|ls|dir))
     # complete remote directories
-    zfcd_match $PREFIX $SUFFIX
+    _tags "$subcom" directories && zfcd_match $PREFIX $SUFFIX
     ;;
 
   *(get(|at)|gcp|delete|remote))
     # complete remote files
-    zfget_match $PREFIX $SUFFIX
+    _tags "$subcom" files && zfget_match $PREFIX $SUFFIX
     ;;
 
   *(put(|at)|pcp))
     # complete local files
-    _files
+    _tags "$subcom" files && _files
     ;;
 
   *(open|anon|params))
     # complete hosts:  should do cleverer stuff with user names
-    _hosts
+    _tags "$subcom" hosts && _hosts
     ;;
 
   *(goto|mark))
     # complete bookmarks.  First decide if ncftp mode is go.
+    _tags "$subcom" bookmarks || return 1
     _description expl bookmark
     if [[ $words[2] = -*n* ]]; then
       if [[ -f ~/.ncftp/bookmarks ]]; then
@@ -61,6 +64,7 @@ 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}
     ;;
@@ -69,6 +73,7 @@ case $subcom in
     # complete arguments like sess1:file1 sess2:file2
     if [[ $PREFIX = *:* ]]; then
       # complete file in the given session
+      _tags "$subcom" files || return 1
       local sess=${PREFIX%%:*} oldsess=$ZFTP_SESSION
       compset -p $(( $#sess + 1 ))
       [[ -n $sess ]] && zftp session $sess
@@ -76,6 +81,7 @@ 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)
     fi
diff --git a/Completion/Builtins/_zle b/Completion/Builtins/_zle
index a153aabdd..21997ef62 100644
--- a/Completion/Builtins/_zle
+++ b/Completion/Builtins/_zle
@@ -3,9 +3,11 @@
 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
 else
+  _tags any:argument widgets || return 1
   _description expl widget
   compadd "$expl[@]" - "${(@k)widgets}"
 fi
diff --git a/Completion/Builtins/_zmodload b/Completion/Builtins/_zmodload
index 097911307..1a1097a7a 100644
--- a/Completion/Builtins/_zmodload
+++ b/Completion/Builtins/_zmodload
@@ -3,12 +3,15 @@
 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
 elif [[ "$fl" = -*u* ]]; then
+  _tags any:argument modules || return 1
   _description 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)
 fi
diff --git a/Completion/Core/_alternative b/Completion/Core/_alternative
index 158f3a07a..f13fc9e5a 100644
--- a/Completion/Core/_alternative
+++ b/Completion/Core/_alternative
@@ -1,19 +1,22 @@
 #autoload
 
-local tags def expl descr action mesgs nm="$compstack[nmatches]"
-local context
+local tags def expl descr action mesgs nm="$compstack[nmatches]" subopts
 
-if [[ "$1" = -C?* ]]; then
-  context="${1[3,-1]}"
+if [[ "$1" = -O?* ]]; then
+  subopts=( "${(@P)1[3,-1]}" )
   shift
-elif [[ "$1" = -C ]]; then
-  context="$2"
+elif [[ "$1" = -O ]]; then
+  subopts=( "${(@P)2}" )
   shift 2
-fi
+else
+  subopts=()
+fi  
+
+[[ "$1" = -(|-) ]] && shift
 
 mesgs=()
 
-_tags -C "$context" "${(@)argv%%:*}"
+_tags "$1" "${(@)argv[2,-1]%%:*}"
 
 while _tags; do
   for def; do
@@ -35,12 +38,12 @@ while _tags; do
 
         eval ws\=\( "${action[3,-3]}" \)
 
-        _describe "$descr" ws -M 'r:|[_-]=* r:|=*'
+        _describe "$descr" ws -M 'r:|[_-]=* r:|=*' "$subopts[@]"
       elif [[ "$action" = \(*\) ]]; then
 
         # Anything inside `(...)' is added directly.
 
-        compadd "$expl[@]" - ${=action[2,-2]}
+        compadd "$subopts[@]" "$expl[@]" - ${=action[2,-2]}
       elif [[ "$action" = \{*\} ]]; then
 
         # A string in braces is evaluated.
@@ -56,7 +59,7 @@ while _tags; do
         # Otherwise we call it with the description-arguments built above.
 
         action=( $=action )
-        ${(e)action[1]} "$expl[@]" ${(e)~action[2,-1]}
+        ${(e)action[1]} "$subopts[@]" "$expl[@]" ${(e)~action[2,-1]}
       fi
     fi
   done
diff --git a/Completion/Core/_complete b/Completion/Core/_complete
index 073212d0f..f351c7349 100644
--- a/Completion/Core/_complete
+++ b/Completion/Core/_complete
@@ -4,7 +4,10 @@
 # a normal completion function, but as one possible value for the
 # compconfig[completer] parameter.
 
-local comp name
+local comp name _tag_context="$_tag_context"
+
+[[ "$compstate[context]" != command || CURRENT -eq 1 ]] && 
+    _tag_context="-${compstate[context]:s/_/-/}-"
 
 # If we have a user-supplied context name, use only that.
 
@@ -36,7 +39,7 @@ else
   # Let's see if we have a special completion definition for the other
   # possible contexts.
 
-  comp="$_comps[-${compstate[context]:s/_/-/}-]"
+  comp="$_comps[$_tag_context]"
 
   # If not, we use default completion, if any.
 
diff --git a/Completion/Core/_files b/Completion/Core/_files
index eb1ec3559..973eea69b 100644
--- a/Completion/Core/_files
+++ b/Completion/Core/_files
@@ -13,22 +13,22 @@ while getopts "P:S:qr:R:W:F:J:V:X:f/g:M:" opt; do
 done
 
 case "$type" in
-file) _tags file           ;;
-dir)  _tags path file      ;;
-*)    _tags glob path file ;;
+file) _tags any all-files                           ;;
+dir)  _tags any directories all-files               ;;
+*)    _tags any globbed-files directories all-files ;;
 esac
 
 while _tags; do
-  if _requested file; then
+  if _requested all-files; then
     _path_files "$opts[@]" -f
     return
-  elif _requested path; then
-    if _requested glob; then
+  elif _requested directories; then
+    if _requested globbed-files; then
       _path_files "$opts[@]" -/g "$type" && return 0
     else
-      _path_files "$opts[@]" -/g "$type" && return 0
+      _path_files "$opts[@]" -/ && return 0
     fi
-  elif _requested glob; then
+  elif _requested globbed-files; then
     _path_files "$opts[@]" -g "$type" && return 0
   fi
 done
diff --git a/Completion/Core/_main_complete b/Completion/Core/_main_complete
index e4ee2879b..f9a8a19ad 100644
--- a/Completion/Core/_main_complete
+++ b/Completion/Core/_main_complete
@@ -17,9 +17,10 @@
 # state than the global one for which you are completing.
 
 
-local comp post ret=1 _compskip _prio_num=1
+local comp post ret=1 _compskip _prio_num=1 _tag_context _cur_contexts
+local context state line opt_args val_args
 typeset -U _offered_tags _tried_tags _failed_tags _used_tags _unused_tags
-typeset -A _prio_names _cur_tags
+typeset -A _prio_names _prio_contexts _cur_tags _tag_contexts
 
 _offered_tags=()
 _tried_tags=()
diff --git a/Completion/Core/_message b/Completion/Core/_message
index ab1c67992..ee869d33b 100644
--- a/Completion/Core/_message
+++ b/Completion/Core/_message
@@ -2,6 +2,8 @@
 
 local format
 
+_tags any messages || return 1
+
 format="${compconfig[message_format]:-$compconfig[description_format]}"
 
 if [[ -n "$format" ]]; then
diff --git a/Completion/Core/_normal b/Completion/Core/_normal
index 79efaeb97..5d0a18406 100644
--- a/Completion/Core/_normal
+++ b/Completion/Core/_normal
@@ -1,6 +1,7 @@
 #autoload
 
 local comp command cmd1 cmd2 pat val name i ret=1 _compskip="$_compskip"
+local _sub_context
 
 # 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,
diff --git a/Completion/Core/_options b/Completion/Core/_options
index 0232db857..0dd92cf69 100644
--- a/Completion/Core/_options
+++ b/Completion/Core/_options
@@ -4,6 +4,8 @@
 
 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}"
diff --git a/Completion/Core/_parameters b/Completion/Core/_parameters
index fdb786231..da479097e 100644
--- a/Completion/Core/_parameters
+++ b/Completion/Core/_parameters
@@ -5,6 +5,8 @@
 
 local pars expl
 
+_tags any parameters || return 1
+
 _description expl parameter
 
 pars=( ${(k)parameters[(R)^*local*]} )
diff --git a/Completion/Core/_requested b/Completion/Core/_requested
index 082c45820..09c57ee09 100644
--- a/Completion/Core/_requested
+++ b/Completion/Core/_requested
@@ -1,9 +1,9 @@
 #autoload
 
-local tag tname="$funcstack[2,-1]"
+# Reset the current context.
 
-for tag; do
-  [[ "${_cur_tags[${tname}]}" = *:${tag}(:|\[*\]:)* ]] && return 0
-done
+_cur_contexts="${_tag_contexts[$tname]}"
 
-return 1
+# Test if the tag given as argument was requested.
+
+[[ "${_cur_tags[${funcstack[2,-1]}]}" = *:${1}:* ]]
diff --git a/Completion/Core/_set_options b/Completion/Core/_set_options
index 947afdeae..55388d0c8 100644
--- a/Completion/Core/_set_options
+++ b/Completion/Core/_set_options
@@ -6,5 +6,7 @@
 
 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
diff --git a/Completion/Core/_sort_tags b/Completion/Core/_sort_tags
new file mode 100644
index 000000000..f1740511d
--- /dev/null
+++ b/Completion/Core/_sort_tags
@@ -0,0 +1,28 @@
+#autoload
+
+comptry arguments values
+comptry options
+
+case "$contexts" 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
+#   comptry all-files
+#   return
+#   ;;
+# *:kill,*)
+#   comptry processes
+#   return              # this return ensures that we use only processes
+#   ;;
+*)
+  comptry globbed-files
+  comptry directories
+  comptry all-files
+  ;;
+esac
+
+comptry "$@"
diff --git a/Completion/Core/_style b/Completion/Core/_style
index b0cbd7b00..a3b54686f 100644
--- a/Completion/Core/_style
+++ b/Completion/Core/_style
@@ -1,45 +1,50 @@
 #autoload
 
-local tags get i
+local all get val i
+
+# Should we return the value?
 
 if [[ "$1" = -g ]]; then
   get=yes
   shift
 fi
 
-if (( ${+_cur_tags[${funcstack[2,-1]}]} )); then
-  tags="${_cur_tags[${funcstack[2,-1]}]}"
-else
-  tags="${_cur_tags[${funcstack[3,-1]}]}"
-fi
+# Get all styles defined for this context.
 
-if [[ "$tags" = *:${1}\[*\]:* ]]; then
+all=()
+for i in "${(s.:.)_cur_contexts}"; do
+  all=("$all[@]" "${(@)_compstyles[(K)${i},${1}]}" )
+done
+all=":${(j.:.)${(@o)all:#}##??}:"
 
-  tags="${${tags#*:${1}\[}%%\]*}"
+if [[ "$all" = *:${2}[:\=]* ]]; then
 
-  if [[ $# -eq 2 ]]; then
-    if [[ -n "$get" ]]; then
-      eval "${2}=\"$tags\""
-      return 0
-    fi
+  # We have a definition for the style.
 
-    [[ "$tags" = (|*,)${2}(|,*) ]]
-    return
-  fi
+  if [[ $# -eq 3 ]]; then
+    if [[ -n "$get" ]]; then
 
-  [[ "$tags" = (|*,)${2}(|(\=|,)*) ]] || return 1
+      # We have to return the value.
 
-  if [[ -n "$get" ]]; then
-    if [[ "$tags" = (|*,)${2}\=* ]]; then
-      eval "${3}=\"${${tags#(|*,)${2}\=}%%,*}\""
+      if [[ "$all" = *,${2}\=* ]]; then
+        eval "${3}=\"${${all#*:${2}\=}%%:*}\""
+      else
+        eval "${3}=''"
+      fi
     else
-      eval "${3}=''"
+
+      # We have to test the value.
+
+      if [[ "$all" = *:${2}\=* ]]; then
+        [[ "${${all#*:${2}\=}%%:*}" = ${~3} ]]
+      else
+        [[ '' -eq ${~3} ]]
+      fi
+
+      return
     fi
-    return 0
   fi
-
-  [[ "$tags" = (|*,)${2}\=(|[^,]#,)${3}(|,*) ]] 
-  return
+  return 0
 fi
 
 return 1
diff --git a/Completion/Core/_tags b/Completion/Core/_tags
index 7b1254325..5ed56df6e 100644
--- a/Completion/Core/_tags
+++ b/Completion/Core/_tags
@@ -1,84 +1,85 @@
 #autoload
 
+# We use the funcstack names to communicate to neighboring functions.
+
 local tname="$funcstack[2,-1]"
 
 if (( $# )); then
-  local cmd="$words[1]" defs i ttags tag pat style prio context opt
 
-  while getopts 'c:C:' opt; do
-    if [[ "$opt" = c ]]; then
-      cmd="$OPTARG"
-    else
-      context="$OPTARG"
-    fi
-  done
-  shift OPTIND-1
+  # We have arguments: the tags supported in this context.
+
+  local command="${_tag_context:-${words[1]}}" _tags contexts name
+
+  # We are given the `-c command-name' option.
+
+  if [[ "$1" = -c?* ]]; then
+    command="${1[3,-1]}"
+    shift
+  elif [[ "$1" = -c ]]; then
+    command="$2"
+    shift 2
+  fi
+
+  [[ "$1" = -(|-) ]] && shift
+
+  # Get the context names.
 
-  [[ -n "$context" ]] && context="/$context"
+  if [[ -n "$_sub_context" ]]; then
+    contexts="${1}:${_sub_context}"
+  else
+    contexts="${1}"
+  fi
+  contexts=":${command},${${contexts//::/:}//:/:${command},}:"
+  shift
 
-  defs=( "${(@M)argv:#${(kj:|:)~override_tags[(R)(|+*)]}}" )
-  (( $#defs )) && set -- "$defs[@]"
+  _tags=()
+
+  # Remember offered tags.
 
   _offered_tags=( "$_offered_tags[@]" "$@" )
   _last_tags=()
 
-  defs=()
-  for i; do
-    if [[ -n ${override_tags[$i]} && ${override_tags[$i]} != (\[|+\[)* ]]; then
-      if [[ ${override_tags[$i]} = *\[* ]]; then
-        prio=( "${i}:*=${override_tags[$i]#+}" )
-      else
-        prio=( "${i}:${(@v)^comptags[(I)(|*:)${i}(|:*)]}" )
-        (( $#prio )) || prio=( "${i}:${comptags[any]}" )
-        prio="${${${prio[(r)(|*:)\*=[^:]#\[*\](|:*)]}##(|*:)\*}%%:*}"
-        prio=( "${i}:*=${override_tags[$i]#+}${(M)prio%%\[*\]}" )
-      fi
-    else
-      prio=( "${i}:${(@v)^comptags[(I)(|*:)${i}(|:*)]}" )
-      (( $#prio )) || prio=( "${i}:${comptags[any]}" )
-    fi
-    defs=( "$defs[@]" "$prio[@]" )
-  done
-
-  ttags=()
-  for i in "$defs[@]"; do
-    tag="${i%%:*}"
-    for pat in "${(s.:.)i#*:}"; do
-      if [[ "$cmd$context" = ${~pat%%\=*} ]]; then
-        prio="${pat#*\=}"
-	[[ "$prio" = -* ]] && continue 2
-
-	if [[ "$prio" = *\[*\] ]]; then
-	  style="${(M)prio%%\[*}"
-	  prio="${prio%%\[*}"
-        else
-	  style=''
-        fi
-	[[ ${override_tags[$tag]} = (|+)\[* ]] &&
-	    style="${override_tags[$tag]#+}"
-
-	(( prio++ ))
-
-        ttags[$prio]="${ttags[$prio]}:${tag}${style}"
-        break
-      fi
-    done
-  done
-
-  prio="_prio_arr$(( _prio_num++ ))"
-  _prio_names[$tname]="$prio"
-  ttags=( "${(@)ttags:#}" )
-  eval "${prio}=( \"\$ttags[@]\" )"
-
-  return \!$#ttags
+  # Call the function that sorts the tags into sets.
+
+  "${_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"
+
+  # Return non-zero if at least one set of tags should be used.
+
+  return \!$#_tags
 fi
 
+# The other mode: switch to the next set of tags.
+
 local prios="$_prio_names[$tname]"
 
+# Reset the current context.
+
+_cur_contexts="${_tag_contexts[$tname]}"
+
 _failed_tags=( "$_failed_tags[@]" "$_last_tags" )
 
+# Return failure if no sets remaining.
+
 (( ${(P)#prios} )) || return 1
 
+# Otherwise get the next tags.
+
 _cur_tags[$tname]="${(@)${(@P)prios}[1]}:"
 
 _last_tags=( "${(@)${(@s.:.)${(@P)prios}[1]}:#}" )
diff --git a/Completion/Core/_unset_options b/Completion/Core/_unset_options
index f6a1c58f0..0c7b91b7a 100644
--- a/Completion/Core/_unset_options
+++ b/Completion/Core/_unset_options
@@ -6,5 +6,7 @@
 
 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
diff --git a/Completion/Core/compinit b/Completion/Core/compinit
index 1b88cc8f0..0f614f322 100644
--- a/Completion/Core/compinit
+++ b/Completion/Core/compinit
@@ -108,13 +108,9 @@ fi
   compconfig[correct_prompt]='correct to:'
 (( ${+compconfig[completer]} )) || compconfig[completer]=_complete
 
-# This holds the tag/priority definitions.
+# This holds the style definitions.
 
-typeset -gA comptags
-
-(( ${+comptags[any]} )) || comptags[any]='*=100'
-
-typeset -gA override_tags
+typeset -gA _compstyles
 
 # This can hold names of functions that are to be called after all
 # matches have been generated.
@@ -378,243 +374,65 @@ compconf() {
   fi
 }
 
-# Function to set tags and priorities.
-
-comptag() {
-  local i opt list tag val
-
-  while getopts "lL" opt; do
-    if [[ "$opt" = l ]]; then
-      [[ -z "$list" ]] && list=yes
-    else
-      list=long
-    fi
-  done
-  shift OPTIND-1
-
-  if (( $# )); then
-    if [[ -n $list ]]; then
-      for i; do
-        if [[ $list = long ]]; then
-	  (( ${+comptags[$i]} )) && print "comptag $i='$comptags[$i]'"
-	else
-          print $comptags[$i]
-	fi
-      done
-    else
-      for i; do
-        tag="${i%%([-+]|)\=*}"
-	val="${${i#*(|[-+])\=}#+}"
-        case "$i" in
-	*+\=*)
-	  if [[ -n "$comptags[$tag]" ]]; then
-	    comptags[$tag]="${val}:${comptags[$tag]}"
-	  else
-	    comptags[$tag]="$val"
-          fi
-	  ;;
-	*\=+*)
-	  if [[ -n "$comptags[$tag]" ]]; then
-	    comptags[$tag]="${comptags[$tag]}:${val}"
-	  else
-	    comptags[$tag]="$val"
-          fi
-	  ;;
-	*-\=*)
-	  if [[ -n "$comptags[$tag]" ]]; then
-	    comptags[$tag]="${${${comptags[$tag]//:${val}\=[^:]##}#${val}\=*:}%:${val}\=[^:]##}"
-	    [[ "$comptags[$tag]" = ${val}\=* ]] && unset "comptags[$tag]"
-          fi
-          ;;
-        *\=*)
-          comptags[${i%%\=*}]="${i#*\=}"
-	  ;;
-        *)
-          unset "compconfig[$i]"
-	  ;;
-        esac
-      done
-    fi
-  else
-    for i in ${(ok)comptags}; do
-      if [[ $list = long ]]; then
-	print "comptag $i='$comptags[$i]'"
-      else
-        print ${(r:25:)i} "$comptags[$i]"
-      fi
-    done
-  fi
-}
-
-# First suggested function for new configuration interface.
+# Very simple interface for setting styles:
 #
-# Example:
+#   compstyle context -styles... context -styles ...
 #
-#   conf1 \
-#     argument = 1 \
-#     value    = 1 with describe \
-#     option   = 2 with describe and hide \
-#     file     = 3 \
-#     path in   '*dvi*' = 1 \
-#          else         = 2 \
-#     glob     = 1 \
-#     job      = never
-
-conf1() {
-  local tag pat prio
-
-  while (( $# )); do
+# Where context is of the form cmd-pat:ctxt-pat:tag-pat.
+#
+# This will be improved if needed. Promised.
 
-    tag="$1"
-    shift
+compstyle() {
+  if (( ! $# )); then
+    local pat
 
-    while (( $# )); do
+    for pat in "${(@k)_compstyles}"; do
+      print -- "${(r:20:: :)pat} -- ${_compstyles[$pat]#??}"
+    done
 
-      if [[ "$1" = in ]]; then
-        pat="$2"
-	shift 2
-      else
-        pat='*'
-	[[ "$1" = else ]] && shift
-      fi
+    return 0
+  fi
 
-      style=''
+  local sep pat test
+  typeset -Z 2 num
 
-      if [[ "$1" = is ]]; then
-        prio=0
-	style="[${2}]"
-	shift 2
-      elif [[ "$1" = \= ]]; then
-        if [[ "$2" = n(o|ever) ]]; then
-          prio=-1
-	  shift 2
-        else
-          prio="$2"
-	  shift 2
-
-	  if [[ "$1" = with ]]; then
-	    while [[ "$1" = (with|and) ]]; do
-	      style="${style},${2}"
-	      shift 2
-            done
-            style="[${style[2,-1]}]"
-          fi
-        fi
-      else
-        echo "$0: missing priority: $1"
-	return 1
-      fi
-      if [[ -n "$comptags[$tag]" ]]; then
-        comptags[$tag]="${comptags[$tag]}:${pat}=${prio}${style}"
-      else
-        comptags[$tag]="${pat}=${prio}${style}"
+  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
-
-      [[ "$1" = (in|else|\=) ]] || break
-
     done
-  done
 
-  return 0
-}
+    pat="$1"
+    shift
 
-# Second suggested function for new configuration interface.
-#
-# Example:
-#
-#   conf2 \
-#     for '*dvi*' do \
-#       glob and path or \
-#       file \
-#     else do \
-#       glob or \
-#       path or \
-#       file \
-#     for '*p[bgpn]m*' do \
-#       argument and option with describe and with hide \
-#     else do \
-#       argument or \
-#       value with describe or \
-#       option with describe \
-#     for 'kill' do \
-#       no job but \
-#       process \
-#     else do \
-#       process and job
-
-conf2() {
-  local pat prio tag style
+    sep=$argv[(I)[^-]*]
 
-  while (( $# )); do
-
-    if [[ "$1" = for ]]; then
-      pat="$2"
-      shift 2
-    elif [[ "$1" = (else|always) ]]; then
-      pat="*"
-      shift
+    if (( sep )); then
+      _compstyles[$pat]="${num}${(j.:.)${(@)argv[1,sep-1]#-}}"
+      shift sep-1
     else
-      echo "$0: missing context: $1"
-      return 1
+      _compstyles[$pat]="${num}${(j.:.)${(@)argv#-}}"
+      break
     fi
+  done
 
-    shift 1
-
-    prio=1
-
-    while (( $# )); do
-
-      if [[ "$1" = no ]]; then
-        while [[ "$1" != (but|for|else|always) ]]; do
-	  if [[ -n "$comptags[$2]" ]]; then
-	    comptags[$2]="${comptags[$2]}:${pat}=-1"
-          else
-	    comptags[$2]="${pat}=-1"
-	  fi
-
-	  shift 2
-	done
-
-	[[ "$1" != but ]] && break
-
-	shift
-      fi
-
-      while (( $# )); do
-
-        tag="$1"
-	shift
-
-	style=''
-	if [[ "$1" = with ]]; then
-	  shift
-	  while true; do
-	    style="${style},${1}"
-	    [[ "$2" != and || "$3" != with ]] && break
-	    shift 3
-          done
-	  shift
-        fi
-
-	[[ -n "$style" ]] && style="[${style[2,-1]}]"
-
-	if [[ -n "$comptags[$tag]" ]]; then
-	  comptags[$tag]="${comptags[$tag]}:${pat}=${prio}${style}"
-        else
-	  comptags[$tag]="${pat}=${prio}${style}"
-        fi
+  return 0
+}
 
-	[[ "$1" != and ]] && break
+# Default styles.
 
-	shift
-      done
+compstyle '*,*,*' -description=yes -prefix-needed=yes -prefix-hidden=no
 
-      [[ "$1" != or ]] && break
+# Helper function for `_tags'. Will be moved into C-code.
 
-      (( prio++ ))
-      shift
-    done
-  done
+comptry() {
+  _tags=( "$_tags[@]" ":${(j.:.)argv}:" )
 }
 
 # Utility function to call a function if it exists.
diff --git a/Completion/Linux/_rpm b/Completion/Linux/_rpm
index 5b59f1d2b..15f154db9 100644
--- a/Completion/Linux/_rpm
+++ b/Completion/Linux/_rpm
@@ -43,7 +43,7 @@ local ret=1 tmp expl
 
 # Used by `_arguments', made local here.
 
-local state lstate line
+local context state lstate line
 typeset -A opt_args
 
 state=''
@@ -187,13 +187,19 @@ 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
     ;;
   package_file)
     if compset -P ftp://; then
+      _tags "$context" hosts || return 1
+
       _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'
@@ -202,6 +208,8 @@ while [[ -n "$state" ]]; do
     ;;
   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
@@ -219,6 +227,8 @@ while [[ -n "$state" ]]; do
       _description expl 'old path'
     fi
 
+    _tags "$context" directories || return 1
+
     _files "$expl[@]" -/ && ret=0
     ;;
   esac
diff --git a/Completion/User/_archie b/Completion/User/_archie
index 1e0eb71be..640fbc4ed 100644
--- a/Completion/User/_archie
+++ b/Completion/User/_archie
@@ -1,6 +1,6 @@
 #compdef archie
 
-local state line
+local context state line expl
 typeset -A opt_args
 
 _arguments -s \
@@ -25,6 +25,10 @@ _arguments -s \
 case "$state" in
 serverhost)
   : ${(A)archie_servers:=${(M)$(archie -L):#archie.*}}
-  compadd $archie_servers
+
+  _tags "${context}:server" hosts || return 1
+
+  _description expl 'archie servers'
+  compadd "$expl[@]" -  $archie_servers
   ;;
 esac
diff --git a/Completion/User/_flex b/Completion/User/_flex
index ef998c3cf..5d5d55f7a 100644
--- a/Completion/User/_flex
+++ b/Completion/User/_flex
@@ -1,6 +1,6 @@
 #compdef flex
 
-local state line ret=1
+local context state line ret=1
 typeset -A opt_args
 
 _arguments -s \
diff --git a/Completion/User/_gcc b/Completion/User/_gcc
index 2fa29df8c..88f70ad52 100644
--- a/Completion/User/_gcc
+++ b/Completion/User/_gcc
@@ -1,6 +1,6 @@
 #compdef gcc
 
-local state line ret=1 expl args
+local context state line ret=1 expl args
 typeset -A opt_args
 
 args=()
@@ -273,6 +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
   ;;
diff --git a/Completion/User/_gprof b/Completion/User/_gprof
index 211a7a15f..cbc362331 100644
--- a/Completion/User/_gprof
+++ b/Completion/User/_gprof
@@ -1,6 +1,6 @@
 #compdef gprof
 
-local state line ret=1
+local context 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} \
@@ -17,6 +17,8 @@ _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
+
   [[ "$state" = pair ]] && pair=yes
 
   if [[ $#line -gt 1 ]]; then
@@ -46,7 +48,7 @@ if [[ -n "$state" ]]; then
     else
       _description expl function
     fi
-    compadd -M 'r:|_=* r:|=*' - "$_gprof_funcs[@]" && ret=0
+    compadd "$expl[@]" -M 'r:|_=* r:|=*' - "$_gprof_funcs[@]" && ret=0
   else
     return 1
   fi
diff --git a/Completion/User/_groups b/Completion/User/_groups
index b867634c0..bc955a8d2 100644
--- a/Completion/User/_groups
+++ b/Completion/User/_groups
@@ -2,6 +2,8 @@
 
 local expl
 
+_tags any groups || return 1
+
 if (( ! $+groups )); then
   if whence -p ypcat > /dev/null; then
     : ${(A)groups:=${${(s: :)$(ypcat group.byname)}%%:*}} # If you use NIS
diff --git a/Completion/User/_gs b/Completion/User/_gs
index 55dc4f8f7..0c9c11e10 100644
--- a/Completion/User/_gs
+++ b/Completion/User/_gs
@@ -8,7 +8,7 @@ if compset -N --; then
     return 1
   fi
 else
-  local state line ret=1
+  local context state line ret=1
   typeset -A opt_args
 
   _x_arguments \
@@ -25,6 +25,8 @@ 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 \
@@ -35,10 +37,14 @@ else
     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
         ;;
       *OutputFile\=)
+        _tags "$context" files || return 1
+
         _description expl 'output file'
         _files && ret=0
         ;;
@@ -47,6 +53,8 @@ else
         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
     fi
diff --git a/Completion/User/_hosts b/Completion/User/_hosts
index 00150f9b7..d577c83ab 100644
--- a/Completion/User/_hosts
+++ b/Completion/User/_hosts
@@ -2,6 +2,8 @@
 
 local expl
 
+_tags any hosts || return 1
+
 : ${(A)hosts:=${(s: :)${(ps:\t:)${${(f)"$(</etc/hosts)"}%%\#*}##[:blank:]#[^[:blank:]]#}}}
 
 _description expl host
diff --git a/Completion/User/_lynx b/Completion/User/_lynx
index eaf5a6603..8399c4735 100644
--- a/Completion/User/_lynx
+++ b/Completion/User/_lynx
@@ -1,6 +1,6 @@
 #compdef lynx
 
-local state line
+local context state line
 typeset -A opt_args
 
 _arguments \
diff --git a/Completion/User/_mount b/Completion/User/_mount
index 579f24381..39e31ee35 100644
--- a/Completion/User/_mount
+++ b/Completion/User/_mount
@@ -5,7 +5,7 @@
 # arguments for the `mount' command for different operating systems
 # are below these table.
 
-local state line ret=1 args fss deffs=iso9660 descr tmp
+local context state line ret=1 args fss deffs=iso9660 descr tmp
 typeset -A opt_args
 
 if (( ! $+_fs_any )); then
@@ -228,11 +228,15 @@ 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
   ;;
 fsopt)
+  _tags "$context" options || return 1
+
   eval 'tmp=(' '"$_fs_'${(s:,:)^${opt_args[-t]:-${deffs}}}'[@]"' ')'
   tmp=( "$_fs_any[@]" "${(@)tmp:#}" )
   _values -s , 'file system options' "$tmp[@]" && ret=0
@@ -241,25 +245,24 @@ devordir)
   if (( $+opt_args[-a] )); then
     _message "no device or directory with option \`-a'"
   else
-    _description expl device
-    compadd "$expl[@]" /dev/* && ret=0
-    if (( ! $+opt_args[-t] )); then
-      _description expl 'mount point'
-      _files "$expl[@]" -/ && ret=0
-    fi
+    _alternative "$context" \
+        'devices:device:compadd /dev/\*' \
+	'directories:mount point:_files -/' && ret=0
   fi
   ;;
 udevordir)
   if (( $+opt_args[-a] )); then
     _message "no device or directory with option \`-a'"
   else
+    local dev_tmp mp_tmp
+
     tmp=( "${(@f)$(< /etc/mtab)}" )
-    _description expl device
-    compadd "$expl[@]" - "${(@)${(@)tmp%% *}:#none}" && ret=0
-    if (( ! $+opt_args[-t] )); then
-      _description expl 'mount point'
-      compadd "$expl[@]" - "${(@)${(@)tmp#* }%% *}"
-    fi
+    dev_tmp=( "${(@)${(@)tmp%% *}:#none}" )
+    mp_tmp=( "${(@)${(@)tmp#* }%% *}" )
+
+    _alternative "$context" \
+        'devices:device:compadd - $dev_tmp[@]' \
+	'directories:mount point:compadd - $mp_tmp[@]' && ret=0
   fi
   ;;
 esac
diff --git a/Completion/User/_mutt b/Completion/User/_mutt
index 1339c32b0..16b1b0c6d 100644
--- a/Completion/User/_mutt
+++ b/Completion/User/_mutt
@@ -1,6 +1,6 @@
 #compdef mutt
 
-local state line muttrc="~/.muttrc" ret=1
+local context state line muttrc="~/.muttrc" ret=1
 
  _arguments \
  '::recipient:->userhost' \
@@ -25,15 +25,16 @@ local state line muttrc="~/.muttrc" ret=1
  '-Z+:open first mailbox with new mail:' && ret=0
 
 if [[ "$state" = userhost ]]; then
-      if compset -P '*@'; then
-        _description expl 'remote host name'
-        _hosts "$expl[@]" -q -S,
-        return
-      else
-          _description expl 'login name'
-          _users "$expl[@]" -q -S@ && ret=0
-        fi
-      fi
+  _tags "$context" hosts || return 1
 
-return ret
+  if compset -P '*@'; then
+    _description expl 'remote host name'
+    _hosts "$expl[@]" -q -S, && return 0
+  else
+    _description expl 'login name'
+    _users "$expl[@]" -q -S@ && return 0
+   fi
+ fi
 fi
+
+return ret
diff --git a/Completion/User/_netscape b/Completion/User/_netscape
index 11f583dd5..3caaad05e 100644
--- a/Completion/User/_netscape
+++ b/Completion/User/_netscape
@@ -1,6 +1,6 @@
 #compdef netscape
 
-local state line
+local context state line ret=1
 typeset -A opt_args
 
 _x_arguments \
@@ -22,56 +22,75 @@ _x_arguments \
   -{,no-}{,irix-}session-management \
   -{done-save,ignore}-geometry-prefs \
   -{component-bar,composer,edit,messenger,mail,discussions,news} \
-  '*:location:->urls'
+  '*:location:->urls' && ret=0
+
+[[ "$state" = "urls" ]] &&
+  _tags "$context" files && _files "$@" && return 0
 
-[ "$state" = "urls" ] && _files "$@" && return
 
 # Handle netscape remote commands
-if [ "$state" = "remote" ]; then  
+if [[ "$state" = "remote" ]]; then  
   local -a remote_commands
   remote_commands=(openURL openFile saveAs mailto addBookmark)
 
   [[ $compstate[quoting] = (double|single) ]] && compset -q
   compset -P '*\('
   case $IPREFIX in
-    openURL*|addBookmark* ) state=urls;;
-    openFile* ) _files -W ~;;
-    saveAs* ) 
+    openURL*|addBookmark*) state=urls;;
+    openFile*) _files -W ~;;
+    saveAs*) 
       if compset -P "*,"; then
-        compadd -s")" -M 'm:{a-zA-Z}={A-Za-z}' HTML Text PostScript
+        if _tags "$context" types; then
+          _description expl 'data type'
+          compadd -s")" -M 'm:{a-zA-Z}={A-Za-z}' HTML Text PostScript &&
+              ret=0
+        fi
       else
-        _path_files -W ~
+        _tags "$context" files && _path_files -W ~ && ret=0
       fi
     ;;
-    mailto* )
+    mailto*)
       compset -P "*,"
       if compset -P '*@'; then
-        _description expl 'remote host name'
-        _hosts "$expl[@]" -q -S,
+        if _tags "$context" hosts; then
+          _description expl 'remote host name'
+          _hosts "$expl[@]" -q -S, && ret=0
+        fi
       else
-        _description expl 'login name'
-        _users "$expl[@]" -q -S@
+        if _tags "$context" users; then
+          _description expl 'login name'
+          _users "$expl[@]" -q -S@ && ret=0
+        fi
       fi
     ;;
-    * )
-      if [ "$QIPREFIX" ]; then
-        compadd -q -S '(' -M 'm:{a-zA-Z}={A-Za-z}' $remote_commands
-      else
-	compadd -s'(' -S '' -M 'm:{a-zA-Z}={A-Za-z}' $remote_commands
+    *)
+      if _tags "$context" commands; then
+        if [[ "$QIPREFIX" ]]; then
+          compadd -q -S '(' -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
+	fi
       fi
     ;;
   esac
 fi
 
-if [ "$state" = "urls" ]; then
+if [[ "$state" = "urls" ]]; then
   # Complete netscape urls
   if [[ -prefix about: ]]; then
-    compset -P about:
-    compadd authors blank cache document fonts global hype image-cache \
-        license logo memory-cache mozilla plugins
+    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
   else
-    _description expl 'URL prefix'
-    compadd "$expl[@]" -S '' about: mocha: javascript:
-    _urls "$@"
+    if _tags "$context" prefixes; then
+      _description expl 'URL prefix'
+      compadd "$expl[@]" -S '' about: mocha: javascript:
+      _urls "$@" && ret=0
+    fi
   fi
 fi
+
+return ret
diff --git a/Completion/User/_nslookup b/Completion/User/_nslookup
index 7bf97a8ad..f3e290505 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 state expl ret=1 setopts
+local context state expl ret=1 setopts
 
 setopts=(
   'all[print current values]' \
@@ -52,6 +52,8 @@ 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
@@ -60,6 +62,8 @@ if [[ -n "$compcontext" ]]; then
 
     funcall ret _nslookup_redirect && return ret
 
+    _tags redirection files || return 1
+
     if [[ "$words[1]" != (finger|ls) ]]; then
       _message "redirection not allowed for command \`$words[1]'"
       return 1
@@ -84,6 +88,8 @@ if [[ -n "$compcontext" ]]; then
 
   case "$words[1]" in
   (|l)server)
+    _tags argument hosts || return 1
+
     _description expl 'new default server'
     _hosts "$expl[@]"
     return
@@ -106,6 +112,8 @@ if [[ -n "$compcontext" ]]; then
     return
     ;;
   view)
+    _tags argument files || return 1
+
     _description expl 'view file'
     _files "$expl[@]"
     return
@@ -118,6 +126,8 @@ if [[ -n "$compcontext" ]]; then
     [[ -z "$state" ]] && return ret
     ;;
   *)
+    _tags argument hosts || return 1
+
     _description expl 'server'
     _hosts "$expl[@]"
     return
@@ -141,6 +151,8 @@ fi
 # This is completion after `srchlist' for both types.
 
 if [[ -n "$state" ]]; then
+  _tags "$context" hosts || return 1
+
   if compset -P '*/'; then
     _description expl 'search list entry'
   else
diff --git a/Completion/User/_pbm b/Completion/User/_pbm
index 77af9b23b..c697ebaa6 100644
--- a/Completion/User/_pbm
+++ b/Completion/User/_pbm
@@ -21,7 +21,7 @@ if [[ $# -ne 0 || $+_in_pbm -ne 0 ]]; then
     _description expl 'picture file'
     set -- "$expl[@]"
   fi
-  _path_files "$@" -g "$pat" || _files "$@" -g '*.(#i)p[bgp]m'
+  _files "$@" -g "$pat" || _files "$@" -g '*.(#i)p[bgp]m'
   return
 fi
 
@@ -775,5 +775,5 @@ zeisstopnm)
 
 *) 
   _description expl 'picture file'
-  _path_files "$expl[@]" -g "$pat" || _files "$expl[@]" -g '*.(#i)p[bgp]m'
+  _files "$expl[@]" -g "$pat" || _files "$expl[@]" -g '*.(#i)p[bgp]m'
 esac
diff --git a/Completion/User/_ports b/Completion/User/_ports
index 950212832..9012dfd5e 100644
--- a/Completion/User/_ports
+++ b/Completion/User/_ports
@@ -2,6 +2,8 @@
 
 local expl
 
+_tags any ports || return 1
+
 : ${(A)ports:=${${(M)${${(f)"$(</etc/services)"}:#\#*}#*/tcp}%%[ 	]*}}
 
 _description expl port
diff --git a/Completion/User/_rlogin b/Completion/User/_rlogin
index aa66b8f01..898f10870 100644
--- a/Completion/User/_rlogin
+++ b/Completion/User/_rlogin
@@ -20,7 +20,7 @@ _rlogin () {
       ':remote host name:_rlogin_hosts'
     ;;
   rsh|remsh)
-    local state line ret=1
+    local context state line ret=1
     typeset -A opt_args
 
     _arguments -s \
@@ -48,13 +48,18 @@ _rlogin () {
 
     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
       else
-	_files && ret=0
-	_rlogin_all_hosts -S: -q && ret=0
-	_rlogin_users -S@ -q && ret=0
+        _alternative "$context" \
+	    'files:: _files' \
+	    'hosts:: _rlogin_all_hosts -qS:' \
+	    'users:: _rlogin_users -qS@' && ret=0
       fi
     fi
     return ret
@@ -63,10 +68,12 @@ _rlogin () {
 }
 
 _rlogin_users () {
-  _combination accounts_users_hosts users "$@"
+  _tags any users && _combination accounts_users_hosts users "$@"
 }
 
 _rlogin_hosts () {
+  _tags any hosts || return 1
+
   if [[ "$IPREFIX" == *@ ]]; then
     _combination accounts_users_hosts "users=${IPREFIX/@}" hosts "$@"
   else
@@ -76,6 +83,8 @@ _rlogin_hosts () {
 }
 
 _rlogin_all_hosts () {
+  _tags any hosts || return 1
+
   _combination accounts_users_hosts hosts "$@"
 }
 
diff --git a/Completion/User/_socket b/Completion/User/_socket
index e43c14c24..ad9232af9 100644
--- a/Completion/User/_socket
+++ b/Completion/User/_socket
@@ -5,13 +5,14 @@
 #  socket_hosts_ports
 #    The array that contains paris `host:port'.
 
-local state line expl
+local context state line expl
 typeset -A opt_args
 
-if [[ $CURRENT -eq 2 && (
-  -z "$compconfig[option_prefix]" ||
-  "$compconfig[option_prefix]" = *\!${words[1]}* ||
-  "$PREFIX" = -* ) ]]; then
+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
@@ -42,9 +43,13 @@ command)
 
 arg1)
   if (( $+opt_args[-s] )); then
+    _tags "$context" ports || return 1
+
     _description expl 'port to listen'
     _ports "$expl[@]"
   else
+    _tags "$context" hosts || return 1
+
     _description expl 'host'
     _combination socket_hosts_ports hosts "$expl[@]"
   fi
@@ -52,6 +57,8 @@ arg1)
 
 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[@]"
   fi
diff --git a/Completion/User/_ssh b/Completion/User/_ssh
index 952b99193..2c71b49a0 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 state lstate line ret=1 expl args
+  local context state lstate line ret=1 expl args tmp
   typeset -A opt_args
 
   local accounts_users_hosts
@@ -58,23 +58,31 @@ _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)*)
-            compadd yes no && ret=0
+	    _tags "$context" values && compadd yes no && ret=0
             ;;
           *(#i)cipher*)
-            _description expl 'encryption cipher'
-            compadd "$expl[@]" idea des 3des blowfish arcfour tss none && ret=0
+	    if _tags "$context" values; then
+              _description expl 'encryption cipher'
+              compadd "$expl[@]" idea des 3des blowfish arcfour tss none && ret=0
+	    fi
             ;;
           *(#i)globalknownhostsfile*)
-            _description expl 'global file with known hosts'
-            _files "$expl[@]" && ret=0
+	    if _tags "$context" files; then
+              _description expl 'global file with known hosts'
+              _files "$expl[@]" && ret=0
+	    fi
             ;;
           *(#i)hostname*)
-            _description expl 'real host name to log into'
-            _ssh_hosts "$expl[@]" && ret=0
+	    if _tags "$context" hosts; then
+              _description expl 'real host name to log into'
+              _ssh_hosts "$expl[@]" && ret=0
+	    fi
             ;;
           *(#i)identityfile*)
-            _description expl 'SSH identity file'
-            _files "$expl[@]" && ret=0
+	    if _tags "$context" files; then
+              _description expl 'SSH identity file'
+              _files "$expl[@]" && ret=0
+	    fi
             ;;
           *(#i)(local|remote)forward*)
             state=forward
@@ -86,36 +94,44 @@ _ssh () {
             _normal && ret=0
             ;;
           *(#i)stricthostkeychecking*)
-            compadd yes no ask
+            _tags "$context" values && compadd yes no ask
             ;;
           *(#i)userknownhostsfile*)
-            _description expl 'user file with known hosts'
-            _files "$expl[@]" && ret=0
+	    if _tags "$context" files; then
+              _description expl 'user file with known hosts'
+              _files "$expl[@]" && ret=0
+	    fi
             ;;
           *(#i)user*)
-            _description expl 'user to log in as'
-            _ssh_users "$expl[@]" && ret=0
+	    if _tags "$context" files; then
+              _description expl 'user to log in as'
+              _ssh_users "$expl[@]" && ret=0
+	    fi
             ;;
           *(#i)xauthlocation*)
-            _description expl 'xauth program'
-            _files "$expl[@]" -g '*(*)' && ret=0
+	    if _tags "$context" files; then
+              _description expl 'xauth program'
+              _files "$expl[@]" -g '*(*)' && ret=0
+	    fi
             ;;
           esac
         else
-          _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
+          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
         fi
         ;;
       forward)
@@ -123,7 +139,7 @@ _ssh () {
           if compset -P '*:'; then
             _message 'port number'
           else
-            _ssh_hosts -S: -q
+	    _tags "$context" hosts && _ssh_hosts -S: -q
           fi
         else
           _message 'listen-port number'
@@ -138,15 +154,19 @@ _ssh () {
         ;;
       userhost)
         if compset -P '*@'; then
-          _description expl 'remote host name'
-          _ssh_hosts "$expl[@]" && ret=0
+	  if _tags "$context" hosts; then
+            _description expl 'remote host name'
+            _ssh_hosts "$expl[@]" && ret=0
+	  fi
         else
-          _description expl 'remote host name'
-          _ssh_hosts "$expl[@]" && ret=0
-          if (( ! $+opt_args[-l] )); then
-            _description expl 'login name'
-            _ssh_users "$expl[@]" -S@ -q && ret=0
-          fi
+          if (( $+opt_args[-l] )); then
+	    tmp=()
+	  else
+	    tmp=( 'users:login name:_ssh_users -qS@' )
+	  fi
+	  _alternative "$context" \
+	      'hosts:remote host name:_ssh_hosts' \
+	      "$tmp[@]" && ret=0
         fi
         ;;
       esac
@@ -178,13 +198,14 @@ _ssh () {
       return
     elif [[ -n "$state" ]]; then
       if compset -P '*:'; then
-        _files && ret=0
+        _tags "$context" files && _files && ret=0
       elif compset -P '*@'; then
-        _ssh_hosts -S: && ret=0
+        _tags "$context" hosts && _ssh_hosts -S: && ret=0
       else
-        _files && ret=0
-        _ssh_hosts -S: && ret=0
-        _ssh_users -S@ && ret=0
+        _alternative "$context" \
+	    'files:: _files' \
+	    'hosts:: _ssh_hosts -S:' \
+	    'users:: _ssh_users -S@' && ret=0
       fi
     fi
     return ret
@@ -222,10 +243,12 @@ _ssh () {
 }
 
 _ssh_users () {
-  _combination accounts_users_hosts users "$@"
+  _tags any 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/_telnet b/Completion/User/_telnet
index b1c628d11..04c9fe69f 100644
--- a/Completion/User/_telnet
+++ b/Completion/User/_telnet
@@ -5,9 +5,9 @@
 #  telnet_hosts_ports_users
 #    The array that contains 3-tuples `host:port:user'.
 
-local state line expl
+local context state line expl
 typeset -A opt_args
-
+set -x
 if (( ! $+_telnet_short )); then
   local k help="$(telnet -\? < /dev/null 2>&1)"
   local -A optionmap
@@ -52,13 +52,11 @@ if (( ! $+_telnet_short )); then
   done
 fi
 
-[[ $#_telnet_long != 0 && (
-     -z "$compconfig[option_prefix]" ||
-     "$compconfig[option_prefix]" = *\!${words[1]}* ||
-     "$PREFIX" = [-+]* ) ]] && {
+if _tags any options && (( $#_telnet_long )) &&
+   { ! _style options prefix-needed yes || [[ "$PREFIX" = [-+]* ]] } ; then
   _description expl 'option'
   _describe -o option _telnet_long "$expl[@]"
-}
+fi
 
 _arguments -s \
   "$_telnet_short[@]" \
@@ -67,6 +65,8 @@ _arguments -s \
 
 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}} \
@@ -74,6 +74,8 @@ hosts)
   ;;
 
 ports)
+  _tags "$context" ports || return 1
+
   _description expl 'port'
   _combination telnet_hosts_ports_users \
     ${opt_args[-l]:+users=${opt_args[-l]:q}} \
@@ -82,6 +84,8 @@ ports)
   ;;
 
 users)
+  _tags "$context" users || return 1
+
   _description expl 'user'
   _combination telnet_hosts_ports_users \
     ${line[2]:+hosts="${line[2]:q}"} \
diff --git a/Completion/User/_tiff b/Completion/User/_tiff
index e02ce6455..e3a023c24 100644
--- a/Completion/User/_tiff
+++ b/Completion/User/_tiff
@@ -19,7 +19,7 @@ fi
 
 local _in_tiff=yes
 
-local state line ret=1
+local context state line ret=1
 typeset -A opt_args
 
 case "$words[1]" in
@@ -194,6 +194,8 @@ 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
diff --git a/Completion/User/_urls b/Completion/User/_urls
index 21d3deaa6..8c0c6f8d8 100644
--- a/Completion/User/_urls
+++ b/Completion/User/_urls
@@ -45,12 +45,13 @@ local localhttp_userdir="${${(@s.:.)compconfig[urls_localhttp]}[3]}"
 
 if [[ "$1" = -f ]]; then
   shift
-  _files "$@" && return
+  _tags argument:-f files && _files "$@" && return
 fi
 
 ipre="$IPREFIX"
 
-if ! compset -P '(#b)([-+.a-z0-9]#):'; then
+if ! compset -P '(#b)([-+.a-z0-9]#):' &&
+   _tags argument prefixes; then
   _description expl 'URL prefix'
   [[ -d $urls_path/bookmark ]] &&
     compadd "$@" "$expl[@]" -S '' bookmark: && ret=0
@@ -62,12 +63,14 @@ scheme="$match[1]"
 case "$scheme" in
   http|ftp|gopher)
     if ! compset -P //; then
-      compadd "$@" -S '' //
+      _tags "$scheme" slashes && compadd "$@" -S '' //
       return
     fi
   ;;
   file)
     if ! compset -P //; then
+      _tags file files || return 1
+
       if [[ -prefix / ]]; then
 	_path_files "$@" -S '' -g '*(^/)' && ret=0
 	_path_files "$@" -S/ -r '/' -/ && ret=0
@@ -81,8 +84,12 @@ case "$scheme" in
   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
     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
@@ -92,7 +99,8 @@ case "$scheme" in
 esac
 
 # Complete hosts
-if ! compset -P '(#b)([^/]#)/'; then
+if ! compset -P '(#b)([^/]#)/' &&
+   _tags argument hosts; then
   uhosts=($urls_path/$scheme/$PREFIX*$SUFFIX(/:t))
   (( $#uhosts )) || _hosts -S/ && ret=0
   [[ "$scheme" = http ]] && uhosts=($uhosts $localhttp_servername)
@@ -103,6 +111,9 @@ fi
 host="$match[1]"
 
 # Complete part after hostname
+
+_tags local files || return 1
+
 if [[ "$localhttp_servername" = "$host" ]]; then
   if compset -P \~; then
     if ! compset -P '(#b)([^/]#)/'; then
diff --git a/Completion/User/_user_at_host b/Completion/User/_user_at_host
index 6006ef63b..c33a024d9 100644
--- a/Completion/User/_user_at_host
+++ b/Completion/User/_user_at_host
@@ -1,15 +1,17 @@
 #autoload
 
-local expl nm="$compstate[nmatches]"
-
 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[@]" "$@"
 fi
-
-[[ nm -ne compstate[nmatches] ]]
diff --git a/Completion/User/_users b/Completion/User/_users
index 6d0b1ce2f..9f2751c11 100644
--- a/Completion/User/_users
+++ b/Completion/User/_users
@@ -5,6 +5,8 @@
 
 local expl
 
+_tags any users || return 1
+
 _description expl user
 
 [[ "${(t)users}" = *array* ]] &&
diff --git a/Completion/User/_users_on b/Completion/User/_users_on
index 7a1ecd864..221ebb0fd 100644
--- a/Completion/User/_users_on
+++ b/Completion/User/_users_on
@@ -2,6 +2,8 @@
 
 local expl
 
+_tags any users || return 1
+
 if which users >/dev/null; then
   _description expl 'users logged on'
   compadd "$@" "$expl[@]" - $(users) && return 0
diff --git a/Completion/User/_wget b/Completion/User/_wget
index c9b671194..3a15d3867 100644
--- a/Completion/User/_wget
+++ b/Completion/User/_wget
@@ -1,6 +1,6 @@
 #compdef wget
 
-local state line
+local context state line
 typeset -A opt_args
 
 local tmp1 tmp2
diff --git a/Completion/User/_whois b/Completion/User/_whois
index 2043cbd4e..1e0f7707c 100644
--- a/Completion/User/_whois
+++ b/Completion/User/_whois
@@ -112,7 +112,7 @@ _whois_setup () {
 }
 
 _whois_single () {
-  local state line expl
+  local context state line expl
   typeset -A opt_args
   local tmp host
 
@@ -189,19 +189,25 @@ _whois_fwhois () {
 }
 
 _whois_hosts () {
-  compadd "$@" \
-    -M 'm:{a-zA-Z}={A-Za-z} r:|.=* r:|=*' \
-    - ${_whois_servers%:?} || _hosts "$@"
+  _tags any hosts &&
+    compadd "$@" \
+      -M 'm:{a-zA-Z}={A-Za-z} r:|.=* r:|=*' \
+      - ${_whois_servers%:?} || _hosts "$@"
 }
 
 _whois_ports () {
-  compadd "$@" - whois || _ports "$@"
+  _tags any ports && compadd "$@" - whois || _ports "$@"
 }
 
 (( $+functions[_whois:whois.internic.net] )) ||
 _whois:whois.internic.net () {
   if (( CURRENT == 1 )); then
-    compadd HELP DOMAIN HOST
+    local expl
+
+    _tags any string || return 1
+
+    _description expl string
+    compadd "$expl[@]" HELP DOMAIN HOST
   else
     _message 'string'
   fi
@@ -210,6 +216,11 @@ _whois:whois.internic.net () {
 (( $+functions[_whois:whois.nic.ad.jp] )) ||
 _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
   else
     _message 'string'
diff --git a/Completion/User/_yp b/Completion/User/_yp
index e06f42a29..d0876f6dd 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 line state ret=1
+local context line state ret=1
 typeset -A opt_args
 
 if (( ! $+_yp_cache_maps )); then
@@ -87,20 +87,31 @@ esac
 if [[ "$state" = map* ]]; then
   local expl
 
-  _description expl 'map name'
-
-  # The `-M ...' allows `pa.n<TAB>' to complete to `passwd.byname'.
-
-  compadd "$expl[@]" -M 'l:.|by=by l:.|=by r:|.=* r:|=*' - \
-          "$_yp_cache_maps[@]" && ret=0
   if [[ $+opt_args[-t] -eq 0 && "$state" != maponly ]]; then
-    _description expl 'nicknames'
-    compadd "$expl[@]" - "$_yp_cache_nicks[@]" && ret=0
+    _tags "$context" maps nicknames
+  else
+    _tags "$context" 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
+  done
 elif [[ "$state" = servers ]]; then
   if compset -P '*,'; then
-    _description expl 'server'
-    _hosts -qS, && ret=0
+    if _tags "$context" hosts; then
+      _description expl 'server'
+      _hosts -qS, && ret=0
+    fi
   else
     _message 'domain name'
   fi
diff --git a/Completion/X/_x_color b/Completion/X/_x_color
index 0cbcdf0eb..4c1c73bf4 100644
--- a/Completion/X/_x_color
+++ b/Completion/X/_x_color
@@ -29,6 +29,8 @@ 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[@]"
diff --git a/Completion/X/_x_cursor b/Completion/X/_x_cursor
index 59ecb5976..a22189f9d 100644
--- a/Completion/X/_x_cursor
+++ b/Completion/X/_x_cursor
@@ -14,5 +14,7 @@ if (( ! $+_cursor_cache )); then
   fi
 fi
 
+_tags any cursors || return 1
+
 _description expl 'cursor name'
 compadd "$@" "$expl[@]" -M 'm:-=_ r:|_=*' - "$_cursor_cache[@]"
diff --git a/Completion/X/_x_display b/Completion/X/_x_display
index e3f9af479..7b9fbab9a 100644
--- a/Completion/X/_x_display
+++ b/Completion/X/_x_display
@@ -1,3 +1,5 @@
 #autoload
 
+_tags any displays || return 1
+
 _hosts -S ':0 ' -r :
diff --git a/Completion/X/_x_extension b/Completion/X/_x_extension
index 967938e28..44e47d956 100644
--- a/Completion/X/_x_extension
+++ b/Completion/X/_x_extension
@@ -2,6 +2,8 @@
 
 local expl
 
+_tags any 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'
diff --git a/Completion/X/_x_font b/Completion/X/_x_font
index 4ba21ddff..f4dfef79c 100644
--- a/Completion/X/_x_font
+++ b/Completion/X/_x_font
@@ -2,6 +2,8 @@
 
 local expl
 
+_tags any fonts || return 1
+
 # This *has* to be improved some day...
 
 if (( ! $+_font_cache )); then
diff --git a/Completion/X/_x_keysym b/Completion/X/_x_keysym
index 6b031014a..fc2847c57 100644
--- a/Completion/X/_x_keysym
+++ b/Completion/X/_x_keysym
@@ -2,6 +2,8 @@
 
 local expl
 
+_tags any keysyms || return 1
+
 if (( ! $+_keysym_cache )); then
   local file
 
diff --git a/Completion/X/_x_modifier b/Completion/X/_x_modifier
index a9276ab71..345243835 100644
--- a/Completion/X/_x_modifier
+++ b/Completion/X/_x_modifier
@@ -2,6 +2,8 @@
 
 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
diff --git a/Completion/X/_x_window b/Completion/X/_x_window
index 65d2b72e2..6d6e3112e 100644
--- a/Completion/X/_x_window
+++ b/Completion/X/_x_window
@@ -2,6 +2,8 @@
 
 local list expl
 
+_tags any windows || return 1
+
 list=( "${(@)${(M@)${(@f)$(xwininfo -root -tree)}:#[ 	]#0x[0-9a-f]# \"*}##[ 	]#}" )
 
 if [[ "$1" = -n ]]; then
diff --git a/Completion/X/_xmodmap b/Completion/X/_xmodmap
index 4e7a8bfc8..d8ba420ce 100644
--- a/Completion/X/_xmodmap
+++ b/Completion/X/_xmodmap
@@ -1,6 +1,6 @@
 #compdef xmodmap
 
-local state line ret=1
+local context state line ret=1
 typeset -A opt_args
 
 _x_arguments \
@@ -82,9 +82,11 @@ if [[ -n "$state" ]]; then
     [[ "$what" = *ksym* ]] && _x_keysym "$suf[@]" && ret=0
 
   else
-    _description expl command
-    compadd "$expl[@]" -S ' ' keycode keysym clear add remove && ret=0
-    compadd "$expl[@]" -S ' = ' pointer && ret=0
+    if _tags any commands; then
+      _description expl command
+      compadd "$expl[@]" -S ' ' keycode keysym clear add remove && ret=0
+      compadd "$expl[@]" -S ' = ' pointer && ret=0
+    fi
   fi
 fi