about summary refs log tree commit diff
diff options
context:
space:
mode:
authorTanaka Akira <akr@users.sourceforge.net>1999-09-15 14:35:16 +0000
committerTanaka Akira <akr@users.sourceforge.net>1999-09-15 14:35:16 +0000
commitbc9e764f4e9b95ec4c2a855c4118f6afb994e904 (patch)
treecba20ce3f39ef0f1916ddd3be6a7aa9250e3dc8f
parentdefa4a7fa08ba3b9020a971d189c5ded4e151d5f (diff)
downloadzsh-bc9e764f4e9b95ec4c2a855c4118f6afb994e904.tar.gz
zsh-bc9e764f4e9b95ec4c2a855c4118f6afb994e904.tar.xz
zsh-bc9e764f4e9b95ec4c2a855c4118f6afb994e904.zip
zsh-workers/7844
-rw-r--r--Completion/Base/_arguments73
-rw-r--r--Completion/Base/_describe155
-rw-r--r--Completion/Base/_subscript4
-rw-r--r--Completion/Base/_tilde4
-rw-r--r--Completion/Base/_values41
-rw-r--r--Completion/Builtins/_cd2
-rw-r--r--Completion/Builtins/_kill4
-rw-r--r--Completion/Builtins/_wait2
-rw-r--r--Completion/Core/_approximate15
-rw-r--r--Completion/Core/_expand45
-rw-r--r--Completion/User/_gdb2
-rw-r--r--Doc/Zsh/compsys.yo46
-rw-r--r--Etc/completion-style-guide4
-rw-r--r--Src/Zle/complist.c8
-rw-r--r--Src/Zle/zle_tricky.c35
15 files changed, 327 insertions, 113 deletions
diff --git a/Completion/Base/_arguments b/Completion/Base/_arguments
index a8e272cac..df01ba6a4 100644
--- a/Completion/Base/_arguments
+++ b/Completion/Base/_arguments
@@ -8,7 +8,7 @@ setopt localoptions extendedglob
 local args rest ws cur nth def nm expl descr action opt arg tmp xor
 local single uns ret=1 aret soptseq soptseq1 sopts prefix _line odescr
 local beg optbeg argbeg nargbeg inopt inrest fromrest cmd="$words[1]"
-local matched curopt noargs i
+local matched curopt noargs i tmp1 tmp2 tmp3 suffix
 
 # Associative arrays used to collect information about the options.
 
@@ -793,13 +793,8 @@ while true; do
 
         eval ws\=\( "${action[3,-3]}" \)
 
-	if [[ -n "$compconfig[describe_values]" &&
-              "$compconfig[describe_values]" != *\!${cmd}* ]] &&
-           _display tmp "$ws[@]"; then
-	  compadd "$expl[@]" -M 'r:|[_-]=* r:|=*' -ld tmp - "${(@)ws%%:*}"
-        else
-	  compadd "$expl[@]" - "${(@)ws%%:*}"
-        fi
+        _describe -c "$cmd" "$descr" ws -M 'r:|[_-]=* r:|=*'
+
       elif [[ "$action" = \(*\) ]]; then
 
         # Anything inside `(...)' is added directly.
@@ -837,62 +832,36 @@ while true; do
     if [[ -n "$sopts" && -n "$PREFIX" &&
       "$PREFIX" = [-+]${~soptseq}[$sopts] ]]; then
       if [[ "$PREFIX" = [-+]${~soptseq1} ]]; then
-        if [[ -z "$compconfig[describe_options]" ||
-              "$compconfig[describe_options]" = *\!${cmd}* ]]; then
-          tmp=( "${PREFIX[1]}${(@)^${(@)${(@M)${=:-${(k)opts} ${(k)dopts} ${(k)odopts}}:#[-+]?(|=)}#?}%=}" )
-          compadd "$expl[@]" -Q -M 'r:|[_-]=* r:|=*' -d tmp - \
-                "${PREFIX}${(@k)^opts[(I)${PREFIX[1]}?]#?}" \
-	        "${PREFIX}${(@k)^dopts[(I)${PREFIX[1]}?]#?}" \
-	        "${PREFIX}${(@)^${(@k)odopts[(I)${PREFIX[1]}?(|=)]#?}%=}" && 
-              ret=0
-        elif _display tmp "${(@Mo)odescr:#[-+]?:*}"; then
-          compadd "$expl[@]" -Q -M 'r:|[_-]=* r:|=*' -ld tmp - \
-	          "${PREFIX}${(@)^${(@)${(@Mo)odescr:#[-+]?:*}%%:*}#?}" && ret=0
-        else
-          compadd "$expl[@]" -Q -M 'r:|[_-]=* r:|=*' -d tmp - \
-	          "${PREFIX}${(@)^${(@)${(@Mo)odescr:#[-+]?:*}%%:*}#?}" && ret=0
-        fi
+        tmp1=( "${(@Mo)odescr:#[-+]?:*}" )
+        tmp2=(
+               "${PREFIX}${(@k)^opts[(I)${PREFIX[1]}?]#?}" \
+	       "${PREFIX}${(@k)^dopts[(I)${PREFIX[1]}?]#?}" \
+	       "${PREFIX}${(@)^${(@k)odopts[(I)${PREFIX[1]}?(|=)]#?}%=}"
+        )
+        tmp2=( "${(@o)tmp2}" )
+
+        _describe -o -c "$cmd" option \
+        tmp1 tmp2  -Q -M 'r:|[_-]=* r:|=*'
       else
         # The last option takes an argument in the next word.
 
         compadd "$expl[@]" -Q -M 'r:|[_-]=* r:|=*' - "${PREFIX}" && ret=0
       fi
     else
