about summary refs log tree commit diff
path: root/Completion/Base
diff options
context:
space:
mode:
Diffstat (limited to 'Completion/Base')
-rw-r--r--Completion/Base/_arguments388
-rw-r--r--Completion/Base/_brace_parameter3
-rw-r--r--Completion/Base/_command_names11
-rw-r--r--Completion/Base/_condition5
-rw-r--r--Completion/Base/_equal7
-rw-r--r--Completion/Base/_long_options79
-rw-r--r--Completion/Base/_math11
-rw-r--r--Completion/Base/_parameter6
-rw-r--r--Completion/Base/_subscript13
-rw-r--r--Completion/Base/_tilde14
-rw-r--r--Completion/Base/_vars9
11 files changed, 492 insertions, 54 deletions
diff --git a/Completion/Base/_arguments b/Completion/Base/_arguments
new file mode 100644
index 000000000..5170acb84
--- /dev/null
+++ b/Completion/Base/_arguments
@@ -0,0 +1,388 @@
+#autoload
+
+# Complete the arguments of the current command according to the
+# descriptions given as arguments to this function.
+
+local long args rest ws cur nth def nm expl descr action opt arg tmp
+
+# Associative arrays used to collect information about the options.
+
+typeset -A opts mopts dopts dmopts odopts odmopts
+
+# See if we support long options, too.
+
+nth=$argv[(I)--]
+if (( nth )); then
+  long=( "${(@)argv[nth+1,-1]}" )
+  argv=("${(@)argv[1,nth-1]}")
+else
+  long=()
+fi
+
+# Now parse the arguments...
+
+args=()
+nth=1
+while (( $# )); do
+
+  # This describes a one-shot option.
+
+  if [[ "$1" = [-+]* ]]; then
+    if [[ "$1" = *:* ]]; then
+
+      # If the option name ends in a `-', the first argument comes
+      # directly after the option, if it ends in a `+', the first
+      # argument *may* come directly after the option, otherwise it
+      # is in the next word.
+
+      if [[ "$1" = [^:]##-:* ]]; then
+        dopts[${${1%%:*}[1,-2]}]="${1#*:}"
+      elif [[ "$1" = [^:]##+:* ]]; then
+        odopts[${${1%%:*}[1,-2]}]="${1#*:}"
+      else
+        opts[${1%%:*}]="${1#*:}"
+      fi
+    else
+      opts[$1]=''
+    fi
+  elif [[ "$1" = \*[-+]* ]]; then
+
+    # The same for options that may appear more than once.
+
+    if [[ "$1" = *:* ]]; then
+      if [[ "$1" = [^:]##-:* ]]; then
+        dmopts[${${1[2,-1]%%:*}[1,-2]}]="${1#*:}"
+      elif [[ "$1" = [^:]##+:* ]]; then
+        odmopts[${${1[2,-1]%%:*}[1,-2]}]="${1#*:}"
+      else
+        mopts[${1[2,-1]%%:*}]="${1#*:}"
+      fi
+    else
+      mopts[${1[2,-1]}]=''
+    fi
+  elif [[ "$1" = \*:* ]]; then
+
+    # This is `*:...', describing `all other arguments'.
+
+    rest="${1[3,-1]}"
+  elif [[ "$1" = :* ]]; then
+
+    # This is `:...', describing `the next argument'.
+
+    args[nth++]="${1#*:}"
+  else
+
+    # And this is `n:...', describing the `n'th argument.
+
+    args[${1%%:*}]="${1#*:}"
+    nth=$(( ${1%%:*} + 1 ))
+  fi
+  shift
+done
+
+if [[ $#long -ne 0 && "$PREFIX" = --* ]]; then
+
+   # If the current words starts with `--' and we should use long
+   # options, just call...
+
+  _long_options "$long[@]"
+else
+
+  # Otherwise parse the command line...
+
+  ws=( "${(@)words[2,-1]}" )
+  cur=$(( CURRENT-2 ))
+  nth=1
+
+  # ...until the current word is reached.
+
+  while [[ cur -gt 0 ]]; do
+
+    # `def' holds the description for the option we are currently after.
+    # Check if the next argument for the option is optional.
+
+    if [[ "$def" = :* ]]; then
+      opt=yes
+    else
+      opt=''
+    fi
+    arg=''
+
+    # Remove one description/action pair from `def' if that isn't empty.
+
+    if [[ -n "$def" ]]; then
+      if [[ "$def" = ?*:*:* ]]; then
+        def="${def#?*:*:}"
+      else
+        def=''
+      fi
+    else
+
+      # If it is empty, and the word starts with `--' and we should
+      # complete long options, just ignore this word, otherwise make sure
+      # we test for options below and handle normal arguments.
+
+      if [[ $#long -eq 0 || "$ws[1]" != --* ]]; then
+        opt=yes
+	arg=yes
+      else
+        def=''
+      fi
+    fi
+
+    if [[ -n "$opt" ]]; then
+
+      # `opt' was set above if we have to test if the word is an option.
+      # We first test for the simple options -- those without arguments or
+      # those whose arguments have to be given as separate words.
+
+      if (( $+opts[$ws[1]] )); then
+
+        # Options that may only be given once are removed from the
+        # associative array so that we are not offered them again.
+
+        def="$opts[$ws[1]]"
+        unset "opts[$ws[1]]"
+      elif (( $+mopts[$ws[1]] )); then
+        def="$mopts[$ws[1]]"
+      else
+
+        # If the word is none of the simple options, test for those
+        # whose first argument has to or may come directly after the
+        # option. This is done in four loops looking very much alike.
+
+        if (( $#dopts )); then
+
+	  # First we get the option names.
+
+	  tmp=( "${(@k)dopts}" )
+
+	  # Then we loop over them and see if the current word begins
+	  # with one of the option names.
+
+	  while (( $#tmp )); do
+	    [[ "$ws[1]" = ${tmp[1]}* ]] && break
+	    shift 1 tmp
+	  done
+
+	  if (( $#tmp )); then
+
+	    # It does. So use the description for it, but only from
+	    # the second argument on, because we are searching the
+	    # description for the next command line argument.
+
+	    opt=''
+	    def="$dopts[$tmp[1]]"
+	    unset "dopts[$tmp[1]]"
+	    if [[ "$def" = ?*:*:* ]]; then
+              def="${def#?*:*:}"
+            else
+              def=''
+	    fi
+          fi
+        fi
+	if [[ -n "$opt" && $#dmopts -ne 0 ]]; then
+	  tmp=( "${(@k)dmopts}" )
+	  while (( $#tmp )); do
+	    [[ "$ws[1]" = ${tmp[1]}* ]] && break
+	    shift 1 tmp
+	  done
+
+	  if (( $#tmp )); then
+	    opt=''
+	    def="$dmopts[$tmp[1]]"
+	    if [[ "$def" = ?*:*:* ]]; then
+              def="${def#?*:*:}"
+            else
+              def=''
+            fi
+          fi
+	fi
+        if [[ -n "$opt" && $#odopts -ne 0 ]]; then
+	  tmp=( "${(@k)odopts}" )
+	  while (( $#tmp )); do
+	    [[ "$ws[1]" = ${tmp[1]}* ]] && break
+	    shift 1 tmp
+	  done
+
+	  if (( $#tmp )); then
+	    opt=''
+	    def="$odopts[$tmp[1]]"
+	    unset "odopts[$tmp[1]]"
+
+	    # For options whose first argument *may* come after the
+	    # option, we skip over the first description only if there
+	    # is something after the option name on the line.
+
+	    if [[ "$ws[1]" != "$tmp[1]" ]]; then
+	      if [[ "$def" = ?*:*:* ]]; then
+                def="${def#?*:*:}"
+              else
+                def=''
+              fi
+	    fi
+          fi
+        fi
+	if [[ -n "$opt" && $#odmopts -ne 0 ]]; then
+	  tmp=( "${(@k)odmopts}" )
+	  while (( $#tmp )); do
+	    [[ "$ws[1]" = ${tmp[1]}* ]] && break
+	    shift 1 tmp
+	  done
+
+	  if (( $#tmp )); then
+	    opt=''
+	    def="$odmopts[$tmp[1]]"
+	    if [[ "$ws[1]" != "$tmp[1]" ]]; then
+	      if [[ "$def" = ?*:*:* ]]; then
+                def="${def#?*:*:}"
+              else
+                def=''
+              fi
+            fi
+          fi
+	fi
+
+	# If we didn't find a matching option description and we were
+	# told to use normal argument descriptions, just increase
+	# our counter `nth'.
+
+        if [[ -n "$opt" && -n "$arg" ]]; then
+          def=''
+	  (( nth++ ))
+        fi
+      fi
+    fi
+
+    shift 1 ws
+    (( cur-- ))
+  done
+
+  # Now generate the matches.
+
+  nm="$compstate[nmatches]"
+
+  if [[ -z "$def" || "$def" = :* ]]; then
+
+    # We either don't have a description for an argument of an option
+    # or we have a description for a optional argument.
+
+    if [[ -z "$def" ]]; then
+
+      # If we have none at all, use the one for this argument position.
+
+      def="$args[nth]"
+      [[ -z "$def" ]] && def="$rest"
+    fi
+
+    # In any case, we have to complete option names here, but we may
+    # be in a string that starts with an option names and continues with
+    # the first argument, test that (again, four loops).
+
+    opt=yes
+    if (( $#dopts )); then
+
+      # Get the option names.
+
+      tmp=( "${(@k)dopts}" )
+      while (( $#tmp )); do
+        if compset -P "$tmp[1]"; then
+
+	  # The current string starts with the option name, so ignore
+	  # that and complete the rest of the string.
+
+	  def="$dopts[$tmp[1]]"
+	  opt=''
+	  break
+        fi
+	shift 1 tmp
+      done
+    fi
+    if [[ -n "$opt" && $#dmopts -ne 0 ]]; then
+      tmp=( "${(@k)dmopts}" )
+      while (( $#tmp )); do
+        if compset -P "$tmp[1]"; then
+	  def="$dmopts[$tmp[1]]"
+	  opt=''
+	  break
+        fi
+	shift 1 tmp
+      done
+    fi
+    if [[ -n "$opt" && $#odopts -ne 0 ]]; then
+      tmp=( "${(@k)odopts}" )
+      while (( $#tmp )); do
+        if compset -P "$tmp[1]"; then
+	  def="$odopts[$tmp[1]]"
+	  opt=''
+	  break
+        fi
+	shift 1 tmp
+      done
+    fi
+    if [[ -n "$opt" && $#odmopts -ne 0 ]]; then
+      tmp=( "${(@k)odmopts}" )
+      while (( $#tmp )); do
+        if compset -P "$tmp[1]"; then
+	  def="$odmopts[$tmp[1]]"
+	  opt=''
+	  break
+        fi
+	shift 1 tmp
+      done
+    fi
+    if [[ -n "$opt" ]]; then
+
+      # We aren't in an argument directly after a option name, so
+      # all option names are possible matches.
+
+      _description expl option
+      compadd "$expl[@]" - "${(@k)opts}" "${(@k)mopts}" \
+                           "${(@k)dopts}" "${(@k)dmopts}" \
+			   "${(@k)odopts}" "${(@k)odmopts}"
+    fi
+  fi
+
+  # Now add the matches from the description, if any.
+
+  if [[ -n "$def" ]]; then
+
+    # Ignore the leading colon describing optional arguments.
+
+    [[ "$def" = :* ]] && def="$def[2,-1]"
+
+    # Get the description and the action.
+
+    descr="${def%%:*}"
+    action="${${def#*:}%%:*}"
+
+    _description expl "$descr"
+
+    if [[ -z "$action" ]]; then
+
+      # An empty action means that we should just display a message.
+      _message "$descr"
+      return 1
+    elif [[ "$action[1]" = \( ]]; then
+
+      # Anything inside `(...)' is added directly.
+
+      compadd "$expl[@]" - ${=action[2,-2]}
+    elif [[ "$action" = \ * ]]; then
+
+      # If the action starts with a space, we just call it.
+
+      $=action
+    else
+
+      # Otherwise we call it with the description-arguments built above.
+
+      action=( $=action )
+      "$action[1]" "$expl[@]" "${(@)action[2,-1]}"
+    fi
+  fi
+
+  # Set the return value.
+
+  [[  nm -ne "$compstate[nmatches]" ]]
+fi
diff --git a/Completion/Base/_brace_parameter b/Completion/Base/_brace_parameter
index 9dfe46bd6..767743281 100644
--- a/Completion/Base/_brace_parameter
+++ b/Completion/Base/_brace_parameter
@@ -7,7 +7,8 @@ local lp ls n q suf=''
 if [[ "$SUFFIX" = *\}* ]]; then
   ISUFFIX="${SUFFIX#*\}}$ISUFFIX"
   SUFFIX="${SUFFIX%%\}*}"
-elif [[ "$LBUFFER" = *\$\{[^}]#\$\{[^}]#$PREFIX ]]; then
+elif [[ "$LBUFFER" = *\$\{[^}]#\$\{[^}]#$PREFIX ||
+        "$compstate[insert]" = *menu* ]]; then
   suf='}'
 else
   suf='} '
diff --git a/Completion/Base/_command_names b/Completion/Base/_command_names
index 61fea56dd..a0ec90262 100644
--- a/Completion/Base/_command_names
+++ b/Completion/Base/_command_names
@@ -1,18 +1,21 @@
 #compdef -command-
 
-local nm=$compstate[nmatches] ret=1
+local nm=$compstate[nmatches] ret=1 expl
 
 
 # Complete jobs in implicit fg and bg
 if [[ "$PREFIX[1]" = "%" ]]; then
-  compgen -j -P '%'
+  _description expl job
+  compgen "$expl[@]" -j -P '%'
   [[ nm -ne compstate[nmatches] ]] && return
 fi
 
-compgen -c && ret=0
+_description expl command
+compgen "$expl[@]" -c && ret=0
 
 if [[ nm -eq compstate[nmatches] ]]; then
-  _path_files -/g "*(*)"
+  _description expl 'executable file or directory'
+  _path_files "$expl[@]" -/g "*(*)"
 else
   return ret
 fi
diff --git a/Completion/Base/_condition b/Completion/Base/_condition
index c617d9d90..afac03195 100644
--- a/Completion/Base/_condition
+++ b/Completion/Base/_condition
@@ -7,10 +7,11 @@ if [[ "$prev" = -o ]]; then
 elif [[ "$prev" = -([no]t|ef) ]]; then
   _files
 else
-  local ret=1
+  local ret=1 expl
 
   _files && ret=0
-  compgen -v && ret=0
+  _description expl parameter
+  compgen "$expl[@]" -v && ret=0
 
   return ret
 fi
diff --git a/Completion/Base/_equal b/Completion/Base/_equal
index 0e2a11e46..14f28703c 100644
--- a/Completion/Base/_equal
+++ b/Completion/Base/_equal
@@ -1,3 +1,8 @@
 #compdef -equal-
 
-compgen -am
+local expl
+
+_description expl alias
+compgen "$expl[@]" -a
+_description expl command
+compgen "$expl[@]" -m
diff --git a/Completion/Base/_long_options b/Completion/Base/_long_options
index a50edee1c..f82de9ed5 100644
--- a/Completion/Base/_long_options
+++ b/Completion/Base/_long_options
@@ -9,9 +9,11 @@
 # For options that get an argument after a `=', the function also tries
 # to automatically find out what should be completed as the argument.
 # The possible completions for option-arguments can be described with
-# the arguments to this function. This is done by giving pairs of
-# patterns and actions as consecutive arguments. The actions specify
-# what should be done to complete arguments of those options that match 
+# the arguments to this function. Each argument contains one description
+# of the form <pattern>:<message>:<action>. The message will be printed 
+# above the possible completion if the `description_format' configuration
+# key is set (see the `_main_complete' file). The actions specify what
+# should be done to complete arguments of those options that match 
 # the pattern. The action may be a list of words in brackets or in
 # parentheses, separated by spaces. A list in brackets denotes
 # possible values for an optional argument, a list in parentheses
@@ -20,9 +22,9 @@
 # command (probably with arguments) that should be invoked to complete 
 # after the equal sign. E.g.:
 #
-#  _long_options '*\*'     '(yes no)' \
-#                '*=FILE*' '_files' \
-#                '*=DIR*'  '_files -/'
+#  _long_options '*\*:toggle:(yes no)' \
+#                '*=FILE*:file:_files' \
+#                '*=DIR*:directory:_files -/'
 #
 # This makes `yes' and `no' be completed as the argument of options
 # whose description ends in a star, file names for options that
@@ -46,23 +48,18 @@
 #      E.g. configure often lists only --enable but accepts both
 #      --enable and --disable options.
 #      _long_options -s '(#--enable- --disable)' will accept both forms.
-#
-# This function also accepts the `-X', `-J', and `-V' options which
-# are given to `compadd'. 
 
-local opt expl group test i name action ret=1 tmp suffix iopts sopts
+local opt test i name action descr expl ret=1 tmp suffix iopts sopts
 
 setopt extendedglob
 
 # Get the options.
 
-group=()
 expl=()
+
 if [[ $1 = -*~--* ]]; then
-  while getopts "J:V:X:ti:s:" opt; do
+  while getopts "ti:s:" opt; do
     case "$opt" in
-      [JV]) group=("-$opt" "$OPTARG");;
-      X)    expl=(-X "$OPTARG");;
       t)    test=yes;;
       i)    if [[ "$OPTARG[1]" = '(' ]]; then
               iopts=( ${=OPTARG[2,-2]} )
@@ -99,7 +96,7 @@ if [[ "$tmp" != $_lo_cache_cmd ]]; then
   # No, store the new command name and clear the old parameters.
 
   _lo_cache_cmd="$tmp"
-  (( $+_lo_cache_actions )) && unset "$_lo_cache_names[@]" _lo_cache_actions _lo_cache_names
+  (( $+_lo_cache_actions )) && unset "$_lo_cache_names[@]" _lo_cache_actions _lo_cache_names _lo_cache_descr
 
   local opts pattern anum=1 tmpo str
   typeset -U opts
@@ -136,16 +133,17 @@ if [[ "$tmp" != $_lo_cache_cmd ]]; then
   # use the positional parameters we were given and a few standard
   # ones. Then we loop through this table.
 
-  set -- "$@" '*=FILE*' '_files' '*=(DIR|PATH)*' '_files -/' '*' ''
+  set -- "$@" '*=FILE*:file:_files' '*=(DIR|PATH)*:directory:_files -/' '*:unknown:'
 
   while [[ $# -gt 1 ]]; do
 
     # First, we get the pattern and the action to use and take them
     # from the positional parameters.
 
-    pattern="$1"
-    action="$2"
-    shift 2
+    pattern="${1%%:*}"
+    descr="${${1#*:}%%:*}"
+    action="${1#*:*:}"
+    shift
 
     # We get all options matching the pattern and take them from the
     # list we have built. If no option matches the pattern, we
@@ -188,6 +186,7 @@ if [[ "$tmp" != $_lo_cache_cmd ]]; then
         tmpo=("${(@)${(@)tmpo%%\=*}//[^a-z0-9-]}")
         _lo_cache_names[anum]="_lo_cache_optarg_$anum"
         _lo_cache_actions[anum]="$action"
+	_lo_cache_descr[anum]="$descr"
         eval "_lo_cache_optarg_${anum}=(\"\$tmpo[@]\")"
 	(( anum++ ))
       fi
@@ -201,6 +200,7 @@ if [[ "$tmp" != $_lo_cache_cmd ]]; then
         tmpo=("${(@)${(@)tmpo%%\=*}//[^a-z0-9-]}")
         _lo_cache_names[anum]="_lo_cache_arg_$anum"
         _lo_cache_actions[anum]="$action"
+	_lo_cache_descr[anum]="$descr"
         eval "_lo_cache_arg_${anum}=(\"\$tmpo[@]\")"
 	(( anum++ ))
       fi
@@ -216,6 +216,7 @@ if [[ "$tmp" != $_lo_cache_cmd ]]; then
     if (( $#tmp )); then
       _lo_cache_names[anum]="$name"
       _lo_cache_actions[anum]="$action"
+      _lo_cache_descr[anum]="$descr"
       eval "${name}=(\"\$tmp[@]\")"
       (( anum++ ))
     fi
@@ -232,7 +233,7 @@ if [[ "$str" = *\=* ]]; then
   # It contains a `=', now we ignore anything up to it, but first save 
   # the old contents of the special parameters we change.
 
-  local oipre opre osuf pre parto parta pat patflags anum=1
+  local oipre opre osuf pre parto parta partd pat patflags anum=1
 
   oipre="$IPREFIX"
   opre="$PREFIX"
@@ -247,14 +248,23 @@ if [[ "$str" = *\=* ]]; then
 
   for name in "$_lo_cache_names[@]"; do
     action="$_lo_cache_actions[anum]"
+    descr="$_lo_cache_descr[anum]"
     if (( ${(@)${(@P)name}[(I)$pre]} )); then
       IPREFIX="${oipre}${pre}="
       PREFIX="${str#*\=}"
       SUFFIX=""
+
+      _description expl "$descr"
+
       if [[ "$action[1]" = (\[|\() ]]; then
-        compadd - ${=action[2,-2]}
+        compadd "$expl[@]" - ${=action[2,-2]}
       elif (( $#action )); then
-        $=action
+        if [[ "$action" = \ * ]]; then
+          $=action
+        else
+	  action=($=action)
+	  $action[1] "$expl[@]" $action[2,-1]
+        fi
       fi
 
       # We found the option string, return.
@@ -276,6 +286,7 @@ if [[ "$str" = *\=* ]]; then
       if [[ -z "$parto" ]]; then
         parto="$tmp[1]"
 	parta="$action"
+	partd="$descr"
       else
         parto=-
       fi
@@ -292,11 +303,17 @@ if [[ "$str" = *\=* ]]; then
     IPREFIX="${oipre}${parto}="
     PREFIX="${str#*\=}"
     SUFFIX=""
+
+    _description expl "$partd"
+
     if (( $#parta )); then
       if [[ "$parta[1]" = (\[|\() ]]; then
-        compadd - ${=parta[2,-2]}
-      else
+        compadd "$expl[@]" - ${=parta[2,-2]}
+      elif [[ "$parta" = \ * ]]; then
         $=parta
+      else
+	action=($=parta)
+	$action[1] "$expl[@]" $action[2,-1]
       fi
     else
       compadd -S '' - "$PREFIX"
@@ -329,15 +346,17 @@ anum=1
 for name in "$_lo_cache_names[@]"; do
   action="$_lo_cache_actions[anum]"
 
+  _description expl option
+
   if [[ "$name" = *_optarg_* ]]; then
-    compadd -M 'r:|-=* r:|=*' -Qq "$suffix[@]" -s "$str" - \
-            "${(@P)name}" && ret=0
+    compadd "$expl[@]" -M 'r:|-=* r:|=*' \
+            -Qq "$suffix[@]" -s "$str" - "${(@P)name}" && ret=0
   elif [[ "$name" = *_arg_* ]]; then
-    compadd -M 'r:|-=* r:|=*' -Q "$suffix[@]" -s "$str" - \
-            "${(@P)name}" && ret=0
+    compadd "$expl[@]" -M 'r:|-=* r:|=*' \
+            -Q "$suffix[@]" -s "$str" - "${(@P)name}" && ret=0
   elif [[ -z "$str" ]]; then
-    compadd -M 'r:|-=* r:|=*' -Q - \
-            "${(@P)name}" && ret=0
+    compadd "$expl[@]" -M 'r:|-=* r:|=*' - \
+            -Q "${(@P)name}" && ret=0
   fi
   (( anum++ ))
 done
diff --git a/Completion/Base/_math b/Completion/Base/_math
index 90a2c5f7b..82b97fe4a 100644
--- a/Completion/Base/_math
+++ b/Completion/Base/_math
@@ -1,5 +1,7 @@
 #compdef -math-
 
+local expl
+
 if [[ "$PREFIX" = *[^a-zA-Z0-9_]* ]]; then
   IPREFIX="$IPREFIX${PREFIX%%[a-zA-Z0-9_]#}"
   PREFIX="${PREFIX##*[^a-zA-Z0-9_]}"
@@ -9,10 +11,5 @@ if [[ "$SUFFIX" = *[^a-zA-Z0-9_]* ]]; then
   SUFFIX="${SUFFIX%%[^a-zA-Z0-9_]*}"
 fi
 
-compgen -v
-#compdef -math-
-
-IPREFIX="$IPREFIX${PREFIX%[a-zA-Z0-9_]*}"
-PREFIX="${PREFIX##*[^a-zA-Z0-9_]}"
-
-compgen -v
+_description expl parameter
+compgen "$expl[@]" -v
diff --git a/Completion/Base/_parameter b/Completion/Base/_parameter
index b235a5fee..5f6f56db2 100644
--- a/Completion/Base/_parameter
+++ b/Completion/Base/_parameter
@@ -1,3 +1,7 @@
 #compdef -parameter-
 
-_parameters -S ' ' -r '['
+if [[ "$compstate[insert]" = *menu* ]]; then
+  _parameters
+else
+  _parameters -S ' ' -r '['
+fi
diff --git a/Completion/Base/_subscript b/Completion/Base/_subscript
index be5f08f62..090a5f07a 100644
--- a/Completion/Base/_subscript
+++ b/Completion/Base/_subscript
@@ -1,17 +1,22 @@
 #compdef -subscript-
 
+local expl
+
 if [[ "$PREFIX" = :* ]]; then
+  _description expl 'character class'
   compadd -p: -S ':]' alnum alpha blank cntrl digit graph lower print punct \
       space upper xdigit
 elif [[ ${(Pt)${compstate[parameter]}} = assoc* ]]; then
+  _description expl 'association key'
   if [[ "$RBUFFER" = \]* ]]; then
-    compadd -S '' - "${(@kP)${compstate[parameter]}}"
+    compadd "$expl[@]" -S '' - "${(@kP)${compstate[parameter]}}"
   else
-    compadd -S ']' - "${(@kP)${compstate[parameter]}}"
+    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
@@ -21,9 +26,9 @@ elif [[ ${(Pt)${compstate[parameter]}} = array* ]]; then
   done
 
   if [[ "$RBUFFER" = \]* ]]; then
-    compadd -S '' -V default -y list - "$ind[@]"
+    compadd "$expl[@]" -S '' -V default -y list - "$ind[@]"
   else
-    compadd -S ']' -V default -y list - "$ind[@]"
+    compadd "$expl[@]" -S ']' -V default -y list - "$ind[@]"
   fi
 else
   _compalso -math-
diff --git a/Completion/Base/_tilde b/Completion/Base/_tilde
index d03030821..f249d4ffa 100644
--- a/Completion/Base/_tilde
+++ b/Completion/Base/_tilde
@@ -7,7 +7,7 @@
 #   `(( compstate[nmatches] )) || compgen -nu -qS/'
 # below that.
 
-local c s dirs list
+local d c s dirs list
 
 if [[ "$SUFFIX" = */* ]]; then
   ISUFFIX="/${SUFFIX#*/}$ISUFFIX"
@@ -24,6 +24,8 @@ if compset -P +; then
   				        printf("%s\t%s\n", $1, $2); }' <<<$dirs)"
   list=("${(@)list%	*}")
   c=(-y '$dirs' -k "($list)")
+
+  _description d 'directory stack'
 elif compset -P -; then
   dirs="$(dirs -v)"
   list=("${(f)dirs}")
@@ -31,8 +33,16 @@ elif compset -P -; then
 					  printf("%s\t%s\n", $1, $2); }' <<<$dirs)"
   list=("${(@)list%	*}")
   c=(-y '$dirs' -k "($list)")
+
+  _description d 'directory stack'
 else
   c=(-nu)
+
+  if (( $# )); then
+    d=( "$@" )
+  else
+    _description d user
+  fi
 fi
 
-compgen "$c[@]" "$s[@]"
+compgen "$d[@]" "$c[@]" "$s[@]"
diff --git a/Completion/Base/_vars b/Completion/Base/_vars
index a40df7699..5a06488a5 100644
--- a/Completion/Base/_vars
+++ b/Completion/Base/_vars
@@ -4,17 +4,22 @@
 # `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%\]}"
   local addclose
+
   compset -p $(( ${#var} + 1 ))
   if ! compset -S \]; then
     addclose=(-S ']')
   fi
   if [[ ${(tP)var} = assoc* ]]; then
-    compadd $addclose - ${(kP)var}
+    _description expl 'association key'
+    compadd "$expl[@]" $addclose - ${(kP)var}
   fi
 else
-  compgen -v
+  _description expl parameter
+  compgen "$expl[@]" -v
 fi