about summary refs log tree commit diff
diff options
context:
space:
mode:
authorTanaka Akira <akr@users.sourceforge.net>1999-12-06 11:39:12 +0000
committerTanaka Akira <akr@users.sourceforge.net>1999-12-06 11:39:12 +0000
commitbb93d135ba484cd423ae71b1686c63ac2c1c654f (patch)
treeea3a27c4f3a5855eb3c176ad322c2d9e225e9d9d
parentfb5a1bc4dce28016a61eb11033bfb9a23ea74b5e (diff)
downloadzsh-bb93d135ba484cd423ae71b1686c63ac2c1c654f.tar.gz
zsh-bb93d135ba484cd423ae71b1686c63ac2c1c654f.tar.xz
zsh-bb93d135ba484cd423ae71b1686c63ac2c1c654f.zip
zsh-workers/8911
-rw-r--r--Completion/Commands/_complete_help3
-rw-r--r--Completion/Core/_approximate6
-rw-r--r--Completion/Core/_expand49
-rw-r--r--Completion/Core/_list3
-rw-r--r--Completion/Core/_main_complete8
-rw-r--r--Completion/Core/_message5
-rw-r--r--Completion/Core/_setup56
-rw-r--r--Completion/Core/_style20
-rw-r--r--Doc/Zsh/compsys.yo41
-rw-r--r--Doc/Zsh/compwid.yo38
-rw-r--r--Doc/Zsh/params.yo4
-rw-r--r--Src/Zle/comp.h60
-rw-r--r--Src/Zle/compcore.c66
-rw-r--r--Src/Zle/complete.c7
-rw-r--r--Src/Zle/compresult.c39
15 files changed, 264 insertions, 141 deletions
diff --git a/Completion/Commands/_complete_help b/Completion/Commands/_complete_help
index cfefdcf90..446fb2a90 100644
--- a/Completion/Commands/_complete_help
+++ b/Completion/Commands/_complete_help
@@ -18,8 +18,7 @@ _complete_help() {
 tags in context \`${i}': ${help_tags[$i]}"
   done
 
-  compstate[list]=list
-  compstate[force_list]=yes
+  compstate[list]='list force'
   compstate[insert]=''
 
   compadd -UX "$text[2,-1]" -n ''
diff --git a/Completion/Core/_approximate b/Completion/Core/_approximate
index f10d6588c..c0d409cb3 100644
--- a/Completion/Core/_approximate
+++ b/Completion/Core/_approximate
@@ -78,7 +78,7 @@ compstate[matcher]=-1
 
 _correct_prompt="${cfgps//\\%e/1}"
 
-_setup original corrections
+_setup corrections
 
 [[ "$cfgorig" != *last* ]] && builtin compadd -V original
 builtin compadd -J corrections
@@ -104,12 +104,14 @@ while [[ _comp_correct -le comax ]]; do
       else
         expl=(-n)
       fi
+      _setup original
       builtin compadd "$expl[@]" -U -V original -Q - "$PREFIX$SUFFIX"
 
       # If you always want to see the list of possible corrections,
       # set `compstate[list]=list' here.
 
-      compstate[force_list]=list
+      [[ "$compstate[list]" != list* ]] &&
+          compstate[list]="$compstate[list] force"
     fi
     compstate[matcher]="$compstate[total_matchers]"
     unfunction compadd
diff --git a/Completion/Core/_expand b/Completion/Core/_expand
index 7598b6f88..471ad370e 100644
--- a/Completion/Core/_expand
+++ b/Completion/Core/_expand
@@ -84,8 +84,6 @@ fi
 
 exp=( "${(@)${(@)${(@q)exp}//\\\\=/=}/#=/\\=}" )
 
-_setup original expansions all-expansions
-
 # We have expansions, should we menucomplete them?
 
 if [[ -z "$menu" ]]; then
@@ -95,16 +93,20 @@ if [[ -z "$menu" ]]; then
   # probably also adding the original string.
 
   if [[ -z "$compstate[insert]" ]]; then
+    _setup all-expansions
     compadd -U -V all-expansions -Q - "$exp[@]"
   else
-    [[ -n "$orig" && "$orig" != *last* ]] &&
-        compadd "$expl[@]" -UQ -V original - "$word"
-
-    compadd -UQ -V _expand - "$exp"
-
-    [[ -n "$orig" && "$orig" = *last* ]] &&
-        compadd "$expl[@]" -UQ -V original - "$word"
+    if [[ -n "$orig" && "$orig" != *last* ]]; then
+      _setup original
+      compadd "$expl[@]" -UQ -V original - "$word"
+    fi
+    _setup expansions
+    compadd -UQ -V expansions - "$exp"
 
+    if [[ -n "$orig" && "$orig" = *last* ]]; then
+      _setup original
+      compadd "$expl[@]" -UQ -V original - "$word"
+    fi
     compstate[insert]=menu
   fi
 else
@@ -115,24 +117,29 @@ else
   # Now add the expansion string, probably also adding the original
   # and/or the string containing all expanded string.
 
-  [[ -n "$orig" && "$orig" != *last* ]] &&
-      compadd "$expl[@]" -UQ -V original - "$word"
-
-  [[ $#exp -ne 1 && "$menu" = *last* && "$menu" != *only* ]] &&
-      compadd "$expl2[@]" -UQ -V all-expansions - "$exp"
-
+  if [[ -n "$orig" && "$orig" != *last* ]]; then
+    _setup original
+    compadd "$expl[@]" -UQ -V original - "$word"
+  fi
+  if [[ $#exp -ne 1 && "$menu" = *last* && "$menu" != *only* ]]; then
+    _setup all-expansions
+    compadd "$expl2[@]" -UQ -V all-expansions - "$exp"
+  fi
+  _setup expansions
   if [[ -z "$prompt" ]]; then
     compadd -UQ $group expansions - "$exp[@]"
   else
     compadd -UQ -X "${prompt//\\%o/$word}" \
             $group expansions - "$exp[@]"
   fi
-  [[ $#exp -ne 1 && "$menu" != *last* && "$menu" != *only* ]] &&
-      compadd "$expl2[@]" -UQ -V all-expansions - "$exp"
-
-  [[ -n "$orig" && "$orig" = *last* ]] &&
-      compadd "$expl[@]" -UQ -V original - "$word"
-
+  if [[ $#exp -ne 1 && "$menu" != *last* && "$menu" != *only* ]]; then
+    _setup all-expansions
+    compadd "$expl2[@]" -UQ -V all-expansions - "$exp"
+  fi
+  if [[ -n "$orig" && "$orig" = *last* ]]; then
+    _setup original
+    compadd "$expl[@]" -UQ -V original - "$word"
+  fi
   compstate[insert]=menu
 fi
 
diff --git a/Completion/Core/_list b/Completion/Core/_list
index ea2ed36aa..6c72bc9e9 100644
--- a/Completion/Core/_list
+++ b/Completion/Core/_list
@@ -26,8 +26,7 @@ if [[ ( -z "$expr" || "${(e):-\$[$expr]}" -eq 1 ) &&
   # to compare the next time.
 
   compstate[insert]=''
-  compstate[list]=list
-  compstate[force_list]=yes
+  compstate[list]='list force'
   _list_prefix="$pre"
   _list_suffix="$suf"
 fi
diff --git a/Completion/Core/_main_complete b/Completion/Core/_main_complete
index 4dd3bd218..f8ef78753 100644
--- a/Completion/Core/_main_complete
+++ b/Completion/Core/_main_complete
@@ -19,6 +19,9 @@
 
 local comp post ret=1 _compskip _prio_num=1 _cur_context format
 local context state line opt_args val_args curcontext="$curcontext"
+local _saved_exact="$compstate[exact]" \
+      _saved_lastprompt="$compstate[last_prompt]" \
+      _saved_list="$compstate[list]"
 typeset -U _offered_tags _tried_tags _failed_tags _used_tags _unused_tags
 
 _offered_tags=()
@@ -82,8 +85,7 @@ if [[ compstate[nmatches] -eq 0 &&
       -n "$format" && $#_lastdescr -ne 0 ]]; then
   local str
 
-  compstate[list]=list
-  compstate[force_list]=yes
+  compstate[list]='list force'
   compstate[insert]=''
 
   case $#_lastdescr in
@@ -95,8 +97,6 @@ if [[ compstate[nmatches] -eq 0 &&
   compadd -UX "${format//\\%d/$str}" -n ''
 fi
 
-_style '' last-prompt && compstate[last_prompt]=yes
-
 _lastcomp=( "${(@kv)compstate}" )
 _lastcomp[completer]="$comp"
 _lastcomp[prefix]="$PREFIX"
diff --git a/Completion/Core/_message b/Completion/Core/_message
index 5c5c42e06..b2730a331 100644
--- a/Completion/Core/_message
+++ b/Completion/Core/_message
@@ -8,11 +8,10 @@ _style -s messages format format || _style -s descriptions format format
 
 if [[ -n "$format" ]]; then
   if [[ $compstate[nmatches] -eq 0 ]]; then
-    compstate[list]=list
-    compstate[force_list]=yes
+    compstate[list]='list force'
     compstate[insert]=''
     compadd -UX "${format//\\%d/$1}" -n ''
   else
-    compadd -X "${format//\\%d/$1}" -n '' && compstate[force_list]=yes
+    compadd -X "${format//\\%d/$1}" -n '' && compstate[list]='list force'
   fi
 fi
diff --git a/Completion/Core/_setup b/Completion/Core/_setup
index f12c34b34..683757918 100644
--- a/Completion/Core/_setup
+++ b/Completion/Core/_setup
@@ -1,13 +1,51 @@
 #autoload
 
-local colors i
+local val
 
-for i; do
-  if _style -a "$i" list-colors colors; then
-    if [[ "$1" = default ]]; then
-      ZLS_COLORS="${(j.:.)${(@)colors:gs/:/\\\:}}"
-    else
-      eval "ZLS_COLORS=\"(${i})\${(j.:(${i}).)\${(@)colors:gs/:/\\\:}}:\${ZLS_COLORS}\""
-    fi
+if _style -a "$1" list-colors val; then
+  if [[ "$1" = default ]]; then
+    ZLS_COLORS="${(j.:.)${(@)val:gs/:/\\\:}}"
+  else
+    eval "ZLS_COLORS=\"(${i})\${(j.:(${i}).)\${(@)val:gs/:/\\\:}}:\${ZLS_COLORS}\""
   fi
-done
+fi
+
+if _style -s "$1" list-packed val; then
+  if [[ "$val" = (yes|true|1|on) ]]; then
+    compstate[list]="${compstate[list]} packed"
+  else
+    compstate[list]="${compstate[list]:gs/packed//}"
+  fi
+else
+  compstate[list]="$_saved_list"
+fi
+
+if _style -s "$1" list-rows-first val; then
+  if [[ "$val" = (yes|true|1|on) ]]; then
+    compstate[list]="${compstate[list]} rows"
+  else
+    compstate[list]="${compstate[list]:gs/rows//}"
+  fi
+else
+  compstate[list]="$_saved_list"
+fi
+
+if _style -s "$1" last-prompt val; then
+  if [[ "$val" = (yes|true|1|on) ]]; then
+    compstate[last_prompt]=yes
+  else
+    compstate[last_prompt]=''
+  fi
+else
+  compstate[last_prompt]="$_saved_lastprompt"
+fi
+
+if _style -s "$1" accept-exact val; then
+  if [[ "$val" = (yes|true|1|on) ]]; then
+    compstate[exact]=accept
+  else
+    compstate[exact]=''
+  fi
+else
+  compstate[exact]="$_saved_exact"
+fi
diff --git a/Completion/Core/_style b/Completion/Core/_style
index 6e2de23df..d666a9fd8 100644
--- a/Completion/Core/_style
+++ b/Completion/Core/_style
@@ -1,21 +1,21 @@
 #autoload
 
-local val ret
+local _val _ret
 
 # Should we return the value?
 
 case "$1" in
 -b)
-  compstyles -S "$context" "$2" val
-  ret="$?"
+  compstyles -S "${curcontext}${2:+:${2}}" "$3" _val
+  _ret="$?"
 
-  if [[ "$val" = (#I)(yes|true|1|on) ]]; then
-    eval "${3}=yes"
+  if [[ "$_val" = (yes|true|1|on) ]]; then
+    eval "${4}=yes"
   else
-    eval "${3}=no"
+    eval "${4}=no"
   fi
 
-  return ret;
+  return _ret
   ;;
 -s)
   compstyles -S "${curcontext}${2:+:${2}}" "$3" "$4"
@@ -33,11 +33,11 @@ esac
 
 [[ "$1" = -(|-) ]] && shift
 
-if compstyles -S "${curcontext}${1:+:${1}}" "$2" val; then
+if compstyles -S "${curcontext}${1:+:${1}}" "$2" _val; then
   if [[ $# -eq 3 ]]; then
-    [[ "$val" = ${~3} ]]
+    [[ "$_val" = ${~3} ]]
   else
-    [[ "$val" = (#I)(yes|true|1|on) ]]
+    [[ "$_val" = (yes|true|1|on) ]]
   fi
 else
   return 1
diff --git a/Doc/Zsh/compsys.yo b/Doc/Zsh/compsys.yo
index 5725b085b..36782f2ff 100644
--- a/Doc/Zsh/compsys.yo
+++ b/Doc/Zsh/compsys.yo
@@ -762,11 +762,13 @@ values. In all these cases any of the strings `tt(true)', `tt(on)',
 every other value (or if the style is not set at all for the context
 in which it is looked up) stands for `false'.
 
-em(NOTE: Maybe we should sort them differently. Or maybe we should
-explain some of them only when explaining the completers that use
-them.)
-
 startitem()
+item(tt(accept-exact))(
+This is tested for the default tag and the tags used when generating
+matches. If it is set to `true' for at least one match which is the
+same as the string on the line, this match will immediatly be
+accepted.
+)
 item(tt(arguments))(
 The value of this style is given to the tt(ps) command by functions
 that call it when generating process identifiers as matches.
@@ -933,10 +935,13 @@ completion only if no unambiguous string could be generated that is at
 least as long as the original string from the line.
 )
 item(tt(last-prompt))(
-This is used by the main completion function tt(_main_complete) with
-no particular context name. If it 
-is `true', the cursor will always be moved back to the last prompt if
-that is still visible, independent of the setting of the
+This is used to determine if thecompletion code should try to put the
+cursor back onto the previous command line after showing a completion
+listing (as for the tt(ALWAYS_LAST_PROMPT) option). Like several other 
+styles it is tested for the tt(default) tag and all tags used when
+generating matches. The cursor will be moved back to the previous line 
+if this style is `true' for all types of matches added. Note also that 
+this is independent of the numeric argument -- unlike the
 tt(ALWAYS_LAST_PROMPT) option.
 )
 item(tt(list))(
@@ -1003,6 +1008,18 @@ example(compstyle '*:default' list-colors ${(s.:.)LS_COLORS})
 And to get the default colors (which are the same as for the GNU
 tt(ls) command) one should set the style to an empty value.
 )
+item(tt(list-packed))(
+Like the tt(list-colors) style, this is tested with the tt(default)
+tag and all tags used when generating matches. If it is set to `true'
+for a tag, the matches added for it will be listed as if the
+tt(LIST_PACKED) option were set for them. If it is set to `false',
+they are listed normally.
+)
+item(tt(list-rows-first))(
+This style is tested like the tt(list-packed) style and determines if
+matches are to be listed in a rows-first fashion, as for the
+tt(LIST_ROWS_FIRST) option.
+)
 item(tt(local))(
 This style is used by completion functions which generate URLs as
 possible matches to add suitable matches when a URL points to a
@@ -1041,7 +1058,7 @@ This is used by the tt(_expand) completer. If it is unset or set to
 an empty value, the words resulting from expansion (if any) will
 simply be inserted in the command line, replacing the original
 string. However, if this style is set to a non-empty value, the user
-can cycle through the expansion as in menucompletion. Unless the value
+can cycle through the expansions as in menucompletion. Unless the value
 contains the string `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
@@ -1772,6 +1789,12 @@ only for a boolean value, you can give a third argument which is then
 used as a pattern and tt(_style) returns zero if the pattern matches
 the value defined for the style.
 
+The tt(-t) and tt(-f) options can be used to test for slightly
+different interpretions of boolean values. If they are given with a
+tag and a style-name as arguments, the return value is zero only if
+the style is set and the value is equal (or, in case of then tt(-f)
+option: unequal) to one of the values mentioned above.
+
 If you want to retrieve the value defined for the style, you can use
 one of the options tt(-b) (to retrieve it as a boolean value, i.e. one 
 of tt(yes) or tt(no)), tt(-s) (to get it as a scalar, i.e. a string
diff --git a/Doc/Zsh/compwid.yo b/Doc/Zsh/compwid.yo
index 89e4f97ca..f383bb595 100644
--- a/Doc/Zsh/compwid.yo
+++ b/Doc/Zsh/compwid.yo
@@ -235,17 +235,22 @@ is unset or empty they will never be listed; if its value begins with
 tt(list), they will always be listed; if it begins with tt(autolist)
 or tt(ambiguous), they will be listed when the tt(AUTO_LIST) or
 tt(LIST_AMBIGUOUS) options respectively would normally cause them to
-be.  Finally, if the value contains the string tt(explanations), only
-the explanation strings, if any, will be listed. It will be set
+be.
+
+If the substring tt(force) appears in the value, this makes the
+list be shown even if there is only one match. Normally, the list
+would be shown only if there are at least two matches.
+
+The value contains the substring tt(packed) if the tt(LIST_PACKED)
+option is set. If this substring is given for all matches added of a
+group, this group will show the tt(LIST_PACKED) behavior. The same is
+done for the tt(LIST_ROWS_FIRST) option with the substring tt(rows).
+
+Finally, if the value contains the string tt(explanations), only the
+explanation strings, if any, will be listed. It will be set
 appropriately on entry to a completion widget and may be changed
 there.
 )
-item(tt(force_list))(
-If the value for the tt(list) key is tt(autolist) or tt(ambiguous), the list will
-normally be shown only if there are at least two matches in the
-list. Setting tt(force_list) to an non-empty string forces the list to be
-shown even if there is only one match.
-)
 item(tt(list_max))(
 Initially this is set to the value of the tt(LISTMAX) parameter.
 It may be set to any other numeric value; when the widget exits this value
@@ -259,18 +264,21 @@ line to this value, this is available as the value of the tt(BLINES)
 special parameter.
 )
 item(tt(last_prompt))(
-If this is set to an non-empty string, the completion code will move
-the cursor back to the previous prompt after the list of completions
-has been displayed.  Initially this is set or unset according to
-the tt(ALWAYS_LAST_PROMPT) option.
+If this is set to an non-empty string for every match added, the
+completion code will move the cursor back to the previous prompt after
+the list of completions has been displayed.  Initially this is set or
+unset according to the tt(ALWAYS_LAST_PROMPT) option.
 )
 item(tt(insert))(
 This controls the manner in which a match is inserted into the command
 line.  On entry to the widget function, if it is unset the command line is
 not to be changed; if set to tt(unambiguous), any prefix common to all
-matches is to be inserted; if set to tt(menu) or tt(automenu) the usual
-behaviour of the tt(MENU_COMPLETE) or tt(AUTO_MENU) options, respectively,
-is to be used.
+matches is to be inserted; if set to tt(automenu-unambiguous), the
+common prefix is to be inserted and the next invocation of the
+completion code may start menu-completion (due to the tt(AUTO_MENU)
+option being set); if set to tt(menu) or tt(automenu) menu-completion
+will be started for the matches currently generated due to (in the
+latter case this will happen because the tt(AUTO_MENU) is set).
 
 On exit it may be set to any of the values above (where setting it to
 the empty string is the same as unsetting it), or to a number, in which
diff --git a/Doc/Zsh/params.yo b/Doc/Zsh/params.yo
index bec7937ae..5bb8b9e6e 100644
--- a/Doc/Zsh/params.yo
+++ b/Doc/Zsh/params.yo
@@ -591,7 +591,9 @@ Used for printing select lists and for the line editor.
 )
 vindex(LISTMAX)
 item(tt(LISTMAX))(
-In the line editor, the number of filenames to list without asking first.
+In the line editor, the number of matches to list without asking
+first. If the value is negative, the list will be shown if it spans at 
+most as many lines as given by the absolute value.
 If set to zero, the shell asks only if the top of the listing would scroll
 off the screen.
 )
diff --git a/Src/Zle/comp.h b/Src/Zle/comp.h
index 6f3b2cd16..a177be614 100644
--- a/Src/Zle/comp.h
+++ b/Src/Zle/comp.h
@@ -81,6 +81,8 @@ struct cmgroup {
 #define CGF_HASDL    4		/* has display strings printed on separate lines */
 #define CGF_UNIQALL  8		/* remove all duplicates */
 #define CGF_UNIQCON 16		/* remove consecutive duplicates */
+#define CGF_PACKED  32		/* LIST_PACKED for this group */
+#define CGF_ROWS    64		/* LIST_ROWS_FIRST for this group */
 
 /* This is the struct used to hold matches. */
 
@@ -107,15 +109,17 @@ struct cmatch {
     int gnum;			/* global number */
 };
 
-#define CMF_FILE       1	/* this is a file */
-#define CMF_REMOVE     2	/* remove the suffix */
-#define CMF_ISPAR      4	/* is paramter expansion */
-#define CMF_PARBR      8	/* paramter expansion with a brace */
-#define CMF_PARNEST   16	/* nested paramter expansion */
-#define CMF_NOLIST    32	/* should not be listed */
-#define CMF_DISPLINE  64	/* display strings one per line */
-#define CMF_HIDE     128	/* temporarily hide this one */
-#define CMF_NOSPACE  256	/* don't add a space */
+#define CMF_FILE     (1<< 0)	/* this is a file */
+#define CMF_REMOVE   (1<< 1)	/* remove the suffix */
+#define CMF_ISPAR    (1<< 2)	/* is paramter expansion */
+#define CMF_PARBR    (1<< 3)	/* paramter expansion with a brace */
+#define CMF_PARNEST  (1<< 4)	/* nested paramter expansion */
+#define CMF_NOLIST   (1<< 5)	/* should not be listed */
+#define CMF_DISPLINE (1<< 6)	/* display strings one per line */
+#define CMF_HIDE     (1<< 7)	/* temporarily hide this one */
+#define CMF_NOSPACE  (1<< 8)	/* don't add a space */
+#define CMF_PACKED   (1<< 9)	/* prefer LIST_PACKED */
+#define CMF_ROWS     (1<<10)	/* prefer LIST_ROWS_FIRST */
 
 /* Stuff for completion matcher control. */
 
@@ -322,43 +326,41 @@ typedef void (*CLPrintFunc)(Cmgroup, Cmatch *, int, int, int, int,
 #define CP_RESTORE     (1 << CPN_RESTORE)
 #define CPN_LIST       10
 #define CP_LIST        (1 << CPN_LIST)
-#define CPN_FORCELIST  11
-#define CP_FORCELIST   (1 << CPN_FORCELIST)
-#define CPN_INSERT     12
+#define CPN_INSERT     11
 #define CP_INSERT      (1 << CPN_INSERT)
-#define CPN_EXACT      13
+#define CPN_EXACT      12
 #define CP_EXACT       (1 << CPN_EXACT)
-#define CPN_EXACTSTR   14
+#define CPN_EXACTSTR   13
 #define CP_EXACTSTR    (1 << CPN_EXACTSTR)
-#define CPN_PATMATCH   15
+#define CPN_PATMATCH   14
 #define CP_PATMATCH    (1 << CPN_PATMATCH)
-#define CPN_PATINSERT  16
+#define CPN_PATINSERT  15
 #define CP_PATINSERT   (1 << CPN_PATINSERT)
-#define CPN_UNAMBIG    17
+#define CPN_UNAMBIG    16
 #define CP_UNAMBIG     (1 << CPN_UNAMBIG)
-#define CPN_UNAMBIGC   18
+#define CPN_UNAMBIGC   17
 #define CP_UNAMBIGC    (1 << CPN_UNAMBIGC)
-#define CPN_LISTMAX    19
+#define CPN_LISTMAX    18
 #define CP_LISTMAX     (1 << CPN_LISTMAX)
-#define CPN_LASTPROMPT 20
+#define CPN_LASTPROMPT 19
 #define CP_LASTPROMPT  (1 << CPN_LASTPROMPT)
-#define CPN_TOEND      21
+#define CPN_TOEND      20
 #define CP_TOEND       (1 << CPN_TOEND)
-#define CPN_OLDLIST    22
+#define CPN_OLDLIST    21
 #define CP_OLDLIST     (1 << CPN_OLDLIST)
-#define CPN_OLDINS     23
+#define CPN_OLDINS     22
 #define CP_OLDINS      (1 << CPN_OLDINS)
-#define CPN_VARED      24
+#define CPN_VARED      23
 #define CP_VARED       (1 << CPN_VARED)
-#define CPN_ANMATCHES  25
+#define CPN_ANMATCHES  24
 #define CP_ANMATCHES   (1 << CPN_ANMATCHES)
-#define CPN_LISTLINES  26
+#define CPN_LISTLINES  25
 #define CP_LISTLINES   (1 << CPN_LISTLINES)
-#define CPN_QUOTES     27
+#define CPN_QUOTES     26
 #define CP_QUOTES      (1 << CPN_QUOTES)
 
-#define CP_KEYPARAMS   28
-#define CP_ALLKEYS     ((unsigned int) 0xfffffff)
+#define CP_KEYPARAMS   27
+#define CP_ALLKEYS     ((unsigned int) 0x7ffffff)
 
 /* Hooks. */
 
diff --git a/Src/Zle/compcore.c b/Src/Zle/compcore.c
index 1bc1fd86f..d6f21f46d 100644
--- a/Src/Zle/compcore.c
+++ b/Src/Zle/compcore.c
@@ -37,7 +37,12 @@ static Widget lastcompwidget;
 /* Flags saying what we have to do with the result. */
 
 /**/
-int useexact, useline, uselist;
+int useexact, useline, uselist, forcelist, startauto;
+
+/* Non-zero if we should go back to the last prompt. */
+
+/**/
+int dolastprompt;
 
 /* Non-zero if we should keep an old list. */
 
@@ -276,6 +281,8 @@ do_completion(Hookdef dummy, Compldat dat)
 	hasunqu = 0;
 	useline = (lst != COMP_LIST_COMPLETE);
 	useexact = isset(RECEXACT);
+	zsfree(compexactstr);
+	compexactstr = ztrdup("");
 	uselist = (useline ?
 		   ((isset(AUTOLIST) && !isset(BASHAUTOLIST)) ? 
 		    (isset(LISTAMBIGUOUS) ? 3 : 2) : 0) : 1);
@@ -283,14 +290,19 @@ do_completion(Hookdef dummy, Compldat dat)
 	opm = comppatmatch = ztrdup(useglob ? "*" : "");
 	zsfree(comppatinsert);
 	comppatinsert = ztrdup("menu");
-	zsfree(compforcelist);
-	compforcelist = ztrdup("");
+	forcelist = 0;
 	haspattern = 0;
 	complistmax = getiparam("LISTMAX");
 	zsfree(complastprompt);
-	complastprompt = ztrdup(((isset(ALWAYSLASTPROMPT) && zmult == 1) ||
-				(unset(ALWAYSLASTPROMPT) && zmult != 1)) ?
+	complastprompt = ztrdup((dolastprompt =
+				 ((isset(ALWAYSLASTPROMPT) && zmult == 1) ||
+				  (unset(ALWAYSLASTPROMPT) && zmult != 1))) ?
 				"yes" : "");
+	zsfree(complist);
+	complist = ztrdup(isset(LISTROWSFIRST) ?
+			  (isset(LISTPACKED) ? "packed rows" : "rows") :
+			  (isset(LISTPACKED) ? "packed" : ""));
+	startauto = isset(AUTOMENU);
 	movetoend = ((cs == we || isset(ALWAYSTOEND)) ? 2 : 1);
 	showinglist = 0;
 	hasmatched = 0;
@@ -360,7 +372,7 @@ do_completion(Hookdef dummy, Compldat dat)
 	    menucmp = 0;
 	    minfo.cur = NULL;
 
-	    if (compforcelist && *compforcelist && uselist)
+	    if (forcelist)
 		showinglist = -2;
 	    else
 		invalidatelist();
@@ -378,7 +390,7 @@ do_completion(Hookdef dummy, Compldat dat)
 		minfo.cur = NULL;
 		minfo.asked = 0;
 		do_single(m->matches[0]);
-		if (compforcelist && *compforcelist) {
+		if (forcelist) {
 		    if (uselist)
 			showinglist = -2;
 		    else
@@ -388,7 +400,7 @@ do_completion(Hookdef dummy, Compldat dat)
 	    }
 	} else {
 	    invalidatelist();
-	    if (compforcelist && *compforcelist)
+	    if (forcelist)
 		clearlist = 1;
 	    cs = 0;
 	    foredel(ll);
@@ -450,7 +462,7 @@ before_complete(Hookdef dummy, int *lst)
 
     /* Check if we have to start a menu-completion (via automenu). */
 
-    if (isset(AUTOMENU) && lastambig &&
+    if (startauto && lastambig &&
 	(!isset(BASHAUTOLIST) || lastambig == 2))
 	usemenu = 2;
 
@@ -495,7 +507,7 @@ callcompfunc(char *s, char *fn)
 	rset = CP_ALLREALS;
 	kset = CP_ALLKEYS &
 	    ~(CP_PARAMETER | CP_REDIRECT | CP_QUOTE | CP_QUOTING |
-	      CP_EXACTSTR | CP_FORCELIST | CP_OLDLIST | CP_OLDINS |
+	      CP_EXACTSTR | CP_OLDLIST | CP_OLDINS |
 	      (useglob ? 0 : CP_PATMATCH));
 	zsfree(compvared);
 	if (varedarg) {
@@ -641,11 +653,20 @@ callcompfunc(char *s, char *fn)
 	case 2: complist = "autolist"; break;
 	case 3: complist = "ambiguous"; break;
 	}
+	if (isset(LISTPACKED))
+	    complist = dyncat(complist, " packed");
+	if (isset(LISTROWSFIRST))
+	    complist = dyncat(complist, " rows");
+
 	complist = ztrdup(complist);
 	zsfree(compinsert);
 	if (useline) {
 	    switch (usemenu) {
-	    case 0: compinsert = "unambiguous"; break;
+	    case 0:
+		compinsert = (isset(AUTOMENU) ?
+			      "automenu-unambiguous" :
+			      "unambiguous");
+		break;
 	    case 1: compinsert = "menu"; break;
 	    case 2: compinsert = "automenu"; break;
 	    }
@@ -722,13 +743,14 @@ callcompfunc(char *s, char *fn)
 	    uselist = 3;
 	else
 	    uselist = 0;
-
+	forcelist = (complist && strstr(complist, "force"));
 	onlyexpl = (complist && strstr(complist, "expl"));
 
 	if (!compinsert)
 	    useline = 0;
 	else if (!strcmp(compinsert, "unambig") ||
-		 !strcmp(compinsert, "unambiguous"))
+		 !strcmp(compinsert, "unambiguous") ||
+		 !strcmp(compinsert, "automenu-unambiguous"))
 	    useline = 1, usemenu = 0;
 	else if (!strcmp(compinsert, "menu"))
 	    useline = 1, usemenu = 1;
@@ -749,6 +771,8 @@ callcompfunc(char *s, char *fn)
 	    insspace = (compinsert[strlen(compinsert) - 1] == ' ');
 	} else
 	    useline = usemenu = 0;
+	startauto = (compinsert &&
+		     !strcmp(compinsert, "automenu-unambiguous"));
 	useexact = (compexact && !strcmp(compexact, "accept"));
 
 	if (!comptoend || !*comptoend)
@@ -1545,6 +1569,8 @@ addmatches(Cadata dat, char **argv)
     qipre = ztrdup(compqiprefix ? compqiprefix : "");
     qisuf = ztrdup(compqisuffix ? compqisuffix : "");
 
+    useexact = (compexact && !strcmp(compexact, "accept"));
+
     /* Switch back to the heap that was used when the completion widget
      * was invoked. */
     SWITCHHEAPS(compheap) {
@@ -2075,7 +2101,11 @@ add_match_data(int alt, char *str, Cline line,
 	cm->isuf = (isuf && *isuf ? isuf : NULL);
     cm->pre = pre;
     cm->suf = suf;
-    cm->flags = flags;
+    cm->flags = (flags |
+		 (complist ?
+		  ((strstr(complist, "packed") ? CMF_PACKED : 0) |
+		   (strstr(complist, "rows")   ? CMF_ROWS   : 0)) : 0));
+
     if ((*compqstack == '\\' && compqstack[1]) ||
 	(autoq && *compqstack && compqstack[1] == '\\'))
 	cm->flags |= CMF_NOSPACE;
@@ -2117,6 +2147,8 @@ add_match_data(int alt, char *str, Cline line,
 
     newmatches = 1;
 
+    if (!complastprompt || !*complastprompt)
+	dolastprompt = 0;
     /* One more match for this explanation. */
     if (curexpl) {
 	if (alt)
@@ -2140,8 +2172,8 @@ add_match_data(int alt, char *str, Cline line,
     /* Do we have an exact match? More than one? */
     if (exact) {
 	if (!ai->exact) {
-	    ai->exact = 1;
-	    if (incompfunc) {
+	    ai->exact = useexact;
+	    if (incompfunc && (!compexactstr || !*compexactstr)) {
 		/* If a completion widget is active, we make the exact
 		 * string available in `compstate'. */
 
@@ -2160,7 +2192,7 @@ add_match_data(int alt, char *str, Cline line,
 		comp_setunset(0, 0, CP_EXACTSTR, 0);
 	    }
 	    ai->exactm = cm;
-	} else {
+	} else if (useexact) {
 	    ai->exact = 2;
 	    ai->exactm = NULL;
 	    if (incompfunc)
diff --git a/Src/Zle/complete.c b/Src/Zle/complete.c
index 416ebfff7..a78a12058 100644
--- a/Src/Zle/complete.c
+++ b/Src/Zle/complete.c
@@ -66,7 +66,6 @@ char *compiprefix,
      *compquoting,
      *comprestore,
      *complist,
-     *compforcelist,
      *compinsert,
      *compexact,
      *compexactstr,
@@ -948,7 +947,6 @@ static struct compparam compkparams[] = {
     { "quoting", PM_SCALAR | PM_READONLY, VAL(compquoting), NULL, NULL },
     { "restore", PM_SCALAR, VAL(comprestore), NULL, NULL },
     { "list", PM_SCALAR, NULL, VAL(set_complist), VAL(get_complist) },
-    { "force_list", PM_SCALAR, VAL(compforcelist), NULL, NULL },
     { "insert", PM_SCALAR, VAL(compinsert), NULL, NULL },
     { "exact", PM_SCALAR, VAL(compexact), NULL, NULL },
     { "exact_string", PM_SCALAR, VAL(compexactstr), NULL, NULL },
@@ -1363,8 +1361,8 @@ setup_complete(Module m)
 	compcontext = compparameter = compredirect = compquote =
 	compquoting = comprestore = complist = compinsert =
 	compexact = compexactstr = comppatmatch = comppatinsert =
-	compforcelist = complastprompt = comptoend = 
-	compoldlist = compoldins = compvared = compqstack = NULL;
+	complastprompt = comptoend = compoldlist = compoldins =
+	compvared = compqstack = NULL;
 
     hascompmod = 1;
 
@@ -1431,7 +1429,6 @@ finish_complete(Module m)
     zsfree(compquoting);
     zsfree(comprestore);
     zsfree(complist);
-    zsfree(compforcelist);
     zsfree(compinsert);
     zsfree(compexact);
     zsfree(compexactstr);
diff --git a/Src/Zle/compresult.c b/Src/Zle/compresult.c
index bdafa3059..4aa171ea1 100644
--- a/Src/Zle/compresult.c
+++ b/Src/Zle/compresult.c
@@ -586,7 +586,7 @@ do_ambiguous(void)
     /* If we have to insert the first match, call do_single().  This is *
      * how REC_EXACT takes effect.  We effectively turn the ambiguous   *
      * completion into an unambiguous one.                              */
-    if (ainfo && ainfo->exact == 1 && useexact && !(fromcomp & FC_LINE)) {
+    if (ainfo && ainfo->exact == 1 && !(fromcomp & FC_LINE)) {
 	minfo.cur = NULL;
 	do_single(ainfo->exactm);
 	invalidatelist();
@@ -669,7 +669,7 @@ do_ambiguous(void)
     if (uselist && (usemenu != 2 || (!listshown && !oldlist)) &&
 	((!showinglist && (!listshown || !oldlist)) ||
 	 (usemenu == 3 && !oldlist)) &&
-	(smatches >= 2 || (compforcelist && *compforcelist)))
+	(smatches >= 2 || forcelist))
 	showinglist = -2;
 
     return ret;
@@ -1151,6 +1151,8 @@ calclist(void)
 	char **pp = g->ylist;
 	int nl = 0, l, glong = 1, gshort = columns, ndisp = 0, totl = 0;
 
+	g->flags |= CGF_PACKED | CGF_ROWS;
+
 	if (!onlyexpl && pp) {
 	    /* We have an ylist, lets see, if it contains newlines. */
 	    hidden = 1;
@@ -1211,6 +1213,10 @@ calclist(void)
 			mlens[m->gnum] = l;
 		    }
 		    nlist++;
+		    if (!(m->flags & CMF_PACKED))
+			g->flags &= ~CGF_PACKED;
+		    if (!(m->flags & CMF_ROWS))
+			g->flags &= ~CGF_ROWS;
 		} else if (!(m->flags & CMF_NOLIST)) {
 		    l = niceztrlen(m->str);
 		    ndisp++;
@@ -1221,6 +1227,10 @@ calclist(void)
 		    totl += l;
 		    mlens[m->gnum] = l;
 		    nlist++;
+		    if (!(m->flags & CMF_PACKED))
+			g->flags &= ~CGF_PACKED;
+		    if (!(m->flags & CMF_ROWS))
+			g->flags &= ~CGF_ROWS;
 		} else
 		    hidden = 1;
 	    }
@@ -1289,11 +1299,14 @@ calclist(void)
 	    nlines += glines;
 	}
     }
-    if (!onlyexpl && isset(LISTPACKED)) {
+    if (!onlyexpl) {
 	char **pp;
 	int *ws, tlines, tline, tcols, maxlen, nth, width;
 
 	for (g = amatches; g; g = g->next) {
+	    if (!(g->flags & CGF_PACKED))
+		continue;
+
 	    ws = g->widths = (int *) zalloc(columns * sizeof(int));
 	    memset(ws, 0, columns * sizeof(int));
 	    tlines = g->lins;
@@ -1308,7 +1321,7 @@ calclist(void)
 		    for (i = 0; *pp; i++, pp++)
 			ylens[i] = strlen(*pp) + add;
 
-		    if (isset(LISTROWSFIRST)) {
+		    if (g->flags & CGF_ROWS) {
 			int count, tcol, first, maxlines = 0, llines;
 
 			for (tcols = columns / g->shortest; tcols > g->cols;
@@ -1366,7 +1379,7 @@ calclist(void)
 		    }
 		}
 	    } else if (g->width) {
-		if (isset(LISTROWSFIRST)) {
+		if (g->flags & CGF_ROWS) {
 		    int addlen, count, tcol, maxlines = 0, llines, i;
 		    Cmatch *first;
 
@@ -1477,12 +1490,12 @@ int asklist(void)
     trashzle();
     showinglist = listshown = 0;
 
-    clearflag = (isset(USEZLE) && !termflags &&
-		 complastprompt && *complastprompt);
+    clearflag = (isset(USEZLE) && !termflags && dolastprompt);
 
     /* Maybe we have to ask if the user wants to see the list. */
     if ((!minfo.cur || !minfo.asked) &&
-	((complistmax && listdat.nlist > complistmax) ||
+	((complistmax > 0 && listdat.nlist >= complistmax) ||
+	 (complistmax < 0 && listdat.nlines <= -complistmax) ||
 	 (!complistmax && listdat.nlines >= lines))) {
 	int qup;
 	zsetterm();
@@ -1599,7 +1612,7 @@ printlist(int over, CLPrintFunc printm)
 			    while (a--)
 				putc(' ', shout);
 			}
-			pq += (isset(LISTROWSFIRST) ? 1 : nc);
+			pq += ((g->flags & CGF_ROWS) ? 1 : nc);
 			mc++;
 			n--;
 		    }
@@ -1612,7 +1625,7 @@ printlist(int over, CLPrintFunc printm)
 				tcout(TCCLEAREOD);
 			}
 		    }
-		    pp += (isset(LISTROWSFIRST) ? g->cols : 1);
+		    pp += ((g->flags & CGF_ROWS) ? g->cols : 1);
 		}
 	    }
 	} else if (!listdat.onlyexpl && g->lcount) {
@@ -1678,7 +1691,8 @@ printlist(int over, CLPrintFunc printm)
 		    printed++;
 
 		    if (--n)
-			for (j = (isset(LISTROWSFIRST) ? 1 : nc); j && *q; j--)
+			for (j = ((g->flags & CGF_ROWS) ? 1 : nc);
+			     j && *q; j--)
 			    q = skipnolist(q + 1);
 		    mc++;
 		}
@@ -1696,7 +1710,8 @@ printlist(int over, CLPrintFunc printm)
 			    tcout(TCCLEAREOD);
 		    }
 		    if (nl)
-			for (j = (isset(LISTROWSFIRST) ? g->cols : 1); j && *p; j--)
+			for (j = ((g->flags & CGF_ROWS) ? g->cols : 1);
+			     j && *p; j--)
 			    p = skipnolist(p + 1);
 		}
 	    }