about summary refs log tree commit diff
diff options
context:
space:
mode:
-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
-rw-r--r--Doc/Zsh/compsys.yo20
-rw-r--r--Src/Zle/computil.c64
93 files changed, 940 insertions, 743 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
 
diff --git a/Doc/Zsh/compsys.yo b/Doc/Zsh/compsys.yo
index e30586238..ed19df233 100644
--- a/Doc/Zsh/compsys.yo
+++ b/Doc/Zsh/compsys.yo
@@ -878,14 +878,14 @@ that implement a state machine. In this case, the `var(string)' (with
 all leading and trailing spaces and tabs removed) will be stored in
 the global parameter tt(state) and the function returns with a return
 value of 300 (to make it distinguishable from other return values)
-after setting the global `tt(line)' and `tt(opt_args)'
+after setting the global `tt(context)', `tt(line)' and `tt(opt_args)'
 parameters as described below and without resetting any changes made
 to the special parameters such as tt(PREFIX) and tt(words). Note that
 this means that a function calling tt(_arguments) with at least one
 action containing such a `tt(->)var(string)' has to declare
 appropriate local parameters as in:
 
-example(local state line
+example(local context state line
 typeset -A opt_args)
 
 This will ensure that tt(_arguments) does not create unused global
@@ -921,7 +921,12 @@ and their arguments. These are stored in the associative array
 `tt(opt_args)', using the option names as keys and their arguments as
 the values. For options that have more than one argument these are
 given as one string, separated by colons. All colons in the original
-arguments are preceded with backslashes.
+arguments are preceded with backslashes. The parameter `tt(context)'
+will be set to the automatically created context name. This is either
+a string of the form `var(-opt)tt(-)var(n)' for the var(n)'th argument 
+of the option var(-opt), or a string of the form `tt(argument-)var(n)' 
+for the var(n)'th argument (for rest arguments the var(n) is the
+string `tt(rest)').
 
 Normally the option names are taken as multi-character names and a
 word from the line is considered to contain only one option (or
@@ -1073,12 +1078,15 @@ One last difference is that this function uses the associative array
 tt(val_args) to report values and their arguments (but otherwise this
 is the same as the tt(opt_args) association used by
 tt(_arguments)). This also means that the function calling tt(_values) 
-should declare the tt(state) and tt(val_args) parameters as in:
+should declare the tt(state), tt(line), tt(context) and tt(val_args)
+parameters as in:
 
-example(local state line
+example(local context state line
 typeset -A val_args)
 
-when using an action of the form `tt(->)var(string)'.
+when using an action of the form `tt(->)var(string)'. With this
+function the tt(context) parameter will be set to the name of the
+value whose argument is to be completed.
 )
 item(tt(_regex_arguments))(
 This function is a compiler to generate a completion function.  The
diff --git a/Src/Zle/computil.c b/Src/Zle/computil.c
index 22a8f7656..b5b09e732 100644
--- a/Src/Zle/computil.c
+++ b/Src/Zle/computil.c
@@ -357,6 +357,7 @@ struct caarg {
     char *action;
     int type;
     char *end;
+    char *opt;
     int num;
 };
 
@@ -395,6 +396,7 @@ free_caargs(Caarg a)
 	zsfree(a->descr);
 	zsfree(a->action);
 	zsfree(a->end);
+	zsfree(a->opt);
 	zfree(a, sizeof(*a));
     }
 }
@@ -442,7 +444,7 @@ rembslashcolon(char *s)
 }
 
 static Caarg
-parse_caarg(int mult, int type, int num, char **def)
+parse_caarg(int mult, int type, int num, char *oname, char **def)
 {
     Caarg ret = (Caarg) zalloc(sizeof(*ret));
     char *p = *def, *d, sav;
@@ -451,6 +453,7 @@ parse_caarg(int mult, int type, int num, char **def)
     ret->descr = ret->action = ret->end = NULL;
     ret->num = num;
     ret->type = type;
+    ret->opt = ztrdup(oname);
 
     for (d = p; *p && *p != ':'; p++)
 	if (*p == '\\' && p[1])
@@ -647,7 +650,7 @@ parse_cadef(char *nam, char **args)
 	    }
 	    if (c == ':') {
 		Caarg *oargp = &oargs;
-		int atype, rest;
+		int atype, rest, oanum = 1;
 		char *end;
 
 		while (c == ':') {
@@ -681,7 +684,7 @@ parse_cadef(char *nam, char **args)
 			rest = 1;
 		    } else
 			atype = CAA_NORMAL;
-		    *oargp = parse_caarg(!rest, atype, 0, &p);
+		    *oargp = parse_caarg(!rest, atype, oanum++, name, &p);
 		    oargp = &((*oargp)->next);
 		    if (rest)
 			break;
@@ -739,7 +742,7 @@ parse_cadef(char *nam, char **args)
 		} else
 		    type = CAA_RARGS;
 	    }