-      if [[ -n "$compconfig[describe_options]" &&
-            "$compconfig[describe_options]" != *\!${cmd}* ]] &&
-	 _display descr "$odescr[@]"; then
-	ws=( "${(k)opts[@]}" "${(@k)odopts[(I)*[^=]]}" )
-	if (( $#ws )); then
-	  tmp=( "${(@M)descr:#(${(j:|:)~ws}) *}" )
-          compadd "$expl[@]" -Q -M 'r:|[_-]=* r:|=*' -ld tmp - \
-                  "$ws[@]" && ret=0
-	fi
-	if (( $#dopts )); then
-	  tmp=( "${(@M)descr:#(${(kj:|:)~dopts}) *}" )
-          compadd "$expl[@]" -QS '' -M 'r:|[_-]=* r:|=*' -ld tmp - \
-                  "${(@k)dopts}" && ret=0
-        fi
-	if (( ${(@k)#odopts[(I)*=]} )); then
-	  tmp=( "${(@M)descr:#(${(kj:|:)~odopts[(I)*=]}) *}" )
-          compadd "$expl[@]" -QqS= -M 'r:|[_-]=* r:|=*' -ld tmp - \
-                  "${(@k)odopts[(I)*=]%=}" && ret=0
-        fi
-      else
-        compadd "$expl[@]" -Q -M 'r:|[_-]=* r:|=*' - \
-                "${(@k)opts}" "${(@k)odopts[(I)*[^=]]}" && ret=0
-        compadd "$expl[@]" -QqS= -M 'r:|[_-]=* r:|=*' - \
-                "${(@k)odopts[(I)*=]%=}" && ret=0
-        compadd "$expl[@]" -QS '' -M 'r:|[_-]=* r:|=*' - \
-                "${(@k)dopts}" && ret=0
-      fi
+      tmp1=( "${(k)opts[@]}" "${(@k)odopts[(I)*[^=]]}" )
+      tmp1=( "${(@M)odescr:#(${(kj:|:)~tmp1}):*}" )
+      tmp2=( "${(@M)odescr:#(${(kj:|:)~dopts}):*}" )
+      tmp3=( "${(@M)odescr:#(${(kj:|:)~odopts[(I)*=]}):*}" )
+      _describe -o -c "$cmd" option \
+        tmp1 -Q -M 'r:|[_-]=* r:|=*' -- \
+        tmp2 -QS '' -M 'r:|[_-]=* r:|=*' -- \
+        tmp3 -QqS= -M 'r:|[_-]=* r:|=*'
     fi
   fi
 
   if [[ nm -eq compstate[nmatches] && 
         ( -z "$single" ||
           ( $#_args_cache_long -ne 0 && "$PREFIX" = --*=* ) ) ]]; then
-    local suffix
-
     tmp=( "${(@Mk)odopts:#[^:]#\=}" )
     prefix="${PREFIX#*\=}"
     suffix="$SUFFIX"
diff --git a/Completion/Base/_describe b/Completion/Base/_describe
new file mode 100644
index 000000000..e01c77509
--- /dev/null
+++ b/Completion/Base/_describe
@@ -0,0 +1,155 @@
+#autoload
+
+# This can be used to add options or values with descriptions as matches.
+
+setopt localoptions extendedglob
+
+local gdescr isopt cmd opt nsets tmp descr match descrs matches adescr i
+local disps disp expl tmps tmpd tmpmd tmpms name ret=1 showd _nm
+
+cmd="$words[1]"
+
+# Get the options.
+
+while getopts 'oc:' opt; do
+  if [[ "$opt" = o ]]; then
+    isopt=yes
+  else
+    cmd="$OPTARG"
+  fi
+done
+shift OPTIND-1
+
+# Do the tests. `showd' is set if the descriptions should be shown.
+
+if [[ -n "$isopt" ]]; then
+
+  # We take the value to test the number of patches from a non-local
+  # parameter `nm' if that exists and contains only digits. It's a hack.
+
+  if [[ "$nm" = [0-9]## ]]; then
+    _nm="$nm"
+  else
+    _nm=0
+  fi
+  [[ -n "$compconfig[option_prefix]" &&
+     "$compconfig[option_prefix]" != *\!${cmd}* &&
+     "$PREFIX" != [-+]* &&
+     ( "$compconfig[option_prefix]" = *nodefault* ||
+       _nm -ne compstate[nmatches] ) ]] && return 1
+
+  [[ -n "$compconfig[describe_options]" &&
+     "$compconfig[describe_options]" != *\!${cmd}* ]] && showd=yes
+else
+  [[ -n "$compconfig[describe_values]" &&
+     "$compconfig[describe_values]" != *\!${cmd}* ]] && showd=yes
+fi
+
+gdescr="$1"
+shift
+
+# Now interpret the arguments.
+
+nsets=0
+adescr=()
+descrs=()
+matches=()
+while (( $# )); do
+  (( nsets++ ))
+  descr="$1"
+  [[ -n "$showd" ]] && adescr=( "$adescr[@]" "${(@PM)^descr:#*:?*},$nsets" )
+  if [[ "$2" = -* ]]; then
+    match=''
+    shift
+  else
+    match="$2"
+    shift 2
+  fi
+  tmp=$argv[(i)--]
+  if [[ tmp -eq 1 ]]; then
+    opt=()
+  else
+    opt=( "${(@)argv[1,tmp-1]}" )
+  fi
+  if [[ tmp -gt $# ]]; then
+    argv=()
+  else
+    shift tmp
+  fi
+
+  # `descr' and `matches' collect the names of the arrays containing the
+  # possible matches with descriptions and the matches to add.
+  # The options to give to `compadd' are stored in local arrays.
+
+  descrs[nsets]="$descr"
+  matches[nsets]="$match"
+  typeset -a _descr_opts_$nsets
+  eval "_descr_opts_${nsets}=( \"\$opt[@]\" )"
+done
+
+(( nsets )) || return 1
+
+# Build the display strings if needed.
+
+[[ -n "$showd" ]] && _display disps "$adescr[@]"
+_description expl "$gdescr"
+
+# Loop through the array/option sets we have.
+
+i=0
+while [[ ++i -le nsets ]]; do
+  name=_descr_opts_$i
+  [[ -n "$showd" ]] && disp=( "${(@)${(@M)disps:#*,${i}}%,*}" )
+  descr=( "${(@P)descrs[i]}" )
+
+  # We collect the strings to display in `tmpd' (one string per line)
+  # and `tmps' (in columns) and the matches to add in `tmpmd' and `tmpms'.
+
+  tmpd=()
+  tmps=()
+  tmpmd=()
+  tmpms=()
+  if [[ -n "$matches[i]" ]]; then
+    match=( "${(@P)matches[i]}" )
+    while (( $#match )); do
+      if [[ -n "$showd" && "$descr[1]" = *:?* ]]; then
+	tmpd=( "$tmpd[@]" "$disp[1]" )
+        tmpmd=( "$tmpmd[@]" "$match[1]" )
+        shift 1 disp
+      else
+        tmps=( "$tmps[@]" "${descr[1]%%:*}" )
+        tmpms=( "$tmpms[@]" "$match[1]" )
+      fi
+      shift 1 match
+      shift 1 descr
+    done
+  else
+    while (( $#descr )); do
+      if [[ -n "$showd" && "$descr[1]" = *:?* ]]; then
+	tmpd=( "$tmpd[@]" "$disp[1]" )
+        tmpmd=( "$tmpmd[@]" "${descr[1]%%:*}" )
+        shift 1 disp
+      else
+        tmps=( "$tmps[@]" "${descr[1]%%:*}" )
+        tmpms=( "$tmpms[@]" "${descr[1]%%:*}" )
+      fi
+      shift 1 descr
+    done
+  fi
+
+  # See if we should remove the option prefix characters.
+
+  if [[ -n "$isopt" && "$compconfig[option_prefix]" = hide* ]]; then
+    if [[ "$PREFIX" = --* ]]; then
+      tmpd=( "${(@)tmpd#--}" )
+      tmps=( "${(@)tmps#--}" )
+    elif [[ "$PREFIX" = [-+]* ]]; then
+      tmpd=( "${(@)tmpd#[-+]}" )
+      tmps=( "${(@)tmps#[-+]}" )
+    fi
+  fi
+  compadd "${(@P)name}" "$expl[@]" -ld tmpd - "$tmpmd[@]" && ret=0
+  compadd "${(@P)name}" "$expl[@]" -d tmps - "$tmpms[@]" && ret=0
+done
+
+return ret
diff --git a/Completion/Base/_subscript b/Completion/Base/_subscript
index 76644bafb..803893912 100644
--- a/Completion/Base/_subscript
+++ b/Completion/Base/_subscript
@@ -26,9 +26,9 @@ elif [[ ${(Pt)${compstate[parameter]}} = array* ]]; then
   done
 
   if [[ "$RBUFFER" = \]* ]]; then
-    compadd "$expl[@]" -S '' -V default -y list - "$ind[@]"
+    compadd "$expl[@]" -S '' -V default -d list - "$ind[@]"
   else
-    compadd "$expl[@]" -S ']' -V default -y list - "$ind[@]"
+    compadd "$expl[@]" -S ']' -V default -d list - "$ind[@]"
   fi
 else
   _compalso -math-
diff --git a/Completion/Base/_tilde b/Completion/Base/_tilde
index b8d639074..95d342538 100644
--- a/Completion/Base/_tilde
+++ b/Completion/Base/_tilde
@@ -9,7 +9,7 @@
 
 setopt localoptions extendedglob
 
-local d s dirs list
+local d s dirs list lines
 
 if [[ "$SUFFIX" = */* ]]; then
   ISUFFIX="/${SUFFIX#*/}$ISUFFIX"
@@ -36,7 +36,7 @@ if [[ -prefix [-+] ]]; then
 
   compset -P '[-+]'
   _description d 'directory stack'
-  compadd "$d[@]" -d lines -Q - "$list[@]" 
+  compadd "$d[@]" -ld lines -Q - "$list[@]" 
 else
   if (( $# )); then
     d=( "$@" )
diff --git a/Completion/Base/_values b/Completion/Base/_values
index 21f6908cc..5b413313b 100644
--- a/Completion/Base/_values
+++ b/Completion/Base/_values
@@ -3,7 +3,7 @@
 setopt localoptions extendedglob
 
 local name arg def descr xor str tmp ret=1 expl nm="$compstate[nmatches]"
-local snames odescr gdescr sep esep spat
+local snames odescr gdescr sep esep spat tmp1 tmp2 tmp3 opts
 typeset -A names onames xors _values
 
 # Probably fill our cache.
@@ -280,34 +280,21 @@ else
 
   # No `=', just complete value names.
 
-  _description expl "$gdescr"
-
-  [[ -n "$sep" && ${#snames}+${#names}+${#onames} -ne 1 ]] &&
-      expl=( "-qS$sep" "$expl[@]" )
-
-  if [[ -n "$compconfig[describe_values]" &&
-        "$compconfig[describe_values]" != *\!${words[1]}* ]] &&
-     _display descr "$odescr[@]"; then
-    if (( $#snames )); then
-      tmp=( "${(@M)descr:#(${(j:|:)~snames}) *}" )
-      compadd "$expl[@]" -ld tmp -M 'r:|[_-]=* r:|=*' - \
-              "${(@)tmp%% *}" && ret=0
-    fi
-    if (( $#names )); then
-      tmp=( "${(@M)descr:#(${(kj:|:)~names}) *}" )
-      compadd -S= "$expl[@]" -ld tmp -M 'r:|[_-]=* r:|=*' - \
-              "${(@)tmp%% *}" && ret=0
-    fi
-    if (( $#onames )); then
-      tmp=( "${(@M)descr:#(${(kj:|:)~onames}) *}" )
-      compadd -qS= "$expl[@]" -ld tmp -M 'r:|[_-]=* r:|=*' - \
-              "${(@)tmp%% *}" && ret=0
-    fi
+  if [[ -n "$sep" && ${#snames}+${#names}+${#onames} -ne 1 ]]; then
+    opts=( "-qS$sep" )
   else
-    compadd "$expl[@]" -M 'r:|[_-]=* r:|=*' - "$snames[@]" && ret=0
-    compadd -S= "$expl[@]" -M 'r:|[_-]=* r:|=*' - "${(@k)names}" && ret=0
-    compadd -qS= "$expl[@]" -M 'r:|[_-]=* r:|=*' - "${(@k)onames}" && ret=0
+    opts=()
   fi
+
+  tmp1=( "${(@M)odescr:#(${(j:|:)~snames}):*}" )
+  tmp2=( "${(@M)odescr:#(${(kj:|:)~names}):*}" )
+  tmp3=( "${(@M)odescr:#(${(kj:|:)~onames}):*}" )
+
+  _describe "$gdescr" \
+  tmp1 "$opts[@]" -M 'r:|[_-]=* r:|=*' -- \
+  tmp2 -S= "$opts[@]" -M 'r:|[_-]=* r:|=*' -- \
+  tmp3 -qS= "$opts[@]" -M 'r:|[_-]=* r:|=*'
+
   return ret
 fi
 
diff --git a/Completion/Builtins/_cd b/Completion/Builtins/_cd
index e4502459c..35940d1fe 100644
--- a/Completion/Builtins/_cd
+++ b/Completion/Builtins/_cd
@@ -55,7 +55,7 @@ elif [[ $PREFIX = [-+]* ]]; then
   # get the array of numbers only
   list=(${lines%% *})
   _description expl 'directory stack index'
-  compadd "$expl[@]" -d lines -Q - "$list[@]" && ret=0
+  compadd "$expl[@]" -ld lines -Q - "$list[@]" && ret=0
   [[ -z $compstate[list] ]] && compstate[list]=list && ret=0
   [[ -n $compstate[insert] ]] && compstate[insert]=menu && ret=0
 
diff --git a/Completion/Builtins/_kill b/Completion/Builtins/_kill
index 264253e0a..d909bef76 100644
--- a/Completion/Builtins/_kill
+++ b/Completion/Builtins/_kill
@@ -10,9 +10,9 @@ else
 
   _description expl job
   compgen "$expl[@]" -P '%' -j && ret=0
-  list=("${(@Mr:COLUMNS-1:)${(f)$(ps ${compconfig[ps_listargs]:-$compconfig[ps_args]} 2>/dev/null)}[2,-1]:#[ 	]#${PREFIX}[0-9]#${SUFFIX}[ 	]*}")
+  list=("${(@Mr:COLUMNS-1:)${(f@)$(ps ${compconfig[ps_listargs]:-$compconfig[ps_args]} 2>/dev/null)}[2,-1]:#[ 	]#${PREFIX}[0-9]#${SUFFIX}[ 	]*}")
   _description expl 'process ID'
-  compadd "$expl[@]" -y list - ${${${(f)"$(ps $compconfig[ps_args] 2>/dev/null)"}[2,-1]## #}%% *} &&
+  compadd "$expl[@]" -ld list - ${${${(f)"$(ps $compconfig[ps_args] 2>/dev/null)"}[2,-1]## #}%% *} &&
     ret=0
 
   return ret
diff --git a/Completion/Builtins/_wait b/Completion/Builtins/_wait
index bcd39963f..7b20aaa10 100644
--- a/Completion/Builtins/_wait
+++ b/Completion/Builtins/_wait
@@ -17,6 +17,6 @@ _description expl job
 compgen "$expl[@]" -P '%' -j && ret=0
 list=("${(@Mr:COLUMNS-1:)${(f)$(ps ${compconfig[ps_listargs]:-$compconfig[ps_args]} 2>/dev/null)}[2,-1]:#[ 	]#${PREFIX}[0-9]#${SUFFIX}[ 	]*}")
 _description expl 'process ID'
-compadd "$expl[@]" -y list - ${${${(f)"$(ps $compconfig[ps_args] 2>/dev/null)"}[2,-1]## #}%% *} && ret=0
+compadd "$expl[@]" -ld list - ${${${(f)"$(ps $compconfig[ps_args] 2>/dev/null)"}[2,-1]## #}%% *} && ret=0
 
 return ret
diff --git a/Completion/Core/_approximate b/Completion/Core/_approximate
index 61f21c5b9..667f9919d 100644
--- a/Completion/Core/_approximate
+++ b/Completion/Core/_approximate
@@ -168,10 +168,21 @@ while [[ _comp_correct -le comax ]]; do
           "${#compstate[unambiguous]}" -ge "${#:-$PREFIX$SUFFIX}" ]]; then
       compstate[pattern_insert]=unambiguous
     elif [[ compstate[nmatches] -gt 1 || "$cfgorig" = *always* ]]; then
+      local expl
+
+      if [[ "$cfgorig" = *show* ]]; then
+        if [[ -n "$compconfig[description_format]" ]]; then
+	  expl=(-X "${compconfig[description_format]//\\%d/original}")
+        else
+	  expl=()
+        fi
+      else
+        expl=(-n)
+      fi
       if [[ "$cfgorig" = *last* ]]; then
-        builtin compadd -U -V _correct_original -nQ - "$PREFIX$SUFFIX"
+        builtin compadd "$expl[@]" -U -V _correct_original -Q - "$PREFIX$SUFFIX"
       elif [[ -n "$cfgorig" ]]; then
-	builtin compadd -U -nQ - "$PREFIX$SUFFIX"
+	builtin compadd "$expl[@]" -U -Q - "$PREFIX$SUFFIX"
       fi
 
       # If you always want to see the list of possible corrections,
diff --git a/Completion/Core/_expand b/Completion/Core/_expand
index 778293a8b..0b8083845 100644
--- a/Completion/Core/_expand
+++ b/Completion/Core/_expand
@@ -30,7 +30,7 @@
 #
 #  expand_menu
 #    If this is unset or set to the empty string, the words resulting
-#    from expansion (if any) will simply be inserted in the ommand line,
+#    from expansion (if any) will simply be inserted in the command line,
 #    replacing the original string. However, if this key is set to an
 #    non-empty string, the user can cycle through the expansion as in
 #    a menucompletion. Unless the value contains the sub-string `only',
@@ -56,7 +56,8 @@
 #    contain the control sequences `%n', `%B', etc. Also, the sequence
 #    `%o' in this string will be replaced by the original string.
 
-local exp word="$PREFIX$SUFFIX" group=-V
+local exp word="$PREFIX$SUFFIX" group=-V expl expl2 disp
+
 # Do this only for the first global matcher.
 
 [[ "$compstate[matcher]" -le 1 ]] || return 1
@@ -89,6 +90,34 @@ exp=("$word")
 [[ $#exp -eq 0 ||
    ( $#exp -eq 1 && "$exp[1]" = "$word"(|\(N\)) ) ]] && return 1
 
+# Get the options for adding the original string and `all'-string.
+
+if [[ "$compconfig[expand_original]" = *show* ]]; then
+  if [[ -n "$compconfig[description_format]" ]]; then
+    expl=(-X "${compconfig[description_format]//\\%d/original}")
+  else
+    expl=()
+  fi
+else
+  expl=(-n)
+fi
+
+if [[ -n "$compconfig[expand_menu]" &&
+      "$compconfig[expand_menu]" != *only* &&
+      "$compconfig[expand_menu]" = *showall* ]]; then
+  if [[ -n "$compconfig[description_format]" ]]; then
+    expl2=(-ld disp -X "${compconfig[description_format]//\\%d/all words}")
+  else
+    expl2=(-ld disp )
+  fi
+  disp=( "$exp" )
+  if [[ ${#disp[1]} -gt COLUMNS-5 ]]; then
+    disp=( "${disp[1][1,COLUMNS-5]}..." )
+  fi
+else
+  expl2=(-n)
+fi
+
 # We have expansions, should we menucomplete them?
 
 if [[ -z "$compconfig[expand_menu]" ]]; then
@@ -102,13 +131,13 @@ if [[ -z "$compconfig[expand_menu]" ]]; then
   else
     [[ -n "$compconfig[expand_original]" && 
        "$compconfig[expand_original]" != *last* ]] &&
-        compadd -UnQ -V _expand_original - "$word"
+        compadd "$expl[@]" -UQ -V _expand_original - "$word"
 
     compadd -UQ -V _expand - "$exp"
 
     [[ -n "$compconfig[expand_original]" && 
        "$compconfig[expand_original]" = *last* ]] &&
-        compadd -UnQ -V _expand_original - "$word"
+        compadd "$expl[@]" -UQ -V _expand_original - "$word"
 
     compstate[insert]=menu
   fi
@@ -122,11 +151,11 @@ else
 
   [[ -n "$compconfig[expand_original]" && 
      "$compconfig[expand_original]" != *last* ]] &&
-      compadd -UnQ -V _expand_original - "$word"
+      compadd "$expl[@]" -UQ -V _expand_original - "$word"
 
   [[ "$compconfig[expand_menu]" = *last* &&
      "$compconfig[expand_menu]" != *only* ]] &&
-      compadd -UnQ -V _expand_all - "$exp"
+      compadd "$expl2[@]" -UQ -V _expand_all - "$exp"
 
   if [[ -z "$compconfig[expand_prompt]" ]]; then
     compadd -UQ $group _expand - "$exp[@]"
@@ -136,11 +165,11 @@ else
   fi
   [[ "$compconfig[expand_menu]" != *last* &&
      "$compconfig[expand_menu]" != *only* ]] &&
-      compadd -UnQ -V _expand_all - "$exp"
+      compadd "$expl2[@]" -UQ -V _expand_all - "$exp"
 
   [[ -n "$compconfig[expand_original]" && 
      "$compconfig[expand_original]" = *last* ]] &&
-      compadd -UnQ -V _expand_original - "$word"
+      compadd "$expl[@]" -UQ -V _expand_original - "$word"
 
   compstate[insert]=menu
 fi
diff --git a/Completion/User/_gdb b/Completion/User/_gdb
index 1f64f0c1f..b16d18fb7 100644
--- a/Completion/User/_gdb
+++ b/Completion/User/_gdb
@@ -49,7 +49,7 @@ else
     _description expl 'process ID'
     list=("${(F)${(@Mr:COLUMNS-1:)${(f)$(ps ${compconfig[ps_listargs]:-$compconfig[ps_args]} 2>/dev/null)}[2,-1]:#[ 	]#${PREFIX}[0-9]#${SUFFIX}[ 	]*${w[1]:t}}}
 ")
-    compadd "$expl[@]" -y list - ${${${(M)${(f)"$(ps $compconfig[ps_args] 2>/dev/null)"}:#*${w[1]:t}*}## #}%% *} && ret=0
+    compadd "$expl[@]" -ld list - ${${${(M)${(f)"$(ps $compconfig[ps_args] 2>/dev/null)"}:#*${w[1]:t}*}## #}%% *} && ret=0
 
     return ret
   else
diff --git a/Doc/Zsh/compsys.yo b/Doc/Zsh/compsys.yo
index 2f228d3ff..267617b15 100644
--- a/Doc/Zsh/compsys.yo
+++ b/Doc/Zsh/compsys.yo
@@ -595,6 +595,36 @@ array built is stored in it.
 The return value of tt(_display) is zero if there was at least one
 match with a description non-zero otherwise.
 )
+item(tt(_describe))(
+This function can be used to add options or values with descriptions
+as matches. The first argument is taken as a string to display above
+the matches if the tt(description_format) configuration key is set.
+
+After this one or two names of arrays followed by options to give
+to tt(compadd) must be given. The first array contains the possible
+completions with their descriptions (with the description separated
+by a colon from the completion string). If the second array is given,
+it should have the same number of elements as the first one and these
+elements are added as possible completions instead of the strings from 
+the first array. In any case, however, the completion list will show
+the strings from the first array.
+
+Any number of array/option sequences may be given separated by
+`tt(-)tt(-)'. This allows one to display matches together that need
+to be added with different options for tt(compadd).
+
+Before the first argument, two options may be given. A `tt(-o)' says
+that the matches added are option names. This will make tt(_describe)
+use the tt(option_prefix) and tt(describe_options) configuration keys
+to find out if the strings should be added at all and if the
+descriptions should be shown. Without the `tt(-o)' option, the
+tt(describe_values) key is used.
+
+The `tt(-c)' option, followed by a string, may be used to give the
+name of the current command for testing the configuration keys. If the 
+first element of the tt(words) special array contains the correct
+command name, this option need not be used.
+)
 item(tt(_multi_parts))(
 This function gets two arguments: a separator character and an
 array.  As usual, the array may be either the
@@ -1147,7 +1177,9 @@ possible matches when no other completions could be found or if the
 string on the line begins with a option prefix character (a minus or a 
 plus sign). This value may also contain strings of the form
 `tt(!)var(command)' which makes options be always completed for all
-var(command)s given in this way.
+var(command)s given in this way. Finally, if the value of this key
+begins with `tt(hide)', the prefix characters `tt(-)', `tt(+)', or
+`tt(-)tt(-)' will not be shown in the list.
 )
 item(tt(last_prompt))(
 If this is set to tt(always), the cursor will always be moved back to
@@ -1199,7 +1231,9 @@ corrected strings.  If the value for this key contains the substring
 that it appears just before wrapping around to the first corrected
 string again.  Also, if the value contains the substring `tt(always)',
 the original string will always be included; normally it is
-included only if more than one possible correction was generated.
+included only if more than one possible correction was generated. And
+finally, if the value contains the substring `tt(show)', the original
+string will be shown in the list of corrections.
 )
 item(tt(approximate_prompt))(
 This can be set to a string to be displayed on top of the
@@ -1246,9 +1280,11 @@ menucompletion. Unless the value contains the substring `tt(only)',
 the user will still be offered all expansions at once as one of the
 strings to insert in the command line; normally, this possibility is
 offered first, but if the value contains the
-substring `tt(last)', it is offered last. Finally, if the value contains
+substring `tt(last)', it is offered last. Also, if the value contains
 the substring `tt(sort)', the expansions will be sorted alphabetically,
 normally they are kept in the order the expansion produced them in.
+And finally, if the value contains the substring `tt(showall)', the
+string of all words will be shown in the list of expansions.
 )
 item(tt(expand_original))(
 If this is set to an non-empty string, the original string from the
@@ -1256,7 +1292,9 @@ line will be included in the list of strings the user can cycle
 through as in a menucompletion. If the value contains the substring
 `tt(last)', the original string will appear as the last string, with
 other values it is inserted as the first one (so that the command line
-does not change immediately).
+does not change immediately). Also, if the value contains the
+substring `tt(show)', the original string will be shown in the list of 
+expansions.
 )
 item(tt(expand_prompt))(
 This may be set to a string that should be displayed before the
diff --git a/Etc/completion-style-guide b/Etc/completion-style-guide
index 5bc289b9b..286cb2a71 100644
--- a/Etc/completion-style-guide
+++ b/Etc/completion-style-guide
@@ -74,8 +74,8 @@ For now this is just a list of things one should or shouldn't do.
       fi
 
     Finally, it is good style to display descriptions for options that
-    aren't self-explanatory. See the `_display' function and its use
-    in `_arguments'.
+    aren't self-explanatory. See the `_display' and `_describe' functions
+    and their uses in `_arguments'.
 
     All this should make it look like a really good idea to just use the
     supplied `_arguments' function to complete options.
diff --git a/Src/Zle/complist.c b/Src/Zle/complist.c
index 913a5e592..af034efab 100644
--- a/Src/Zle/complist.c
+++ b/Src/Zle/complist.c
@@ -375,7 +375,7 @@ complistmatches(Hookdef dummy, Chdata dat)
 		    if (m->flags & CMF_DISPLINE) {
 			nlines += 1 + printfmt(m->disp, 0, 0, 0);
 			g->flags |= CGF_HASDL;
-		    } else if ((l = strlen(m->disp)) > longest)
+		    } else if ((l = niceztrlen(m->disp)) > longest)
 			longest = l;
 		    nlist++;
 		} else if (!(m->flags & CMF_NOLIST)) {
@@ -395,7 +395,7 @@ complistmatches(Hookdef dummy, Chdata dat)
 	}
     }
     longest += 2 + of;
-    if ((ncols = (columns + 1) / longest)) {
+    if ((ncols = columns / longest)) {
 	for (g = amatches; g; g = g->next)
 	    nlines += (g->lcount - g->llcount + ncols - 1) / ncols;
     } else {
@@ -417,7 +417,7 @@ complistmatches(Hookdef dummy, Chdata dat)
 			if (m->flags & CMF_DISPLINE)
 			    nlines += 1 + printfmt(m->disp, 0, 0, 0);
 			else
-			    nlines += 1 + ((1 + niceztrlen(m->disp)) / columns);
+			    nlines += 1 + (niceztrlen(m->disp) / columns);
 		    } else if (!(m->flags & CMF_NOLIST))
 			nlines += 1 + ((1 + niceztrlen(m->str)) / columns);
 	}
@@ -678,7 +678,7 @@ complistmatches(Hookdef dummy, Chdata dat)
 			    putc(' ', shout);
 		    }
 		    a = longest - niceztrlen(m->disp ? m->disp : m->str) - 2 - of;
-		    while (a--)
+		    while (a-- > 0)
 			putc(' ', shout);
 		    if (col.cols[COL_EC])
 			tputs(col.cols[COL_EC], 1, putshout);
diff --git a/Src/Zle/zle_tricky.c b/Src/Zle/zle_tricky.c
index ecbfc123e..51d331f4a 100644
--- a/Src/Zle/zle_tricky.c
+++ b/Src/Zle/zle_tricky.c
@@ -3925,7 +3925,8 @@ addmatches(Cadata dat, char **argv)
 		aign = get_user_var(dat->ign);
 	    /* Get the display strings. */
 	    if (dat->disp)
-		disp = get_user_var(dat->disp) - 1;
+		if ((disp = get_user_var(dat->disp)))
+		    disp--;
 	    /* Get the contents of the completion variables if we have
 	     * to perform matching. */
 	    if (dat->aflags & CAF_MATCH) {
@@ -8194,6 +8195,16 @@ printfmt(char *fmt, int n, int dopr, int doesc)
 	} else {
 	    cc++;
 	    if (*p == '\n') {
+		if (dopr) {
+		    if (tccan(TCCLEAREOL))
+			tcout(TCCLEAREOL);
+		    else {
+			int s = columns - 1 - (cc % columns);
+
+			while (s-- > 0)
+			    putc(' ', shout);
+		    }
+		}
 		l += 1 + (cc / columns);
 		cc = 0;
 	    }
@@ -8201,7 +8212,16 @@ printfmt(char *fmt, int n, int dopr, int doesc)
 		putc(*p, shout);
 	}
     }
+    if (dopr) {
+	if (tccan(TCCLEAREOL))
+	    tcout(TCCLEAREOL);
+	else {
+	    int s = columns - 1 - (cc % columns);
 
+	    while (s-- > 0)
+		putc(' ', shout);
+	}
+    }
     return l + (cc / columns);
 }
 
@@ -8291,7 +8311,7 @@ ilistmatches(Hookdef dummy, Chdata dat)
 		    if (m->flags & CMF_DISPLINE) {
 			nlines += 1 + printfmt(m->disp, 0, 0, 0);
 			g->flags |= CGF_HASDL;
-		    } else if ((l = strlen(m->disp)) > longest)
+		    } else if ((l = niceztrlen(m->disp)) > longest)
 			longest = l;
 		    nlist++;
 		} else if (!(m->flags & CMF_NOLIST)) {
@@ -8310,7 +8330,7 @@ ilistmatches(Hookdef dummy, Chdata dat)
 	}
     }
     longest += 2 + of;
-    if ((ncols = (columns + 1) / longest)) {
+    if ((ncols = columns / longest)) {
 	for (g = amatches; g; g = g->next)
 	    nlines += (g->lcount + ncols - 1) / ncols;
     } else {
@@ -8328,7 +8348,12 @@ ilistmatches(Hookdef dummy, Chdata dat)
 		}
 	    } else
 		for (p = g->matches; (m = *p); p++)
-		    if (!(m->flags & CMF_NOLIST))
+		    if (m->disp) {
+			if (m->flags & CMF_DISPLINE)
+			    nlines += 1 + printfmt(m->disp, 0, 0, 0);
+			else
+			    nlines += 1 + (niceztrlen(m->disp) / columns);
+		    } else if (!(m->flags & CMF_NOLIST))
 			nlines += 1 + ((1 + niceztrlen(m->str)) / columns);
 	}
     }
@@ -8476,7 +8501,7 @@ ilistmatches(Hookdef dummy, Chdata dat)
 
 			a--;
 		    }
-		    if (i && !opl)
+		    if (i && !opl && a > 0)
 			while (a--)
 			    putc(' ', shout);
 		    if (--n)