-	    ret->rest = parse_caarg(0, type, -1, &p);
+	    ret->rest = parse_caarg(0, type, -1, NULL, &p);
 	} else {
 	    int type = CAA_NORMAL;
 	    Caarg arg, tmp, pre;
@@ -763,7 +766,7 @@ parse_cadef(char *nam, char **args)
 		type = CAA_OPT;
 		p++;
 	    }
-	    arg = parse_caarg(0, type, anum - 1, &p);
+	    arg = parse_caarg(0, type, anum - 1, NULL, &p);
 
 	    for (tmp = ret->args, pre = NULL;
 		 tmp && tmp->num < anum - 1;
@@ -1191,8 +1194,9 @@ bin_comparguments(char *nam, char **args, char *ops, int func)
     switch (args[0][1]) {
     case 'i': min = 2; max = -1; break;
     case 'D': min = 2; max =  2; break;
+    case 'C': min = 1; max =  1; break;
     case 'O': min = 4; max =  4; break;
-    case 'L': min = 3; max =  3; break;
+    case 'L': min = 3; max =  4; break;
     case 's': min = 1; max =  1; break;
     case 'M': min = 1; max =  1; break;
     case 'a': min = 0; max =  0; break;
@@ -1248,6 +1252,24 @@ bin_comparguments(char *nam, char **args, char *ops, int func)
 	    }
 	    return 1;
 	}
+    case 'C':
+	{
+	    Caarg arg = ca_laststate.def;
+
+	    if (arg) {
+		char buf[20];
+
+		if (arg->num > 0)
+		    sprintf(buf, "%d", arg->num);
+		else
+		    strcpy(buf, "rest");
+
+		setsparam(args[1], (arg->opt ? tricat(arg->opt, "-", buf) :
+				    tricat("argument-", buf, "")));
+		return 0;
+	    }
+	    return 1;
+	}
     case 'O':
 	if (ca_laststate.opt) {
 	    LinkList next = newlinklist();
@@ -1283,8 +1305,8 @@ bin_comparguments(char *nam, char **args, char *ops, int func)
 	    set_list_array(args[4], equal);
 
 	    return 0;
-	} else
-	    return 1;
+	}
+	return 1;
     case 'L':
 	{
 	    Caopt opt = ca_get_opt(ca_laststate.d, args[1], 1, NULL);
@@ -1293,6 +1315,9 @@ bin_comparguments(char *nam, char **args, char *ops, int func)
 		setsparam(args[2], ztrdup(opt->args->descr));
 		setsparam(args[3], ztrdup(opt->args->action));
 
+		if (args[4])
+		    setsparam(args[4], tricat(opt->name, "-1", NULL));
+
 		return 0;
 	    }
 	    return 1;
@@ -1306,8 +1331,8 @@ bin_comparguments(char *nam, char **args, char *ops, int func)
 			      (ca_laststate.ddef->type == CAO_EQUAL ?
 			       "equal" : "next")) : ""));
 	    return 0;
-	} else
-	    return 1;
+	}
+	return 1;
     case 'M':
 	setsparam(args[1], ztrdup(ca_laststate.d->match));
 	return 0;
@@ -1533,7 +1558,7 @@ parse_cvdef(char *nam, char **args)
 		vtype = CVV_OPT;
 	    } else
 		vtype = CVV_ARG;
-	    arg = parse_caarg(0, 0, 0, &p);
+	    arg = parse_caarg(0, 0, 0, name, &p);
 	} else {
 	    vtype = CVV_NOARG;
 	    arg = NULL;
@@ -1758,10 +1783,11 @@ bin_compvalues(char *nam, char **args, char *ops, int func)
     switch (args[0][1]) {
     case 'i': min = 2; max = -1; break;
     case 'D': min = 2; max =  2; break;
+    case 'C': min = 1; max =  1; break;
     case 'V': min = 3; max =  3; break;
     case 's': min = 1; max =  1; break;
     case 'd': min = 1; max =  1; break;
-    case 'L': min = 3; max =  3; break;
+    case 'L': min = 3; max =  4; break;
     case 'v': min = 1; max =  1; break;
     default:
 	zerrnam(nam, "invalid option: %s", args[0], 0);
@@ -1806,6 +1832,17 @@ bin_compvalues(char *nam, char **args, char *ops, int func)
 	    }
 	    return 1;
 	}
+    case 'C':
+	{
+	    Caarg arg = cv_laststate.def;
+
+	    if (arg) {
+		setsparam(args[1], ztrdup(arg->opt));
+
+		return 0;
+	    }
+	    return 1;
+	}
     case 'V':
 	{
 	    LinkList noarg = newlinklist();
@@ -1861,6 +1898,9 @@ bin_compvalues(char *nam, char **args, char *ops, int func)
 		setsparam(args[2], val->arg->descr);
 		setsparam(args[3], val->arg->action);
 
+		if (args[4])
+		    setsparam(args[4], ztrdup(val->name));
+
 		return 0;
 	    }
 	    return 1;