zsh-workers
 help / color / mirror / code / Atom feed
* Re: PATCH: scrolling completion lists (was: Re: Questions)
@ 2000-04-18  7:34 Sven Wischnowsky
  2000-04-18  8:47 ` Peter Stephenson
  2000-04-18  9:16 ` Peter Stephenson
  0 siblings, 2 replies; 10+ messages in thread
From: Sven Wischnowsky @ 2000-04-18  7:34 UTC (permalink / raw)
  To: zsh-workers


Peter Stephenson wrote:

>
> ...
> 
> Maybe select-prompt is more consistent than select-status, which implies a
> returned value, although it should be the same as the parameter.
> 
> It occurs to me that you can display other stuff in this prompt, e.g. info
> about the currently selected file in menu-select mode.  But that's nothing
> to do with scrolling.

>:-> yesssss...


Anyway, this patch:

- Removes the (unused) `st' capability from ZLS_COLO(|U)RS.
- Renames LISTSTATUS to LISTPROMPT and SELECTSTATUS to SELECTPROMPT.
- Adds the styles list-prompt, select-prompt and select-scroll as an
  interface to the underlying parameters. All are tested (only) with
  the default tag.
  select-prompt has the default value suggested by Peter and
  list-prompt also turns on list-scrolling (and loads complist).
- Finally, the patch adds the `listscroll' keymap that is used when
  listing a completion lists that is too big for the screen and the
  shell is waiting at the list-prompt. It has some default bindings,
  but of course one can now use whatever keys one wants.


Bye
 Sven

Index: Completion/Builtins/_zstyle
===================================================================
RCS file: /cvsroot/zsh/zsh/Completion/Builtins/_zstyle,v
retrieving revision 1.6
diff -u -r1.6 _zstyle
--- Completion/Builtins/_zstyle	2000/04/17 08:22:44	1.6
+++ Completion/Builtins/_zstyle	2000/04/18 07:32:43
@@ -41,6 +41,7 @@
   list			 c:listwhen
   list-colors		 c:
   list-packed		 c:bool
+  list-prompt            c:
   list-rows-first	 c:bool
   local			 c:
   matcher-list		 c:
@@ -55,6 +56,8 @@
   prefix-needed		 c:bool
   prompt		 c:
   remove-all-dups	 c:bool
+  select-prompt          c:
+  select-scroll          c:
   single-ignored         c:single-ignored
   sort			 c:bool
   special-dirs		 c:sdirs
Index: Completion/Core/_main_complete
===================================================================
RCS file: /cvsroot/zsh/zsh/Completion/Core/_main_complete,v
retrieving revision 1.6
diff -u -r1.6 _main_complete
--- Completion/Core/_main_complete	2000/04/12 09:28:57	1.6
+++ Completion/Core/_main_complete	2000/04/18 07:32:43
@@ -56,6 +56,16 @@
                 )
 _last_menu_style=()
 
+if zstyle -s ":completion:${curcontext}:default" list-prompt LISTPROMPT &&
+   [[ -n "$LISTPROMPT" ]]; then
+  zmodload -i zsh/complist
+  compstate[list_max]=scroll
+fi
+zstyle -s ":completion:${curcontext}:default" select-prompt SELECTPROMPT ||
+    SELECTPROMPT='%SScrolling active: current selection at %p'
+zstyle -s ":completion:${curcontext}:default" select-scroll SELECTSCROLL ||
+    SELECTSCROLL=1
+
 # Get the names of the completers to use in the positional parameters.
 
 if (( $# )); then
Index: Doc/Zsh/compsys.yo
===================================================================
RCS file: /cvsroot/zsh/zsh/Doc/Zsh/compsys.yo,v
retrieving revision 1.18
diff -u -r1.18 compsys.yo
--- Doc/Zsh/compsys.yo	2000/04/17 08:22:44	1.18
+++ Doc/Zsh/compsys.yo	2000/04/18 07:32:44
@@ -1267,6 +1267,19 @@
 tt(LIST_PACKED) option were set for them. If it is set to `false',
 they are listed normally.
 )
+kindex(list-prompt, completion style)
+item(tt(list-prompt))(
+If this style is set to a non-empty value for the tt(default) tag,
+completion lists that don't fit on the screen can be scrolled (see
+ifzman(the description of the tt(zsh/complist) module in zmanref(zshmodules))\
+ifnzman(noderef(The zsh/complist Module))\
+). The value will be displayed after every screenful, prompting for a
+key and may contain the escape `tt(%l)' which will be replaced by the
+number of the last line displayed and the total number of lines. As
+usual, the `tt(%S)', `tt(%s)', `tt(%B)', `tt(%b)', `tt(%U)', `tt(%u)',
+and `tt(%{)...tt(%})' escapes for the terminal display modes are
+understood, too.
+)
 kindex(list-rows-first, completion style)
 item(tt(list-rows-first))(
 This style is tested like the tt(list-packed) style and determines if
@@ -1558,6 +1571,28 @@
 The tt(_history_complete_word) bindable command uses this to decide if 
 all duplicate matches should be removed, rather than just consecutive
 duplicates.
+)
+kindex(select-prompt, completion style)
+item(tt(select-prompt))(
+If this is set to a non-empty string for the tt(default) tag, its
+value will be displayed during menu-selection (see the tt(menu) style
+above) when the completion list does not fit on the screen as a
+whole. The same escapes as for the tt(list-prompt) style are
+understood, plus `tt(%m)' which is replaced by the number of the
+currently selected match and the total number of matches and `tt(%p)'
+which is replaced by `tt(Top)' when the mark is on the first line,
+`tt(Bottom)' when it is on the last line and the relative position of
+the mark in the list given as a percentage.
+)
+kindex(select-scroll, completion style)
+item(tt(select-scroll))(
+This style is tested for the tt(default) tag and determines how a
+completion list is scrolled during a menu-selection (see the tt(menu)
+style above) when the completion list does not fit on the screen as a
+whole. Its value should be `tt(0)' (zero) to scroll by
+half-screenfuls, a positive integer to scroll by that many lines and a
+negative number to scroll by the number of lines of the screen minus
+that number (or plus the number, since it is negative).
 )
 kindex(single-ignored, completion style)
 item(tt(single-ignored))(
Index: Doc/Zsh/compwid.yo
===================================================================
RCS file: /cvsroot/zsh/zsh/Doc/Zsh/compwid.yo,v
retrieving revision 1.4
diff -u -r1.4 compwid.yo
--- Doc/Zsh/compwid.yo	2000/04/12 09:12:16	1.4
+++ Doc/Zsh/compwid.yo	2000/04/18 07:32:45
@@ -247,7 +247,7 @@
 vindex(list_max, compstate)
 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
+It may be set to any other value; when the widget exits this value
 will be used in the same way as the value of tt(LISTMAX).
 )
 vindex(list_lines, compstate)
Index: Doc/Zsh/mod_complist.yo
===================================================================
RCS file: /cvsroot/zsh/zsh/Doc/Zsh/mod_complist.yo,v
retrieving revision 1.2
diff -u -r1.2 mod_complist.yo
--- Doc/Zsh/mod_complist.yo	2000/04/17 11:17:10	1.2
+++ Doc/Zsh/mod_complist.yo	2000/04/18 07:32:46
@@ -133,26 +133,30 @@
 parameter has to be set to the string `tt(scroll)'. If it has this
 value, the completion code will not ask if the list should be
 shown. Instead it immediately starts displaying the list, stopping
-after the first screenful, showing a simple prompt at the bottom,
-waiting for a keypress. The following keys have a special meaning:
+after the first screenful, showing a prompt at the bottom,
+waiting for a keypress after temporarily switching to the
+tt(listscroll) keymap. Some of the zle functions have special meaning:
 
 startitem()
-item(tt(Space), tt(Tab))(
-scroll forward one screenful
+item(tt(send-break))(
+stops listing discarding the key pressed
 )
-item(tt(Return), tt(Newline))(
-scroll forward one line
+xitem(tt(accept-line), tt(down-history), tt(down-line-or-history))
+item(tt(down-line-or-search), tt(vi-down-line-or-history))(
+scrolls forward one line
 )
-item(tt(q))(
-stops listing and redisplays the command line without inserting the
-`tt(q)'
+item(tt(complete-word), tt(menu-complete), tt(expand-or-complete))(
+item(tt(expand-or-complete-prefix), tt(menu-complete-or-expand))(
+scrolls forward one screenful
 )
 enditem()
 
 Every other character stops listing and immediately processes the key
-as usual.
+as usual. Any key that is not bound in the tt(listscroll) keymap or
+that is bound to tt(undefined-key) is looked up in the keymap
+currently selected.
 
-If the parameter tt(LISTSTATUS) is set, its value will be used as the
+If the parameter tt(LISTPROMPT) is set, its value will be used as the
 prompt.  The value may contain escapes of the form `tt(%x)'. It
 supports the escapes `tt(%B)', `tt(%b)', `tt(%S)', `tt(%s)', `tt(%U)',
 `tt(%u)' and `tt(%{...%})' known from the shell prompts and the
@@ -160,6 +164,11 @@
 last line shown and the total number of lines in the form
 `var(number)tt(/)var(total)'.
 
+As for the tt(ZLS_COLORS) and tt(ZLS_COLOURS) parameters,
+tt(LISTPROMPT) should not be set directly when using the shell
+function based completion system. Instead, the tt(list-prompt) style
+should be used.
+
 subsect(Menu selection)
 cindex(completion, selecting by cursor)
 vindex(SELECTMIN)
@@ -197,9 +206,9 @@
 control sequence as for the `tt(%S)' escape in prompts is used.
 
 If there are more matches than fit on the screen and the parameter
-tt(SELECTSTATUS) is set, its value will be shown below the
+tt(SELECTPROMPT) is set, its value will be shown below the
 matches. Next to the escape sequences understood for the
-tt(LISTSTATUS) parameter, a `tt(%m)' will be replaced by a string
+tt(LISTPROMPT) parameter, a `tt(%m)' will be replaced by a string
 containing the number of the match the mark is on and the total number 
 of matches in the form `var(number)tt(/)var(total)' and the sequence
 `tt(%p)' will be replaced with `tt(Top)', `tt(Bottom)' or the position
@@ -210,8 +219,14 @@
 scrolled. If the parameter is unset, this is done line by line, if it
 is set to `tt(0)' (zero), the list will scrolled half the number of
 lines of the screen. If the value is positive, it gives the number of
-lines to scroll and if it is negative, the list will be scrolled one
+lines to scroll and if it is negative, the list will be scrolled
 the number of lines of the screen minus the (absolute) value.
+
+As for the tt(ZLS_COLORS), tt(ZLS_COLOURS) and tt(LISTPROMPT)
+parameters, neither tt(SELECTPROMPT) nor tt(SELECTSCROLL) should be
+set directly when using the shell function based completion
+system. Instead, the tt(select-prompt) and tt(select-scroll) styles
+should be used.
 
 The completion code sometimes decides not to show all of the matches
 in the list. These hidden matches are either matches for which the
Index: Src/Zle/complist.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Zle/complist.c,v
retrieving revision 1.2
diff -u -r1.2 complist.c
--- Src/Zle/complist.c	2000/04/17 11:17:10	1.2
+++ Src/Zle/complist.c	2000/04/18 07:32:46
@@ -37,7 +37,7 @@
 
 
 static Widget w_menuselect;
-static Keymap mskeymap;
+static Keymap mskeymap, lskeymap;
 
 /* Indixes into the terminal string arrays. */
 
@@ -59,9 +59,8 @@
 #define COL_MA 15
 #define COL_HI 16
 #define COL_DU 17
-#define COL_ST 18
 
-#define NUM_COLS 19
+#define NUM_COLS 18
 
 /* Maximum number of in-string colours supported. */
 
@@ -71,14 +70,14 @@
 
 static char *colnames[] = {
     "no", "fi", "di", "ln", "pi", "so", "bd", "cd", "ex", "mi",
-    "lc", "rc", "ec", "tc", "sp", "ma", "hi", "du", "st", NULL
+    "lc", "rc", "ec", "tc", "sp", "ma", "hi", "du", NULL
 };
 
 /* Default values. */
 
 static char *defcols[] = {
     "0", "0", "1;34", "1;36", "33", "1;35", "1;33", "1;33", "1;32", NULL,
-    "\033[", "m", NULL, "0", "0", "7", "0", "0", "7"
+    "\033[", "m", NULL, "0", "0", "7", "0", "0"
 };
 
 /* This describes a terminal string for a file type. */
@@ -347,12 +346,9 @@
 	
 	if ((s = tcstr[TCSTANDOUTBEG]) && s[0]) {
 	    c->files[COL_MA] = filecol(s);
-	    c->files[COL_ST] = filecol(s);
 	    c->files[COL_EC] = filecol(tcstr[TCSTANDOUTEND]);
-	} else {
+	} else
 	    c->files[COL_MA] = filecol(defcols[COL_MA]);
-	    c->files[COL_ST] = filecol(defcols[COL_ST]);
-	}
 	lr_caplen = 0;
 	if ((max_caplen = strlen(c->files[COL_MA]->col)) <
 	    (l = strlen(c->files[COL_EC]->col)))
@@ -657,32 +653,46 @@
 static int
 asklistscroll(int ml)
 {
-    int v, i;
+    Thingy cmd;
+    int i, ret = 0;
 
     compprintfmt(NULL, -1, 1, 1, ml, NULL);
 
     fflush(shout);
     zsetterm();
-    v = getzlequery(0);
+    selectlocalmap(lskeymap);
+    if (!(cmd = getkeycmd()) || cmd == Th(z_sendbreak))
+	ret = 1;
+    else if (cmd == Th(z_acceptline) ||
+	     cmd == Th(z_downhistory) ||
+	     cmd == Th(z_downlineorhistory) ||
+	     cmd == Th(z_downlineorsearch) ||
+	     cmd == Th(z_vidownlineorhistory))
+	mrestlines = 1;
+    else if (cmd == Th(z_completeword) ||
+		   cmd == Th(z_expandorcomplete) ||
+		   cmd == Th(z_expandorcompleteprefix) ||
+		   cmd == Th(z_menucomplete) ||
+		   cmd == Th(z_menuexpandorcomplete) ||
+		   !strcmp(cmd->nam, "menu-select") ||
+		   !strcmp(cmd->nam, "complete-word") ||
+		   !strcmp(cmd->nam, "expand-or-complete") ||
+		   !strcmp(cmd->nam, "expand-or-complete-prefix") ||
+		   !strcmp(cmd->nam, "menu-complete") ||
+	     !strcmp(cmd->nam, "menu-expand-or-complete"))
+	mrestlines = lines - 1;
+    else {
+	ungetkeycmd();
+	ret = 1;
+    }
+    selectlocalmap(NULL);
     settyinfo(&shttyinfo);
     putc('\r', shout);
     for (i = columns - 1; i--; )
 	putc(' ', shout);
-
     putc('\r', shout);
-
-    if (v == '\n' || v == '\r') {
-	mrestlines = 1;
-	return 0;
-    }
-    mrestlines = lines - 1;
 
-    if (v == ' ' || v == '\t')
-	return 0;
-    if (v != 'q')
-	ungetkey(v);
-
-    return 1;
+    return ret;
 }
 
 #define dolist(X)   ((X) >= mlbeg && (X) < mlend)
@@ -720,8 +730,8 @@
 	    if (!(fmt = mstatus))
 		return 0;
 	    cc = -1;
-	} else if (!(fmt = getsparam("LISTSTATUS")))
-	    fmt = "continue? ";
+	} else if (!(fmt = getsparam("LISTPROMPT")))
+	    fmt = "Continue? ";
     }
     for (p = fmt; *p; p++) {
 	if (doesc && *p == '%') {
@@ -1417,7 +1427,7 @@
     mscroll = 0;
 
     if (mselect >= 0 || mlbeg >= 0 ||
-	((p = getsparam("LISTMAX")) && !strcmp(p, "scroll"))) {
+	((p = complistmax) && !strcmp(p, "scroll"))) {
 	trashzle();
 	showinglist = listshown = 0;
 
@@ -1536,8 +1546,8 @@
 	    if ((step += lines - nlnct) < 0)
 		step = 1;
     }
-    mstatus = getsparam("SELECTSTATUS");
-    mhasstat = !!mstatus;
+    mstatus = getsparam("SELECTPROMPT");
+    mhasstat = (mstatus && *mstatus);
     fdat = dat;
     selectlocalmap(mskeymap);
     noselect = 0;
@@ -2054,6 +2064,14 @@
     bindkey(mskeymap, "\33OB",  refthingy(t_downlineorhistory), NULL);
     bindkey(mskeymap, "\33OC",  refthingy(t_forwardchar), NULL);
     bindkey(mskeymap, "\33OD",  refthingy(t_backwardchar), NULL);
+    lskeymap = newkeymap(NULL, "listscroll");
+    linkkeymap(lskeymap, "listscroll", 1);
+    bindkey(lskeymap, "\t", refthingy(t_completeword), NULL);
+    bindkey(lskeymap, " ", refthingy(t_completeword), NULL);
+    bindkey(lskeymap, "\n", refthingy(t_acceptline), NULL);
+    bindkey(lskeymap, "\r", refthingy(t_acceptline), NULL);
+    bindkey(lskeymap, "\33[B",  refthingy(t_downlineorhistory), NULL);
+    bindkey(lskeymap, "\33OB",  refthingy(t_downlineorhistory), NULL);
     return 0;
 }
 
@@ -2068,6 +2086,7 @@
     deletehookfunc("comp_list_matches", (Hookfn) complistmatches);
     deletehookfunc("menu_start", (Hookfn) domenuselect);
     unlinkkeymap("menuselect", 1);
+    unlinkkeymap("listscroll", 1);
     return 0;
 }
 

--
Sven Wischnowsky                         wischnow@informatik.hu-berlin.de


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: PATCH: scrolling completion lists (was: Re: Questions)
  2000-04-18  7:34 PATCH: scrolling completion lists (was: Re: Questions) Sven Wischnowsky
@ 2000-04-18  8:47 ` Peter Stephenson
  2000-04-18  9:16 ` Peter Stephenson
  1 sibling, 0 replies; 10+ messages in thread
From: Peter Stephenson @ 2000-04-18  8:47 UTC (permalink / raw)
  To: Zsh hackers list

> +item(tt(complete-word), tt(menu-complete), tt(expand-or-complete))(
> +item(tt(expand-or-complete-prefix), tt(menu-complete-or-expand))(
> +scrolls forward one screenful
>  )

Index: Doc/Zsh/mod_complist.yo
===================================================================
RCS file: /cvsroot/zsh/zsh/Doc/Zsh/mod_complist.yo,v
retrieving revision 1.3
diff -u -r1.3 mod_complist.yo
--- Doc/Zsh/mod_complist.yo	2000/04/18 07:36:56	1.3
+++ Doc/Zsh/mod_complist.yo	2000/04/18 08:45:49
@@ -145,7 +145,7 @@
 item(tt(down-line-or-search), tt(vi-down-line-or-history))(
 scrolls forward one line
 )
-item(tt(complete-word), tt(menu-complete), tt(expand-or-complete))(
+xitem(tt(complete-word), tt(menu-complete), tt(expand-or-complete))
 item(tt(expand-or-complete-prefix), tt(menu-complete-or-expand))(
 scrolls forward one screenful
 )

-- 
Peter Stephenson <pws@cambridgesiliconradio.com>
Cambridge Silicon Radio, Unit 300, Science Park, Milton Road,
Cambridge, CB4 0XL, UK                          Tel: +44 (0)1223 392070


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: PATCH: scrolling completion lists (was: Re: Questions)
  2000-04-18  7:34 PATCH: scrolling completion lists (was: Re: Questions) Sven Wischnowsky
  2000-04-18  8:47 ` Peter Stephenson
@ 2000-04-18  9:16 ` Peter Stephenson
  1 sibling, 0 replies; 10+ messages in thread
From: Peter Stephenson @ 2000-04-18  9:16 UTC (permalink / raw)
  To: Zsh hackers list

Some other minor comments on scrolling, which I'm not suggesting any
immediate action on:

- the %l in list-prompt adds some spaces after it, so a message like
  `listing completions at %l, space to scroll'
  looks a little messy
- maybe it would be better if this one understood %p, too, just for
  consistency
- maybe there should likewise by a (different) default prompt here, too
- I understand the need for the difference between scrolling in listing and
  in menu selection, but (this is basically what Zefram was saying) we need
  to keep it as intuitive as possible.  So for example I'm not necessarily
  yet convinced that it would be a bad thing to be able to scroll backwards
  in the completion list form (given this is already in the code).

-- 
Peter Stephenson <pws@cambridgesiliconradio.com>
Cambridge Silicon Radio, Unit 300, Science Park, Milton Road,
Cambridge, CB4 0XL, UK                          Tel: +44 (0)1223 392070


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: PATCH: scrolling completion lists (was: Re: Questions)
@ 2000-04-19  6:47 Sven Wischnowsky
  0 siblings, 0 replies; 10+ messages in thread
From: Sven Wischnowsky @ 2000-04-19  6:47 UTC (permalink / raw)
  To: zsh-workers


Peter Stephenson wrote:

> Some other minor comments on scrolling, which I'm not suggesting any
> immediate action on:
> 
> - the %l in list-prompt adds some spaces after it, so a message like
>   `listing completions at %l, space to scroll'
>   looks a little messy

The patch adds %[MLP] as you suggested. To repeat: the uppercase forms 
used fixed widths, the lowercase ones don't

> - maybe it would be better if this one understood %p, too, just for
>   consistency

Done. Even %m is allowed.

> - maybe there should likewise by a (different) default prompt here, too

There is now a default in shell code. If one doesn't want to use
scrolling, one can set the list-prompt style to an empty string.

> - I understand the need for the difference between scrolling in listing and
>   in menu selection, but (this is basically what Zefram was saying) we need
>   to keep it as intuitive as possible.  So for example I'm not necessarily
>   yet convinced that it would be a bad thing to be able to scroll backwards
>   in the completion list form (given this is already in the code).

I have not done that yet, because I wasn't sure how to do this
best. Currently even scrolled lists use only very simple terminal
stuff, i.e. it should work everywhere and on an xterm one can use the
terminal's scrolling feature to scroll back.
If we want to support going back in a non-menu-selection list, this
would have to be changed one way or the other. The simplest solution
would be to just output the previous screenful (without moving the
cursor up before that). But that looks like doing it in a way we could 
do better.
So maybe we would want to make this much more like the way menu-select 
does it (that would also be easiest to implement). We could probably
use the current implementation as a fallback for dumb terminals.
If we do it like menu-select, should we also try to keep the prompt on 
the screen, so that alwayslastprompt puts the cursor back on it?
Or should we use alwayslastprompt to toggle between listing as in
menu-select (with going back to the prompt etc.) and the style we have 
now (with alwayslastprompt unset, obviously)? Hm, that actually seems
to make sense...

Bye
 Sven

Index: Completion/Core/_main_complete
===================================================================
RCS file: /cvsroot/zsh/zsh/Completion/Core/_main_complete,v
retrieving revision 1.7
diff -u -r1.7 _main_complete
--- Completion/Core/_main_complete	2000/04/18 07:36:56	1.7
+++ Completion/Core/_main_complete	2000/04/19 06:45:34
@@ -56,8 +56,9 @@
                 )
 _last_menu_style=()
 
-if zstyle -s ":completion:${curcontext}:default" list-prompt LISTPROMPT &&
-   [[ -n "$LISTPROMPT" ]]; then
+zstyle -s ":completion:${curcontext}:default" list-prompt LISTPROMPT ||
+    LISTPROMPT='Current position at %P    Continue? '
+if [[ -n "$LISTPROMPT" ]]; then
   zmodload -i zsh/complist
   compstate[list_max]=scroll
 fi
Index: Doc/Zsh/compsys.yo
===================================================================
RCS file: /cvsroot/zsh/zsh/Doc/Zsh/compsys.yo,v
retrieving revision 1.19
diff -u -r1.19 compsys.yo
--- Doc/Zsh/compsys.yo	2000/04/18 07:36:56	1.19
+++ Doc/Zsh/compsys.yo	2000/04/19 06:45:35
@@ -1274,11 +1274,21 @@
 ifzman(the description of the tt(zsh/complist) module in zmanref(zshmodules))\
 ifnzman(noderef(The zsh/complist Module))\
 ). The value will be displayed after every screenful, prompting for a
-key and may contain the escape `tt(%l)' which will be replaced by the
-number of the last line displayed and the total number of lines. As
+key press. It may contain the escape `tt(%l)' or `tt(%L)' which will be
+replaced by the number of the last line displayed and the total number
+of lines. A `tt(%m)' or `tt(%M)' will be replaced by the number of the 
+last match shown and the total number of matches and `tt(%p)' and
+`tt(%P)' will be replaced by `tt(Top)' when at the beginning of the
+list, `tt(Bottom)' when at the end and the position shown in percent
+of the total length. In each of these cases the form with the
+uppercase letter is replaced by a string of fixed width, padded to the 
+right with spaces. As
 usual, the `tt(%S)', `tt(%s)', `tt(%B)', `tt(%b)', `tt(%U)', `tt(%u)',
 and `tt(%{)...tt(%})' escapes for the terminal display modes are
 understood, too.
+
+Note that this style has a default value. If you don't want to use
+scrolling, set this style to an empty string.
 )
 kindex(list-rows-first, completion style)
 item(tt(list-rows-first))(
@@ -1578,11 +1588,7 @@
 value will be displayed during menu-selection (see the tt(menu) style
 above) when the completion list does not fit on the screen as a
 whole. The same escapes as for the tt(list-prompt) style are
-understood, plus `tt(%m)' which is replaced by the number of the
-currently selected match and the total number of matches and `tt(%p)'
-which is replaced by `tt(Top)' when the mark is on the first line,
-`tt(Bottom)' when it is on the last line and the relative position of
-the mark in the list given as a percentage.
+understood, but give the number of the match or line the mark is on.
 )
 kindex(select-scroll, completion style)
 item(tt(select-scroll))(
Index: Doc/Zsh/mod_complist.yo
===================================================================
RCS file: /cvsroot/zsh/zsh/Doc/Zsh/mod_complist.yo,v
retrieving revision 1.4
diff -u -r1.4 mod_complist.yo
--- Doc/Zsh/mod_complist.yo	2000/04/18 08:50:13	1.4
+++ Doc/Zsh/mod_complist.yo	2000/04/19 06:45:35
@@ -159,10 +159,16 @@
 If the parameter tt(LISTPROMPT) is set, its value will be used as the
 prompt.  The value may contain escapes of the form `tt(%x)'. It
 supports the escapes `tt(%B)', `tt(%b)', `tt(%S)', `tt(%s)', `tt(%U)',
-`tt(%u)' and `tt(%{...%})' known from the shell prompts and the
-additional sequence `tt(%l)' which is replaced by the number of the
-last line shown and the total number of lines in the form
-`var(number)tt(/)var(total)'.
+`tt(%u)' and `tt(%{...%})' known from the shell prompts and three
+pairs of additional sequences. A `tt(%l)' or `tt(%L)' is replaced by
+the number of the last line shown and the total number of lines in the form
+`var(number)tt(/)var(total)'. A `tt(%m)' or `tt(%M)' is replaced with
+the number of the last match shown and the total number of matches and 
+`tt(%p)' or `tt(%P)' is replaced with `tt(Top)', `tt(Bottom)' or the
+position of the first line shown in percent of the total number of
+lines, respectively. In each of these cases the one with the uppercase 
+letter will be replaced with a string of fixed width, padded to the
+right with spaces.
 
 As for the tt(ZLS_COLORS) and tt(ZLS_COLOURS) parameters,
 tt(LISTPROMPT) should not be set directly when using the shell
@@ -207,13 +213,9 @@
 
 If there are more matches than fit on the screen and the parameter
 tt(SELECTPROMPT) is set, its value will be shown below the
-matches. Next to the escape sequences understood for the
-tt(LISTPROMPT) parameter, a `tt(%m)' will be replaced by a string
-containing the number of the match the mark is on and the total number 
-of matches in the form `var(number)tt(/)var(total)' and the sequence
-`tt(%p)' will be replaced with `tt(Top)', `tt(Bottom)' or the position
-in percent of the total size when the mark is in the first line, in
-the last line or somewhere in between, respectively.
+matches. It supports the sames escape sequences as tt(LISTPROMPT), but 
+the number of the match or line shown will be that of the one where
+the mark is placed.
 
 The tt(SELECTSCROLL) parameter can be used to specify how the list is
 scrolled. If the parameter is unset, this is done line by line, if it
Index: Src/Zle/complist.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Zle/complist.c,v
retrieving revision 1.3
diff -u -r1.3 complist.c
--- Src/Zle/complist.c	2000/04/18 07:36:56	1.3
+++ Src/Zle/complist.c	2000/04/19 06:45:35
@@ -383,7 +383,7 @@
 
 static int noselect, mselect, inselect, mcol, mline, mcols, mlines, mmlen;
 static int selected, mlbeg = -1, mlend = 9999999, mscroll, mrestlines;
-static int mnew, mlastcols, mlastlines, mhasstat;
+static int mnew, mlastcols, mlastlines, mhasstat, mfirstl, mlastm;
 static char *mstatus;
 static Cmatch **mtab, **mmtabp;
 static Cmgroup *mgtab, *mgtabp;
@@ -656,7 +656,7 @@
     Thingy cmd;
     int i, ret = 0;
 
-    compprintfmt(NULL, -1, 1, 1, ml, NULL);
+    compprintfmt(NULL, 1, 1, 1, ml, NULL);
 
     fflush(shout);
     zsetterm();
@@ -791,24 +791,38 @@
 			p--;
 		    break;
 		case 'm':
-		    if (stat && n >= 0) {
-			sprintf(nbuf, "%d/%d", mselect, listdat.nlist);
+		    if (stat) {
+			sprintf(nc, "%d/%d", (n ? mlastm : mselect),
+				listdat.nlist);
+			m = 2;
+		    }
+		    break;
+		case 'M':
+		    if (stat) {
+			sprintf(nbuf, "%d/%d", (n ? mlastm : mselect),
+				listdat.nlist);
 			sprintf(nc, "%-9s", nbuf);
 			m = 2;
 		    }
 		    break;
 		case 'l':
 		    if (stat) {
+			sprintf(nc, "%d/%d", ml + 1, listdat.nlines);
+			m = 2;
+		    }
+		    break;
+		case 'L':
+		    if (stat) {
 			sprintf(nbuf, "%d/%d", ml + 1, listdat.nlines);
 			sprintf(nc, "%-9s", nbuf);
 			m = 2;
 		    }
 		    break;
 		case 'p':
-		    if (stat && n >= 0) {
+		    if (stat) {
 			if (ml == listdat.nlines - 1)
 			    strcpy(nc, "Bottom");
-			else if (mlbeg || ml != n)
+			else if (n ? mfirstl : (mlbeg > 0 || ml != mfirstl))
 			    sprintf(nc, "%d%%",
 				    ((ml + 1) * 100) / listdat.nlines);
 			else
@@ -816,6 +830,18 @@
 			m = 2;
 		    }
 		    break;
+		case 'P':
+		    if (stat) {
+			if (ml == listdat.nlines - 1)
+			    strcpy(nc, "Bottom");
+			else if (n ? mfirstl : (mlbeg > 0 || ml != mfirstl))
+			    sprintf(nc, "%2d%%   ",
+				    ((ml + 1) * 100) / listdat.nlines);
+			else
+			    strcpy(nc, "Top   ");
+			m = 2;
+		    }
+		    break;
 		}
 		if (m == 2 && dopr == 1) {
 		    int l = strlen(nc);
@@ -853,6 +879,8 @@
 		    ml++;
 		if (mscroll && beg && !--mrestlines && (ask = asklistscroll(ml))) {
 		    *stop = 1;
+		    if (stat && n)
+			mfirstl = -1;
 		    return l + (cc / columns);
 		}
 	    }
@@ -861,6 +889,9 @@
     if (dopr && mlbeg >= 0 && tccan(TCCLEAREOL))
 	tcout(TCCLEAREOL);
 
+    if (stat && n)
+	mfirstl = -1;
+
     return l + (cc / columns);
 }
 
@@ -944,8 +975,9 @@
     Cmatch *p, m;
     Cexpl *e;
     int pnl = 0, cl, mc = 0, ml = 0, printed = 0, stop = 0, asked = 1;
-    int lastused = 0, fl = -1;
+    int lastused = 0;
 
+    mfirstl = -1;
     if (mnew || lastbeg != mlbeg || mlbeg < 0) {
 	lasttype = 0;
 	lastg = NULL;
@@ -988,6 +1020,8 @@
 				tcout(TCCLEAREOD);
 			}
 		    }
+		    if (mlbeg < 0 && mfirstl < 0)
+			mfirstl = ml;
 		    l = compprintfmt((*e)->str, (*e)->count, dolist(ml), 1,
 				     ml, &stop);
 		    if (stop)
@@ -1026,6 +1060,8 @@
 			tcout(TCCLEAREOD);
 		}
 	    }
+	    if (mlbeg < 0 && mfirstl < 0)
+		mfirstl = ml;
 	    if (g->flags & CGF_LINES) {
 		while (*pp) {
 		    if (compzputs(*pp, ml))
@@ -1112,8 +1148,8 @@
 				    tcout(TCCLEAREOD);
 			    }
 			}
-			if (fl < 0)
-			    fl = ml;
+			if (mfirstl < 0)
+			    mfirstl = ml;
 			if (dolist(ml))
 			    printed++;
 			if (clprintm(g, p, 0, ml, 1, 0, NULL, NULL))
@@ -1183,8 +1219,8 @@
 
 		    if (dolist(ml))
 			printed++;
-		    if (fl < 0)
-			fl = ml;
+		    if (mfirstl < 0)
+			mfirstl = ml;
 
 		    if (--n)
 			for (j = ((g->flags & CGF_ROWS) ? 1 : nc);
@@ -1233,7 +1269,7 @@
 	    if ((ml = listdat.nlines + nlnct) >= lines) {
 		if (mhasstat) {
 		    putc('\n', shout);
-		    compprintfmt(NULL, fl, 1, 1, mline, NULL);
+		    compprintfmt(NULL, 0, 1, 1, mline, NULL);
 		}
 		ml = lines - 1;
 	    } else
@@ -1287,6 +1323,7 @@
 	return 0;
     }
     m = *mp;
+    mlastm = m->gnum;
     if (m->disp && (m->flags & CMF_DISPLINE)) {
 	if (mselect >= 0) {
 	    int mm = (mcols * ml), i;

--
Sven Wischnowsky                         wischnow@informatik.hu-berlin.de


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: PATCH: scrolling completion lists (was: Re: Questions)
  2000-04-18  9:32 Sven Wischnowsky
@ 2000-04-18  9:47 ` Peter Stephenson
  0 siblings, 0 replies; 10+ messages in thread
From: Peter Stephenson @ 2000-04-18  9:47 UTC (permalink / raw)
  To: Zsh hackers list

> 
> Peter Stephenson wrote:
> 
> > Some other minor comments on scrolling, which I'm not suggesting any
> > immediate action on:
> > 
> > - the %l in list-prompt adds some spaces after it, so a message like
> >   `listing completions at %l, space to scroll'
> >   looks a little messy
> 
> Right (%m does the same). I was torn in two here... if you have a
> select-prompt like
> 
>   'Match %m  Line %l  %p'
> 
> I think it is nice that the `Line...' doesn't move back and forth when 
> moving from match number 9 to number 10 or something like that.

You could have %M, %L and %P do the current form of alignment, %m, %l and
%p not, which would save any extra parsing.

-- 
Peter Stephenson <pws@cambridgesiliconradio.com>
Cambridge Silicon Radio, Unit 300, Science Park, Milton Road,
Cambridge, CB4 0XL, UK                          Tel: +44 (0)1223 392070


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: PATCH: scrolling completion lists (was: Re: Questions)
@ 2000-04-18  9:32 Sven Wischnowsky
  2000-04-18  9:47 ` Peter Stephenson
  0 siblings, 1 reply; 10+ messages in thread
From: Sven Wischnowsky @ 2000-04-18  9:32 UTC (permalink / raw)
  To: zsh-workers


Peter Stephenson wrote:

> Some other minor comments on scrolling, which I'm not suggesting any
> immediate action on:
> 
> - the %l in list-prompt adds some spaces after it, so a message like
>   `listing completions at %l, space to scroll'
>   looks a little messy

Right (%m does the same). I was torn in two here... if you have a
select-prompt like

  'Match %m  Line %l  %p'

I think it is nice that the `Line...' doesn't move back and forth when 
moving from match number 9 to number 10 or something like that. And I
was to lazy to allow `%<num>l'.
I'll see what I can do here, which may well result in just removing
the alignement.

> - maybe it would be better if this one understood %p, too, just for
>   consistency

Yep, shouldn't be too hard (see above, keyword `lazy').

> - maybe there should likewise by a (different) default prompt here, too

There is a very simple builtin default, but maybe, yes.

> - I understand the need for the difference between scrolling in listing and
>   in menu selection, but (this is basically what Zefram was saying) we need
>   to keep it as intuitive as possible.  So for example I'm not necessarily
>   yet convinced that it would be a bad thing to be able to scroll backwards
>   in the completion list form (given this is already in the code).

Most of the things we need are indeed there. It's mostly a matter of
passing one more bit of information from the function that displays
the prompt back to the main listing function.

Bye
 Sven


--
Sven Wischnowsky                         wischnow@informatik.hu-berlin.de


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: PATCH: scrolling completion lists (was: Re: Questions)
  2000-04-17 12:11 Sven Wischnowsky
@ 2000-04-17 13:01 ` Peter Stephenson
  0 siblings, 0 replies; 10+ messages in thread
From: Peter Stephenson @ 2000-04-17 13:01 UTC (permalink / raw)
  To: Zsh hackers list

> As you have seen I haven't added styles for any of this yet, but I'm
> planning to do so. Maybe just the obvious `select-status' (or should
> that be in the menu style with `status=...'? harder to parse...),
> `list-status' (`list-prompt' might be a better name, for the
> parameter, too), and `select-scroll' (or maybe put that into the
> menu-style, too).

Maybe select-prompt is more consistent than select-status, which implies a
returned value, although it should be the same as the parameter.

It occurs to me that you can display other stuff in this prompt, e.g. info
about the currently selected file in menu-select mode.  But that's nothing
to do with scrolling.

> Default values could then be defined as defaults for the style(s),
> that's probably what you suggested.

Yes, I think that would be OK.

-- 
Peter Stephenson <pws@cambridgesiliconradio.com>
Cambridge Silicon Radio, Unit 300, Science Park, Milton Road,
Cambridge, CB4 0XL, UK                          Tel: +44 (0)1223 392070


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: PATCH: scrolling completion lists (was: Re: Questions)
@ 2000-04-17 12:11 Sven Wischnowsky
  2000-04-17 13:01 ` Peter Stephenson
  0 siblings, 1 reply; 10+ messages in thread
From: Sven Wischnowsky @ 2000-04-17 12:11 UTC (permalink / raw)
  To: zsh-workers


Peter Stephenson wrote:

> > I had been thinking about doing this, but the patch below uses a
> > simple statusline below the menu when it is too big to fit on the
> > screen and the $SELECTSTATUS parameter is set. That may contain some
> > %-escaped (%l - line information, %m - match information, %p -
> > Top/Bottom/%).
> 
> This is fine, but it should probably have some default value, which could
> be set in the shell functions if that's possible, e.g.
>   SELECTSTATUS='Scrolling active: current selection at %p'
> although I've put a %B at the front.

As you have seen I haven't added styles for any of this yet, but I'm
planning to do so. Maybe just the obvious `select-status' (or should
that be in the menu style with `status=...'? harder to parse...),
`list-status' (`list-prompt' might be a better name, for the
parameter, too), and `select-scroll' (or maybe put that into the
menu-style, too). I'm not yet decided if we should support setting
this per-tag or only for the default tag. The former is probably more
consistent (and silly).
Default values could then be defined as defaults for the style(s),
that's probably what you suggested.

> At the moment it doesn't alter the default LISTMAX.  That's tricky, since
> LISTMAX is set in params.c.  But it would be preferable to have that
> reflect the fact that scrolling is going to be used instead of limiting the
> display.  More precisely, it would be preferable for LISTMAX not to be set
> if it's going to be used, and to be used if it's explicitly set, I suppose.
> One problem is that until zsh/complist is loaded, LISTMAX *will* be used.
> Maybe that means we just document the fact it will be ignored when using
> complist.

Hm, actually complist uses it as usual, it only adds a new
interpretation to the value `scroll'. And that is documented. But yes, 
maybe we should explicitly point out that in that case the completion
code won't ask if one wants to see the list.

Bye
 Sven


--
Sven Wischnowsky                         wischnow@informatik.hu-berlin.de


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: PATCH: scrolling completion lists (was: Re: Questions)
  2000-04-17 11:10 Sven Wischnowsky
@ 2000-04-17 11:47 ` Peter Stephenson
  0 siblings, 0 replies; 10+ messages in thread
From: Peter Stephenson @ 2000-04-17 11:47 UTC (permalink / raw)
  To: Zsh hackers list

> I had been thinking about doing this, but the patch below uses a
> simple statusline below the menu when it is too big to fit on the
> screen and the $SELECTSTATUS parameter is set. That may contain some
> %-escaped (%l - line information, %m - match information, %p -
> Top/Bottom/%).

This is fine, but it should probably have some default value, which could
be set in the shell functions if that's possible, e.g.
  SELECTSTATUS='Scrolling active: current selection at %p'
although I've put a %B at the front.

At the moment it doesn't alter the default LISTMAX.  That's tricky, since
LISTMAX is set in params.c.  But it would be preferable to have that
reflect the fact that scrolling is going to be used instead of limiting the
display.  More precisely, it would be preferable for LISTMAX not to be set
if it's going to be used, and to be used if it's explicitly set, I suppose.
One problem is that until zsh/complist is loaded, LISTMAX *will* be used.
Maybe that means we just document the fact it will be ignored when using
complist.

-- 
Peter Stephenson <pws@cambridgesiliconradio.com>
Cambridge Silicon Radio, Unit 300, Science Park, Milton Road,
Cambridge, CB4 0XL, UK                          Tel: +44 (0)1223 392070


^ permalink raw reply	[flat|nested] 10+ messages in thread

* PATCH: scrolling completion lists (was: Re: Questions)
@ 2000-04-17 11:10 Sven Wischnowsky
  2000-04-17 11:47 ` Peter Stephenson
  0 siblings, 1 reply; 10+ messages in thread
From: Sven Wischnowsky @ 2000-04-17 11:10 UTC (permalink / raw)
  To: zsh-workers


Peter Stephenson wrote:

> ...
> 
> > And did anyone have the time to try the patch for scrolling completion 
> > lists? (I have a new version which is faster and allows status lines --
> > it's getting silly ;-)
> 
> It seems fine.  The natural way of showing that text is missing would be to
> put an ellipsis (`...' in English) at the top or bottom, like it does when
> a line is too long. 

I had been thinking about doing this, but the patch below uses a
simple statusline below the menu when it is too big to fit on the
screen and the $SELECTSTATUS parameter is set. That may contain some
%-escaped (%l - line information, %m - match information, %p -
Top/Bottom/%). I *don't* want to say that this is better, I was just
playing with it. If we agree to do that differently, I'll change
it. No problem. Maybe using the `...'s (that would sometimes take two
lines, hm) and a ZLS_COLO(|U)RS capability to be able to highlight it
or something (complist.c still contains code for the `st' capability I 
added when playing with something like this; I'll leave it in for now
and remove either that or the $*STATUS stuff when we've decided what
we want). Trivial.

Note also that I consider scrolling in completion lists without being
in a menu-selection and when being in one to be different things. In
fact, I was never happy that menu-selection didn't work with too long
lists and that's why I brought this up again.

For the listing (not selection), there is a $LISTSTATUS (which
supports only the %l) that can be set to the prompt that should be
shown below the current screenful.

Both *STATUS parameters support the %[sSbBuB{}] known from everywhere
else.

> It's most confusing when you wrap around the bottom
> without warning.  A scroll-step style would certainly be useful, and in the
> long run a special keymap. 

The parameter $SCROLLSTEP can be used to define the scroll step one
wants (0 - half a screen, positive - that many lines, negative -
screen height minus that many lines). But it is only used in
menu-selection.

Using a keymap for normal listing would be easy to add...

> I have doubts about `return' forcing the
> display to scroll a line, since in menu-selection it already has another
> meaning (and you have to hit it twice to execute a line, which took me a
> long time to get used to), so this may be overloading it too much.

But return is only used for the normal listing, it hasn't changed in
menu-selection. And I was thinking about pagers which normally allow
this... but I wouldn't be against removing it. I definitely prefer the 
solution with the extra keymap anyway, especially to get rid of that
ugly special case for `q'.

> ...
> 
> I don't see that it has to be that much more sophisticated.  I'm against
> implementing a rewrite of `less' in the shell, at least unless it goes into
> a completely self-contained library.

Right, that's why I want to keep it small, too.

> ...
> 
> Would people rejoice or complain if we had this on by default (other
> settings permitting)?

For menu-selection-scrolling there shouldn't be a way around it, I
think. For normal lists: I would like to hear more opinions, too.


Zefram wrote:

> Peter Stephenson wrote:
> >Would people rejoice or complain if we had this on by default (other
> >settings permitting)?
> 
> I'd like it.  I've often cursed at too-long completion listings that (a)
> take a long time to scroll past at 9600 baud (well that was a while ago)
> and (b) aren't readable because they've scrolled past.  And I've often
> used completion listing to get a quick directory listing; having that
> work for more than one screenful would be good.
> 
> My only real concern here is that the pager shouldn't get in the way of
> normal typing.  What I'd like is that repeated <tab>s show successive
> pages of listing, after the <tab> that shows the first page. 

The hard-wired key-handling for scrolling non-menu-selection lists did 
that from the first patch on.

> That seems
> intuitive to me, but it might be difficult to fit in with the form of
> menu completion where the first match is inserted at the same time the
> list is shown.  Not to mention the case of an explicit list requested
> during completion.  That needs some thinking about.

I'm not exactly sure what you mean here...


Anyway here is the patch and I committed it (or will be committing it
soon), so that everone can easily try it. I don't think we'll need
more than this week to find answers to the open questions.

Bye
 Sven

Index: Doc/Zsh/mod_complist.yo
===================================================================
RCS file: /cvsroot/zsh/zsh/Doc/Zsh/mod_complist.yo,v
retrieving revision 1.1.1.20
diff -u -r1.1.1.20 mod_complist.yo
--- Doc/Zsh/mod_complist.yo	2000/01/24 09:38:23	1.1.1.20
+++ Doc/Zsh/mod_complist.yo	2000/04/17 11:06:14
@@ -3,17 +3,18 @@
 !MOD!)
 cindex(completion, listing)
 cindex(completion, coloured listings)
-The tt(zsh/complist) module offers two extensions to completion listings:
-the ability to highlight matches in such a list and a different
-style of menu-completion.
+cindex(completion, scroll listings)
+The tt(zsh/complist) module offers three extensions to completion listings:
+the ability to highlight matches in such a list, the ability to
+scroll through long lists and a different style of menu-completion.
 
+subsect(Colored completion listings)
 Whenever one of the parameters tt(ZLS_COLORS) or tt(ZLS_COLOURS) is set 
 and the tt(zsh/complist) module is loaded or linked into the shell,
 completion lists will be colored.  Note, however, that tt(complist) will
 not automatically be loaded if it is not linked in:  on systems with
 dynamic loading, `tt(zmodload zsh/complist)' is required.
 
-subsect(Parameters)
 vindex(ZLS_COLORS)
 vindex(ZLS_COLOURS)
 The parameters tt(ZLS_COLORS) and tt(ZLS_COLOURS) describe how matches
@@ -126,6 +127,39 @@
 ifnzman(noderef(Completion System Configuration))\
 ).
 
+subsect(Scrolling in completion listings)
+vindex(LISTMAX)
+To be able to scroll through a completion list, the tt(LISTMAX)
+parameter has to be set to the string `tt(scroll)'. If it has this
+value, the completion code will not ask if the list should be
+shown. Instead it immediately starts displaying the list, stopping
+after the first screenful, showing a simple prompt at the bottom,
+waiting for a keypress. The following keys have a special meaning:
+
+startitem()
+item(tt(Space), tt(Tab))(
+scroll forward one screenful
+)
+item(tt(Return), tt(Newline))(
+scroll forward one line
+)
+item(tt(q))(
+stops listing and redisplays the command line without inserting the
+`tt(q)'
+)
+enditem()
+
+Every other character stops listing and immediately processes the key
+as usual.
+
+If the parameter tt(LISTSTATUS) is set, its value will be used as the
+prompt.  The value may contain escapes of the form `tt(%x)'. It
+supports the escapes `tt(%B)', `tt(%b)', `tt(%S)', `tt(%s)', `tt(%U)',
+`tt(%u)' and `tt(%{...%})' known from the shell prompts and the
+additional sequence `tt(%l)' which is replaced by the number of the
+last line shown and the total number of lines in the form
+`var(number)tt(/)var(total)'.
+
 subsect(Menu selection)
 cindex(completion, selecting by cursor)
 vindex(SELECTMIN)
@@ -151,7 +185,9 @@
 and tt(ZLS_COLOURS) parameters described above). Instead, the tt(menu) 
 style should be used.
 
-After menu-selection is started, the matches will be listed. The
+After menu-selection is started, the matches will be listed. If there
+are more matches than fit on the screen, only the first screenful is
+shown. The
 matches to insert into the command line can be selected from this
 list. In the list one match is highlighted using the value for tt(ma)
 from the tt(ZLS_COLORS) or tt(ZLS_COLOURS) parameter. The default
@@ -160,6 +196,23 @@
 neither tt(ZLS_COLORS) nor tt(ZLS_COLOURS) is set, the same terminal
 control sequence as for the `tt(%S)' escape in prompts is used.
 
+If there are more matches than fit on the screen and the parameter
+tt(SELECTSTATUS) is set, its value will be shown below the
+matches. Next to the escape sequences understood for the
+tt(LISTSTATUS) parameter, a `tt(%m)' will be replaced by a string
+containing the number of the match the mark is on and the total number 
+of matches in the form `var(number)tt(/)var(total)' and the sequence
+`tt(%p)' will be replaced with `tt(Top)', `tt(Bottom)' or the position
+in percent of the total size when the mark is in the first line, in
+the last line or somewhere in between, respectively.
+
+The tt(SELECTSCROLL) parameter can be used to specify how the list is
+scrolled. If the parameter is unset, this is done line by line, if it
+is set to `tt(0)' (zero), the list will scrolled half the number of
+lines of the screen. If the value is positive, it gives the number of
+lines to scroll and if it is negative, the list will be scrolled one
+the number of lines of the screen minus the (absolute) value.
+
 The completion code sometimes decides not to show all of the matches
 in the list. These hidden matches are either matches for which the
 completion function which added them explicitly requested that they
@@ -173,25 +226,86 @@
 hidden matches of the first and second kind, respectively.
 
 Selecting matches is done by moving the mark around using the zle movement
-functions. The zle functions tt(send-break) and tt(accept-line) can be used
-to leave menu-selection, leaving the match currently inserted into the line
-in place.  In the case of tt(accept-line), the match currently inserted
-will be accepted and a new completion may be attempted.
-Using tt(send-break) leaves menu-selection and continues with normal
-menu-completion.  The functions tt(accept-and-hold) and
-tt(accept-and-menu-complete) can be used to accept the match currently
-inserted and continue inserting matches from the same list. The
-function tt(accept-and-infer-next-history) accepts the current match and
-then tries completion with menu-selection again.  In the case of
-files this allows one to select a directory and immediately attempt to
-complete files in it.  Matches inserted in one of these ways can be removed
-by invoking the tt(undo) function.  Keys bound to one of
-the completion functions will cycle to the next (or, in case of
-tt(reverse-menu-complete), the previous) match, and the tt(redisplay) and
-tt(clear-screen) functions work as usual without leaving
-menu-selection.
+functions. When not all matches can be shown on the screen at the same 
+time, the list will scroll up and down when crossing the top or
+bottom line. The following zle functions have special meaning during
+menu selection:
+
+startitem()
+item(tt(accept-line))(
+accepts the current match and leaves menu selection
+)
+item(tt(send-break))(
+leaves menu selection and continues with normal menu completion
+)
+item(tt(redisplay), tt(clear-screen))(
+execute their normal function without leaving menu selection
+)
+item(tt(accept-and-hold), tt(accept-and-menu-complete))(
+accept the currently inserted match and continue selection allowing to 
+select the next match to insert into the line
+)
+item(tt(accept-and-infer-next-history))(
+accepts the current match and then tries completion with
+menu-selection again;  in the case of files this allows one to select
+a directory and immediately attempt to complete files in it
+)
+item(tt(undo))(
+removes matches inserted during the menu selection by one of the three 
+functions before
+)
+xitem(tt(down-history), tt(down-line-or-history))
+item(tt(vi-down-line-or-history),  tt(down-line-or-search))(
+moves the mark one line down
+)
+xitem(tt(up-history), tt(up-line-or-history))
+item(tt(vi-up-line-or-history), tt(up-line-or-search))(
+moves the mark one line up
+)
+item(tt(forward-char), tt(vi-forward-char))(
+moves the mark one column right
+)
+item(tt(backward-char), tt(vi-backward-char))(
+moves the mark one column left
+)
+xitem(tt(forward-word), tt(vi-forward-word))
+item(tt(vi-forward-word-end), tt(emacs-forward-word))(
+moves the mark one screenful down
+)
+item(tt(backward-word), tt(vi-backward-word), tt(emacs-backward-word))(
+moves the mark one screenful up
+)
+item(tt(vi-forward-blank-word), tt(vi-forward-blank-word-end))(
+moves the mark to the first line of the next group of matches
+)
+item(tt(vi-backward-blank-word))(
+moves the mark to the last line of the previous group of matches
+)
+item(tt(beginning-of-history))(
+moves the mark to the first line
+)
+item(tt(end-of-history))(
+moves the mark to the last line
+)
+xitem(tt(beginning-of-buffer-or-history), tt(beginning-of-line))
+item(tt(beginning-of-line-hist), tt(vi-beginning-of-line))(
+moves the mark to the leftmost column
+)
+xitem(tt(end-of-buffer-or-history), tt(end-of-line))
+item(tt(end-of-line-hist), tt(vi-end-of-line))(
+moves the mark to the rightmost column
+)
+xitem(tt(complete-word), tt(menu-complete), tt(expand-or-complete))
+item(tt(expand-or-complete-prefix), tt(menu-expand-or-complete))(
+moves the mark to the next match
+)
+item(tt(reverse-menu-omplete))(
+moves the mark to the previous match
+)
+enditem()
 
-Any other zle function leaves menu-selection and executes that function.
+All movement function do wrap-around at the edges and
+any other zle function leaves menu-selection and executes that function.
 It is possible to make widgets in the above list do the same by using the
 form of the widget with a `tt(.)' in front.  For example, the widget
 `tt(.accept-line)' has the effect of leaving menu selection and accepting
Index: Src/params.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/params.c,v
retrieving revision 1.5
diff -u -r1.5 params.c
--- Src/params.c	2000/04/13 17:57:45	1.5
+++ Src/params.c	2000/04/17 11:06:16
@@ -483,10 +483,10 @@
     setiparam("MAILCHECK", 60);
     setiparam("LOGCHECK", 60);
     setiparam("KEYTIMEOUT", 40);
-    setiparam("LISTMAX", 100);
 #ifdef HAVE_SELECT
     setiparam("BAUD", getbaudrate(&shttyinfo));  /* get the output baudrate */
 #endif
+    setsparam("LISTMAX", ztrdup("100"));
     setsparam("FCEDIT", ztrdup(DEFAULT_FCEDIT));
     setsparam("TMPPREFIX", ztrdup(DEFAULT_TMPPREFIX));
     setsparam("TIMEFMT", ztrdup(DEFAULT_TIMEFMT));
Index: Src/Zle/compcore.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Zle/compcore.c,v
retrieving revision 1.8
diff -u -r1.8 compcore.c
--- Src/Zle/compcore.c	2000/04/13 08:09:13	1.8
+++ Src/Zle/compcore.c	2000/04/17 11:06:18
@@ -296,7 +296,8 @@
     comppatinsert = ztrdup("menu");
     forcelist = 0;
     haspattern = 0;
-    complistmax = getiparam("LISTMAX");
+    zsfree(complistmax);
+    complistmax = ztrdup(getsparam("LISTMAX"));
     zsfree(complastprompt);
     complastprompt = ztrdup(((isset(ALWAYSLASTPROMPT) && zmult == 1) ||
 			     (unset(ALWAYSLASTPROMPT) && zmult != 1)) ?
Index: Src/Zle/complete.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Zle/complete.c,v
retrieving revision 1.2
diff -u -r1.2 complete.c
--- Src/Zle/complete.c	2000/04/01 20:49:48	1.2
+++ Src/Zle/complete.c	2000/04/17 11:06:18
@@ -35,8 +35,7 @@
 /**/
 mod_export zlong compcurrent;
 /**/
-zlong complistmax,
-      complistlines,
+zlong complistlines,
       compignored;
 
 /**/
@@ -50,7 +49,8 @@
      *compquote,
      *compqstack,
      *comppatmatch,
-     *complastprompt;
+     *complastprompt,
+     *complistmax;
 /**/
 char *compiprefix,
      *compcontext,
@@ -904,7 +904,7 @@
     { "unambiguous", PM_SCALAR | PM_READONLY, NULL, NULL, VAL(get_unambig) },
     { "unambiguous_cursor", PM_INTEGER | PM_READONLY, NULL, NULL,
       VAL(get_unambig_curs) },
-    { "list_max", PM_INTEGER, VAL(complistmax), NULL, NULL },
+    { "list_max", PM_SCALAR, VAL(complistmax), NULL, NULL },
     { "last_prompt", PM_SCALAR, VAL(complastprompt), NULL, NULL },
     { "to_end", PM_SCALAR, VAL(comptoend), NULL, NULL },
     { "old_list", PM_SCALAR, VAL(compoldlist), NULL, NULL },
@@ -1292,7 +1292,7 @@
     comprpms = compkpms = NULL;
     compwords = NULL;
     compprefix = compsuffix = compiprefix = compisuffix = 
-	compqiprefix = compqisuffix =
+	compqiprefix = compqisuffix = complistmax = 
 	compcontext = compparameter = compredirect = compquote =
 	compquoting = comprestore = complist = compinsert =
 	compexact = compexactstr = comppatmatch = comppatinsert =
@@ -1347,6 +1347,7 @@
 {
     if (compwords)
 	freearray(compwords);
+    zsfree(complistmax);
     zsfree(compprefix);
     zsfree(compsuffix);
     zsfree(compiprefix);
Index: Src/Zle/complist.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Zle/complist.c,v
retrieving revision 1.1.1.44
diff -u -r1.1.1.44 complist.c
--- Src/Zle/complist.c	2000/03/01 14:03:20	1.1.1.44
+++ Src/Zle/complist.c	2000/04/17 11:06:19
@@ -59,8 +59,9 @@
 #define COL_MA 15
 #define COL_HI 16
 #define COL_DU 17
+#define COL_ST 18
 
-#define NUM_COLS 18
+#define NUM_COLS 19
 
 /* Maximum number of in-string colours supported. */
 
@@ -70,14 +71,14 @@
 
 static char *colnames[] = {
     "no", "fi", "di", "ln", "pi", "so", "bd", "cd", "ex", "mi",
-    "lc", "rc", "ec", "tc", "sp", "ma", "hi", "du", NULL
+    "lc", "rc", "ec", "tc", "sp", "ma", "hi", "du", "st", NULL
 };
 
 /* Default values. */
 
 static char *defcols[] = {
     "0", "0", "1;34", "1;36", "33", "1;35", "1;33", "1;33", "1;32", NULL,
-    "\033[", "m", NULL, "0", "0", "7", "0", "0"
+    "\033[", "m", NULL, "0", "0", "7", "0", "0", "7"
 };
 
 /* This describes a terminal string for a file type. */
@@ -346,9 +347,12 @@
 	
 	if ((s = tcstr[TCSTANDOUTBEG]) && s[0]) {
 	    c->files[COL_MA] = filecol(s);
+	    c->files[COL_ST] = filecol(s);
 	    c->files[COL_EC] = filecol(tcstr[TCSTANDOUTEND]);
-	} else
-	    c->files[COL_MA] = filecol("");
+	} else {
+	    c->files[COL_MA] = filecol(defcols[COL_MA]);
+	    c->files[COL_ST] = filecol(defcols[COL_ST]);
+	}
 	lr_caplen = 0;
 	if ((max_caplen = strlen(c->files[COL_MA]->col)) <
 	    (l = strlen(c->files[COL_EC]->col)))
@@ -382,7 +386,9 @@
 /* Information about the list shown. */
 
 static int noselect, mselect, inselect, mcol, mline, mcols, mlines, mmlen;
-static int selected;
+static int selected, mlbeg = -1, mlend = 9999999, mscroll, mrestlines;
+static int mnew, mlastcols, mlastlines, mhasstat;
+static char *mstatus;
 static Cmatch **mtab, **mmtabp;
 static Cmgroup *mgtab, *mgtabp;
 static struct listcols mcolors;
@@ -496,10 +502,10 @@
 
 /* Stripped-down version of printfmt(). But can do in-string colouring. */
 
-static void
-clprintfmt(Listcols c, char *p)
+static int
+clprintfmt(Listcols c, char *p, int ml)
 {
-    int cc = 0, i = 0;
+    int cc = 0, i = 0, ask, beg;
 
     initiscol(c);
 
@@ -507,34 +513,32 @@
 	doiscol(c, i++);
 	cc++;
 	if (*p == '\n') {
-	    if (tccan(TCCLEAREOL))
+	    if (mlbeg >= 0 && tccan(TCCLEAREOL))
 		tcout(TCCLEAREOL);
-	    else {
-		int s = columns - 1 - (cc % columns);
-
-		while (s-- > 0)
-		    putc(' ', shout);
-	    }
 	    cc = 0;
 	}
+	if (ml == mlend - 1 && (cc % columns) == columns - 1)
+	    return 0;
+
 	putc(*p, shout);
+	if ((beg = !(cc % columns)))
+	    ml++;
+	if (mscroll && !(cc % columns) &&
+	    !--mrestlines && (ask = asklistscroll(ml)))
+	    return ask;
     }
-    if (tccan(TCCLEAREOL))
+    if (mlbeg >= 0 && tccan(TCCLEAREOL))
 	tcout(TCCLEAREOL);
-    else {
-	int s = columns - 1 - (cc % columns);
-
-	while (s-- > 0)
-	    putc(' ', shout);
-    }
+    return 0;
 }
 
 /* Local version of nicezputs() with in-string colouring. */
 
-static void
-clnicezputs(Listcols c, char *s)
+static int
+clnicezputs(Listcols c, char *s, int ml)
 {
-    int cc, i = 0;
+    int cc, i = 0, col = 0, ask;
+    char *t;
 
     initiscol(c);
 
@@ -548,8 +552,21 @@
 	}
 	if (cc == Meta)
 	    cc = *s++ ^ 32;
-	fputs(nicechar(cc), shout);
+
+	for (t = nicechar(cc); *t; t++) {
+	    if (ml == mlend - 1 && col == columns - 1)
+		return 0;
+	    putc(*t, shout);
+	    if (++col == columns) {
+		ml++;
+		if (mscroll && !--mrestlines && (ask = asklistscroll(ml)))
+		    return ask;
+
+		col = 0;
+	    }
+	}
     }
+    return 0;
 }
 
 /* Get the terminal color string for the given match. */
@@ -636,12 +653,613 @@
 
 static Cmgroup last_group;
 
-static void
+/**/
+static int
+asklistscroll(int ml)
+{
+    int v, i;
+
+    compprintfmt(NULL, -1, 1, 1, ml, NULL);
+
+    fflush(shout);
+    zsetterm();
+    v = getzlequery(0);
+    settyinfo(&shttyinfo);
+    putc('\r', shout);
+    for (i = columns - 1; i--; )
+	putc(' ', shout);
+
+    putc('\r', shout);
+
+    if (v == '\n' || v == '\r') {
+	mrestlines = 1;
+	return 0;
+    }
+    mrestlines = lines - 1;
+
+    if (v == ' ' || v == '\t')
+	return 0;
+    if (v != 'q')
+	ungetkey(v);
+
+    return 1;
+}
+
+#define dolist(X)   ((X) >= mlbeg && (X) < mlend)
+#define dolistcl(X) ((X) >= mlbeg && (X) < mlend + 1)
+#define dolistnl(X) ((X) >= mlbeg && (X) < mlend - 1)
+
+/**/
+static int
+compprintnl(int ml)
+{
+    int ask;
+
+    if (mlbeg >= 0 && tccan(TCCLEAREOL))
+	tcout(TCCLEAREOL);
+    putc('\n', shout);
+
+    if (mscroll && !--mrestlines && (ask = asklistscroll(ml)))
+	return ask;
+
+    return 0;
+}
+
+/* This is used to print the strings (e.g. explanations). *
+ * It returns the number of lines printed.       */
+
+/**/
+static int
+compprintfmt(char *fmt, int n, int dopr, int doesc, int ml, int *stop)
+{
+    char *p, nc[2*DIGBUFSIZE + 12], nbuf[2*DIGBUFSIZE + 12];
+    int l = 0, cc = 0, b = 0, s = 0, u = 0, m, ask, beg, stat;
+
+    if ((stat = !fmt)) {
+	if (mlbeg >= 0) {
+	    if (!(fmt = mstatus))
+		return 0;
+	    cc = -1;
+	} else if (!(fmt = getsparam("LISTSTATUS")))
+	    fmt = "continue? ";
+    }
+    for (p = fmt; *p; p++) {
+	if (doesc && *p == '%') {
+	    if (*++p) {
+		m = 0;
+		switch (*p) {
+		case '%':
+		    if (dopr == 1)
+			putc('%', shout);
+		    cc++;
+		    break;
+		case 'n':
+		    if (!stat) {
+			sprintf(nc, "%d", n);
+			if (dopr == 1)
+			    fputs(nc, shout);
+			cc += strlen(nc);
+		    }
+		    break;
+		case 'B':
+		    b = 1;
+		    if (dopr)
+			tcout(TCBOLDFACEBEG);
+		    break;
+		case 'b':
+		    b = 0; m = 1;
+		    if (dopr)
+			tcout(TCALLATTRSOFF);
+		    break;
+		case 'S':
+		    s = 1;
+		    if (dopr)
+			tcout(TCSTANDOUTBEG);
+		    break;
+		case 's':
+		    s = 0; m = 1;
+		    if (dopr)
+			tcout(TCSTANDOUTEND);
+		    break;
+		case 'U':
+		    u = 1;
+		    if (dopr)
+			tcout(TCUNDERLINEBEG);
+		    break;
+		case 'u':
+		    u = 0; m = 1;
+		    if (dopr)
+			tcout(TCUNDERLINEEND);
+		    break;
+		case '{':
+		    for (p++; *p && (*p != '%' || p[1] != '}'); p++)
+			if (dopr)
+			    putc(*p, shout);
+		    if (*p)
+			p++;
+		    else
+			p--;
+		    break;
+		case 'm':
+		    if (stat && n >= 0) {
+			sprintf(nbuf, "%d/%d", mselect, listdat.nlist);
+			sprintf(nc, "%-9s", nbuf);
+			m = 2;
+		    }
+		    break;
+		case 'l':
+		    if (stat) {
+			sprintf(nbuf, "%d/%d", ml + 1, listdat.nlines);
+			sprintf(nc, "%-9s", nbuf);
+			m = 2;
+		    }
+		    break;
+		case 'p':
+		    if (stat && n >= 0) {
+			if (ml == listdat.nlines - 1)
+			    strcpy(nc, "Bottom");
+			else if (mlbeg || ml != n)
+			    sprintf(nc, "%d%%",
+				    ((ml + 1) * 100) / listdat.nlines);
+			else
+			    strcpy(nc, "Top");
+			m = 2;
+		    }
+		    break;
+		}
+		if (m == 2 && dopr == 1) {
+		    int l = strlen(nc);
+
+		    if (l + cc > columns - 2)
+			nc[l -= l + cc - (columns - 2)] = '\0';
+		    fputs(nc, shout);
+		    cc += l;
+		} else if (dopr && m == 1) {
+		    if (b)
+			tcout(TCBOLDFACEBEG);
+		    if (s)
+			tcout(TCSTANDOUTBEG);
+		    if (u)
+			tcout(TCUNDERLINEBEG);
+		}
+	    } else
+		break;
+	} else {
+	    if ((++cc == columns - 2 || *p == '\n') && stat)
+		dopr = 2;
+	    if (*p == '\n') {
+		if (dopr == 1 && mlbeg >= 0 && tccan(TCCLEAREOL))
+		    tcout(TCCLEAREOL);
+		l += 1 + (cc / columns);
+		cc = 0;
+	    }
+	    if (dopr == 1) {
+		if (ml == mlend - 1 && (cc % columns) == columns - 1) {
+		    dopr = 0;
+		    continue;
+		}
+		putc(*p, shout);
+		if ((beg = !(cc % columns)) && !stat)
+		    ml++;
+		if (mscroll && beg && !--mrestlines && (ask = asklistscroll(ml))) {
+		    *stop = 1;
+		    return l + (cc / columns);
+		}
+	    }
+	}
+    }
+    if (dopr && mlbeg >= 0 && tccan(TCCLEAREOL))
+	tcout(TCCLEAREOL);
+
+    return l + (cc / columns);
+}
+
+/* This is like zputs(), but allows scrolling. */
+
+/**/
+static int
+compzputs(char const *s, int ml)
+{
+    int c, col = 0, ask;
+
+    while (*s) {
+	if (*s == Meta)
+	    c = *++s ^ 32;
+	else if(itok(*s)) {
+	    s++;
+	    continue;
+	} else
+	    c = *s;
+	s++;
+	putc(c, shout);
+	if (c == '\n' && mlbeg >= 0 && tccan(TCCLEAREOL))
+	    tcout(TCCLEAREOL);
+	if (mscroll && (++col == columns || c == '\n')) {
+	    ml++;
+	    if (!--mrestlines && (ask = asklistscroll(ml)))
+		return ask;
+
+	    col = 0;
+	}
+    }
+    return 0;
+}
+
+/* This is like nicezputs(), but allows scrolling. */
+
+/**/
+static int
+compnicezputs(char *s, int ml)
+{
+    int c, col = 0, ask;
+    char *t;
+
+    while ((c = *s++)) {
+	if (itok(c)) {
+	    if (c <= Comma)
+		c = ztokens[c - Pound];
+	    else 
+		continue;
+	}
+	if (c == Meta)
+	    c = *s++ ^ 32;
+
+	for (t = nicechar(c); *t; t++) {
+	    if (ml == mlend - 1 && col == columns - 1)
+		return 0;
+	    putc(*t, shout);
+	    if (++col == columns) {
+		ml++;
+		if (mscroll && !--mrestlines && (ask = asklistscroll(ml)))
+		    return ask;
+
+		col = 0;
+	    }
+	}
+    }
+    return 0;
+}
+
+/**/
+static int
+compprintlist(int showall)
+{
+    static int lasttype = 0, lastbeg = 0, lastml = 0;
+    static lastn = 0, lastnl = 0;
+    static Cmgroup lastg = NULL;
+    static Cmatch *lastp = NULL;
+    static Cexpl *lastexpl = NULL;
+
+    Cmgroup g;
+    Cmatch *p, m;
+    Cexpl *e;
+    int pnl = 0, cl, mc = 0, ml = 0, printed = 0, stop = 0, asked = 1;
+    int lastused = 0, fl = -1;
+
+    if (mnew || lastbeg != mlbeg || mlbeg < 0) {
+	lasttype = 0;
+	lastg = NULL;
+	lastexpl = NULL;
+	lastml = 0;
+    }
+    cl = (listdat.nlines > lines - nlnct - mhasstat ?
+	  lines - nlnct - mhasstat : listdat.nlines);
+    mrestlines = lines - 1;
+
+    if (cl < 2) {
+	cl = -1;
+	if (tccan(TCCLEAREOD))
+	    tcout(TCCLEAREOD);
+    } else if (mlbeg >= 0 && !tccan(TCCLEAREOL) && tccan(TCCLEAREOD))
+	tcout(TCCLEAREOD);
+
+    g = ((lasttype && lastg) ? lastg : amatches);
+    while (g) {
+	char **pp = g->ylist;
+
+	if ((e = g->expls)) {
+	    int l;
+
+	    if (!lastused && lasttype == 1) {
+		e = lastexpl;
+		ml = lastml;
+		lastused = 1;
+	    }
+	    while (*e) {
+		if ((*e)->count) {
+		    if (pnl) {
+			if (dolistnl(ml) && compprintnl(ml))
+			    goto end;
+			pnl = 0;
+			ml++;
+			if (dolistcl(ml) && cl >= 0 && --cl <= 1) {
+			    cl = -1;
+			    if (tccan(TCCLEAREOD))
+				tcout(TCCLEAREOD);
+			}
+		    }
+		    l = compprintfmt((*e)->str, (*e)->count, dolist(ml), 1,
+				     ml, &stop);
+		    if (stop)
+			goto end;
+		    if (!lasttype && ml >= mlbeg) {
+			lasttype = 1;
+			lastg = g;
+			lastbeg = mlbeg;
+			lastml = ml;
+			lastexpl = e;
+			lastp = NULL;
+			lastused = 1;
+		    }
+		    ml += l;
+		    if (dolistcl(ml) && cl >= 0 && (cl -= l) <= 1) {
+			cl = -1;
+			if (tccan(TCCLEAREOD))
+			    tcout(TCCLEAREOD);
+		    }
+		    pnl = 1;
+		}
+		e++;
+		if (!mnew && ml > mlend)
+		    goto end;
+	    }
+	}
+	if (!listdat.onlyexpl && mlbeg < 0 && pp && *pp) {
+	    if (pnl) {
+		if (dolistnl(ml) && compprintnl(ml))
+		    goto end;
+		pnl = 0;
+		ml++;
+		if (cl >= 0 && --cl <= 1) {
+		    cl = -1;
+		    if (tccan(TCCLEAREOD))
+			tcout(TCCLEAREOD);
+		}
+	    }
+	    if (g->flags & CGF_LINES) {
+		while (*pp) {
+		    if (compzputs(*pp, ml))
+			goto end;
+		    if (*++pp && compprintnl(ml))
+			goto end;
+		}
+	    } else {
+		int n = g->lcount, nl, nc, i, a;
+		char **pq;
+
+		nl = nc = g->lins;
+
+		while (n && nl--) {
+		    i = g->cols;
+		    mc = 0;
+		    pq = pp;
+		    while (n && i--) {
+			if (pq - g->ylist >= g->lcount)
+			    break;
+			if (compzputs(*pq, mscroll))
+			    goto end;
+			if (i) {
+			    a = (g->widths ? g->widths[mc] : g->width) -
+				strlen(*pq);
+			    while (a--)
+				putc(' ', shout);
+			}
+			pq += ((g->flags & CGF_ROWS) ? 1 : nc);
+			mc++;
+			n--;
+		    }
+		    if (n) {
+			if (compprintnl(ml))
+			    goto end;
+			ml++;
+			if (cl >= 0 && --cl <= 1) {
+			    cl = -1;
+			    if (tccan(TCCLEAREOD))
+				tcout(TCCLEAREOD);
+			}
+		    }
+		    pp += ((g->flags & CGF_ROWS) ? g->cols : 1);
+		}
+	    }
+	} else if (!listdat.onlyexpl &&
+		   (g->lcount || (showall && g->mcount))) {
+	    int n = g->dcount, nl, nc, i, j, wid;
+	    Cmatch *q;
+
+	    nl = nc = g->lins;
+
+	    if ((g->flags & CGF_HASDL) &&
+		(lastused || !lasttype || lasttype == 2)) {
+		if (!lastused && lasttype == 2) {
+		    p = lastp;
+		    ml = lastml;
+		    n = lastn;
+		    nl = lastnl;
+		    lastused = 1;
+		} else
+		    p = g->matches;
+
+		for (; (m = *p); p++) {
+		    if (m->disp && (m->flags & CMF_DISPLINE)) {
+			if (!lasttype && ml >= mlbeg) {
+			    lasttype = 2;
+			    lastg = g;
+			    lastbeg = mlbeg;
+			    lastml = ml;
+			    lastp = p;
+			    lastn = n;
+			    lastnl = nl;
+			    lastused = 1;
+			}
+			if (pnl) {
+			    if (dolistnl(ml) && compprintnl(ml))
+				goto end;
+			    pnl = 0;
+			    ml++;
+			    if (dolistcl(ml) && cl >= 0 && --cl <= 1) {
+				cl = -1;
+				if (tccan(TCCLEAREOD))
+				    tcout(TCCLEAREOD);
+			    }
+			}
+			if (fl < 0)
+			    fl = ml;
+			if (dolist(ml))
+			    printed++;
+			if (clprintm(g, p, 0, ml, 1, 0, NULL, NULL))
+			    goto end;
+			pnl = 1;
+		    }
+		    if (!mnew && ml > mlend)
+			goto end;
+		}
+	    }
+	    if (n && pnl) {
+		if (dolistnl(ml) && compprintnl(ml))
+		    goto end;
+		pnl = 0;
+		ml++;
+		if (dolistcl(ml) && cl >= 0 && --cl <= 1) {
+		    cl = -1;
+		    if (tccan(TCCLEAREOD))
+			tcout(TCCLEAREOD);
+		}
+	    }
+	    if (!lastused && lasttype == 3) {
+		p = lastp;
+		n = lastn;
+		nl = lastnl;
+		ml = lastml;
+		lastused = 1;
+	    } else
+		p = skipnolist(g->matches, showall);
+
+	    while (n && nl--) {
+		if (!lasttype && ml >= mlbeg) {
+		    lasttype = 3;
+		    lastg = g;
+		    lastbeg = mlbeg;
+		    lastml = ml;
+		    lastp = p;
+		    lastn = n;
+		    lastnl = nl + 1;
+		    lastused = 1;
+		}
+		i = g->cols;
+		mc = 0;
+		q = p;
+		while (n && i--) {
+		    wid = (g->widths ? g->widths[mc] : g->width);
+		    if (!(m = *q)) {
+			if (clprintm(g, NULL, mc, ml, (!i), wid, NULL, NULL))
+			    goto end;
+			break;
+		    }
+		    if (!m->disp && (m->flags & CMF_FILE)) {
+			struct stat buf;
+			char *pb;
+
+			pb = (char *) zhalloc((m->prpre ? strlen(m->prpre) : 0) +
+					     3 + strlen(m->str));
+			sprintf(pb, "%s%s", (m->prpre ? m->prpre : "./"),
+				m->str);
+
+			if (ztat(pb, &buf, 1) ?
+			    clprintm(g, q, mc, ml, (!i), wid, NULL, NULL) :
+			    clprintm(g, q, mc, ml, (!i), wid, pb, &buf))
+			    goto end;
+		    } else if (clprintm(g, q, mc, ml, (!i), wid, NULL, NULL))
+			goto end;
+
+		    if (dolist(ml))
+			printed++;
+		    if (fl < 0)
+			fl = ml;
+
+		    if (--n)
+			for (j = ((g->flags & CGF_ROWS) ? 1 : nc);
+			     j && *q; j--)
+			    q = skipnolist(q + 1, showall);
+		    mc++;
+		}
+		while (i-- > 0) {
+		    if (clprintm(g, NULL, mc, ml, (!i),
+				 (g->widths ? g->widths[mc] : g->width),
+				 NULL, NULL))
+			goto end;
+		    mc++;
+		}
+		if (n) {
+		    if (dolistnl(ml) && compprintnl(ml))
+			goto end;
+		    ml++;
+		    if (dolistcl(ml) && cl >= 0 && --cl <= 1) {
+			cl = -1;
+			if (tccan(TCCLEAREOD))
+			    tcout(TCCLEAREOD);
+		    }
+		    if (nl)
+			for (j = ((g->flags & CGF_ROWS) ? g->cols : 1);
+			     j && *p; j--)
+			    p = skipnolist(p + 1, showall);
+		}
+		if (!mnew && ml > mlend)
+		    goto end;
+	    }
+	}
+	if (g->lcount || (showall && g->mcount))
+	    pnl = 1;
+	g = g->next;
+    }
+    asked = 0;
+ end:
+    lastlistlen = 0;
+    if (nlnct <= 1)
+	mscroll = 0;
+    if (clearflag) {
+	/* Move the cursor up to the prompt, if always_last_prompt *
+	 * is set and all that...                                  */
+	if (mlbeg >= 0) {
+	    if ((ml = listdat.nlines + nlnct) >= lines) {
+		if (mhasstat) {
+		    putc('\n', shout);
+		    compprintfmt(NULL, fl, 1, 1, mline, NULL);
+		}
+		ml = lines - 1;
+	    } else
+		ml--;
+	    tcmultout(TCUP, TCMULTUP, ml);
+	    showinglist = -1;
+
+	    lastlistlen = listdat.nlines;
+	} else if ((ml = listdat.nlines + nlnct - 1) < lines) {
+	    if (mlbeg >= 0 && tccan(TCCLEAREOL))
+		tcout(TCCLEAREOL);
+	    tcmultout(TCUP, TCMULTUP, ml);
+	    showinglist = -1;
+
+	    lastlistlen = listdat.nlines;
+	} else {
+	    clearflag = 0;
+	    if (!asked)
+		compprintnl(ml);
+	}
+    } else if (!asked)
+	compprintnl(ml);
+
+    listshown = (clearflag ? 1 : -1);
+    mnew = 0;
+
+    return printed;
+}
+
+/**/
+static int
 clprintm(Cmgroup g, Cmatch *mp, int mc, int ml, int lastc, int width,
 	 char *path, struct stat *buf)
 {
     Cmatch m;
-    int len, subcols = 0;
+    int len, subcols = 0, stop = 0, ret = 0;
 
     if (g != last_group)
         *last_cap = '\0';
@@ -649,12 +1267,14 @@
     last_group = g;
 
     if (!mp) {
-	zcputs(&mcolors, g->name, COL_SP);
-	len = width - 2;
-	while (len-- > 0)
-	    putc(' ', shout);
-	zcoff();
-	return;
+	if (dolist(ml)) {
+	    zcputs(&mcolors, g->name, COL_SP);
+	    len = width - 2;
+	    while (len-- > 0)
+		putc(' ', shout);
+	    zcoff();
+	}
+	return 0;
     }
     m = *mp;
     if (m->disp && (m->flags & CMF_DISPLINE)) {
@@ -666,6 +1286,8 @@
 		mgtab[mm + i] = g;
 	    }
 	}
+	if (!dolist(ml))
+	    return 0;
 	if (m->gnum == mselect) {
 	    int mm = (mcols * ml);
 	    mline = ml;
@@ -681,9 +1303,12 @@
 	else
 	    subcols = putmatchcol(&mcolors, g->name, m->disp);
 	if (subcols)
-	    clprintfmt(&mcolors, m->disp);
-	else
-	    printfmt(m->disp, 0, 1, 0);
+	    ret = clprintfmt(&mcolors, m->disp, ml);
+	else {
+	    compprintfmt(m->disp, 0, 1, 0, ml, &stop);
+	    if (stop)
+		ret = 1;
+	}
 	zcoff();
     } else {
 	int mx;
@@ -704,6 +1329,8 @@
 		mgtab[mx + mm + i] = g;
 	    }
 	}
+	if (!dolist(ml))
+	    return 0;
 	if (m->gnum == mselect) {
 	    int mm = mcols * ml;
 
@@ -723,9 +1350,13 @@
 	    subcols = putmatchcol(&mcolors, g->name, (m->disp ? m->disp : m->str));
 
 	if (subcols)
-	    clnicezputs(&mcolors, (m->disp ? m->disp : m->str));
+	    ret = clnicezputs(&mcolors, (m->disp ? m->disp : m->str), ml);
 	else
-	    nicezputs((m->disp ? m->disp : m->str), shout);
+	    ret = compnicezputs((m->disp ? m->disp : m->str), ml);
+	if (ret) {
+	    zcoff();
+	    return 1;
+	}
 	len = niceztrlen(m->disp ? m->disp : m->str);
 
 	 if (isset(LISTTYPES) && buf) {
@@ -751,28 +1382,30 @@
 	    zcoff();
 	}
     }
+    return ret;
 }
 
 static int
 complistmatches(Hookdef dummy, Chdata dat)
 {
     Cmgroup oamatches = amatches;
+    char *p = NULL;
 
     amatches = dat->matches;
 
-    if (minfo.asked == 2) {
+    if ((minfo.asked == 2 && mselect < 0) || nlnct >= lines) {
 	showinglist = 0;
 	amatches = oamatches;
 	return (noselect = 1);
     }
     getcols(&mcolors);
 
-    calclist(mselect >= 0);
+    mnew = ((calclist(mselect >= 0) || mlastcols != columns ||
+	     mlastlines != listdat.nlines) && mselect >= 0);
 
     if (!listdat.nlines || (mselect >= 0 &&
-			    (!(isset(USEZLE) && !termflags &&
-			       complastprompt && *complastprompt) ||
-			     (listdat.nlines + nlnct - 1) >= lines))) {
+			    !(isset(USEZLE) && !termflags &&
+			      complastprompt && *complastprompt))) {
 	showinglist = listshown = 0;
 	noselect = 1;
 	amatches = oamatches;
@@ -780,12 +1413,35 @@
     }
     if (inselect)
 	clearflag = 0;
+
+    mscroll = 0;
+
+    if (mselect >= 0 || mlbeg >= 0 ||
+	((p = getsparam("LISTMAX")) && !strcmp(p, "scroll"))) {
+	trashzle();
+	showinglist = listshown = 0;
 
-    if (asklist()) {
+	lastlistlen = 0;
+
+	if (p) {
+	    clearflag = (isset(USEZLE) && !termflags && dolastprompt);
+	    mscroll = 1;
+	} else {
+	    clearflag = 1;
+	    minfo.asked = (listdat.nlines + nlnct <= lines);
+	}
+    } else if (asklist()) {
 	amatches = oamatches;
 	return (noselect = 1);
     }
-    if (mselect >= 0) {
+    if (mlbeg >= 0) {
+	mlend = mlbeg + lines - nlnct - mhasstat;
+	while (mline >= mlend)
+	    mlbeg++, mlend++;
+    } else
+	mlend = 9999999;
+
+    if (mnew) {
 	int i;
 
 	i = columns * listdat.nlines;
@@ -795,14 +1451,13 @@
 	free(mgtab);
 	mgtab = (Cmgroup *) zalloc(i * sizeof(Cmgroup));
 	memset(mgtab, 0, i * sizeof(Cmgroup));
-	mcols = columns;
-	mlines = listdat.nlines;
+	mlastcols = mcols = columns;
+	mlastlines = mlines = listdat.nlines;
     }
     last_cap = (char *) zhalloc(max_caplen + 1);
     *last_cap = '\0';
 
-    if (!printlist(1, clprintm, (mselect >= 0)) || listdat.nlines >= lines ||
-	!clearflag)
+    if (!compprintlist(mselect >= 0) || !clearflag)
 	noselect = 1;
 
     amatches = oamatches;
@@ -849,7 +1504,7 @@
     Brinfo brbeg;
     Brinfo brend;
     int nbrbeg, nbrend;
-    int cs, acc, nmatches;
+    int cs, acc, nmatches, mline, mlbeg;
     struct menuinfo info;
     Cmgroup amatches, pmatches, lastmatches, lastlmatches;
 };
@@ -863,6 +1518,7 @@
     Thingy cmd;
     Menustack u = NULL;
     int i = 0, acc = 0, wishcol = 0, setwish = 0, oe = onlyexpl, wasnext = 0;
+    int space, lbeg = 0, step = 1;
     char *s;
 
     if (fdat || (dummy && (!(s = getsparam("SELECTMIN")) ||
@@ -873,11 +1529,47 @@
 	}
 	return 0;
     }
+    if ((s = getsparam("SELECTSCROLL"))) {
+	if (!(step = mathevali(s)))
+	    step = (lines - nlnct) >> 1;
+	else if (step < 0)
+	    if ((step += lines - nlnct) < 0)
+		step = 1;
+    }
+    mstatus = getsparam("SELECTSTATUS");
+    mhasstat = !!mstatus;
     fdat = dat;
     selectlocalmap(mskeymap);
     noselect = 0;
     mselect = (*(minfo.cur))->gnum;
+    mline = 0;
+    mlines = 999999;
+    mlbeg = 0;
     for (;;) {
+	space = lines - nlnct - mhasstat;
+	while (mline < mlbeg)
+	    if ((mlbeg -= step) < 0)
+		mlbeg = 0;
+
+	if (mlbeg && lbeg != mlbeg) {
+	    Cmatch **p = mtab + ((mlbeg - 1) * columns), **q;
+	    int c;
+
+	    while (mlbeg) {
+		for (q = p, c = columns; c; q++, c--)
+		    if (*q)
+			break;
+		if (c)
+		    break;
+		p -= columns;
+		mlbeg--;
+	    }
+	}
+	while (mline >= mlbeg + space)
+	    if ((mlbeg += step) + space > mlines)
+		mlbeg = mlines - space;
+
+	lbeg = mlbeg;
 	onlyexpl = 0;
 	showinglist = -2;
 	zrefresh();
@@ -923,6 +1615,8 @@
 	    u = s;
 	    s->line = dupstring((char *) line);
 	    s->cs = cs;
+	    s->mline = mline;
+	    s->mlbeg = mlbeg;
 	    memcpy(&(s->info), &minfo, sizeof(struct menuinfo));
 	    s->amatches = amatches;
 	    s->pmatches = pmatches;
@@ -949,15 +1643,19 @@
 	    clearlist = listshown = 1;
 	    mselect = (*(minfo.cur))->gnum;
 	    setwish = wasnext = 1;
+	    mline = 0;
 	    continue;
 	} else if (cmd == Th(z_acceptandhold) ||
 		   cmd == Th(z_acceptandmenucomplete)) {
 	    Menustack s = (Menustack) zhalloc(sizeof(*s));
+	    int ol;
 
 	    s->prev = u;
 	    u = s;
 	    s->line = dupstring((char *) line);
 	    s->cs = cs;
+	    s->mline = mline;
+	    s->mlbeg = mlbeg;
 	    memcpy(&(s->info), &minfo, sizeof(struct menuinfo));
 	    s->amatches = s->pmatches =
 		s->lastmatches = s->lastlmatches = NULL;
@@ -970,6 +1668,24 @@
 	    accept_last();
 	    do_menucmp(0);
 	    mselect = (*(minfo.cur))->gnum;
+
+	    p -= mcol;
+	    mcol = 0;
+	    ol = mline;
+	    do {
+		for (mcol = 0; mcol < mcols; mcol++, p++)
+		    if (*p == minfo.cur)
+			break;
+		if (mcol != mcols)
+		    break;
+		mline++;
+	    } while (mline != ol);
+	    if (*p != minfo.cur) {
+		noselect = clearlist = listshown = 1;
+		onlyexpl = 0;
+		zrefresh();
+		break;
+	    }
 	    setwish = 1;
 	    continue;
 	} else if (cmd == Th(z_undo)) {
@@ -986,6 +1702,8 @@
 	    menuacc = u->acc;
 	    memcpy(&minfo, &(u->info), sizeof(struct menuinfo));
 	    p = &(minfo.cur);
+	    mline = u->mline;
+	    mlbeg = u->mlbeg;
 	    if (u->lastmatches && lastmatches != u->lastmatches) {
 		if (lastmatches)
 		    freematches(lastmatches);
@@ -1043,6 +1761,97 @@
 		if (adjust_mcol(wishcol, &p, NULL))
 		    continue;
 	    } while (!*p);
+	} else if (cmd == Th(z_emacsforwardword) ||
+		   cmd == Th(z_viforwardword) ||
+		   cmd == Th(z_viforwardwordend) ||
+		   cmd == Th(z_forwardword)) {
+	    int i = lines - nlnct - 1, oi = i, ll = 0;
+	    Cmatch **lp = NULL;
+
+	    if (mline == mlines - 1)
+		goto top;
+	    while (i > 0) {
+		if (mline == mlines - 1) {
+		    if (i != oi && lp)
+			break;
+		    goto top;
+		} else {
+		    mline++;
+		    p += mcols;
+		}
+		if (adjust_mcol(wishcol, &p, NULL))
+		    continue;
+		if (*p) {
+		    i--;
+		    lp = p;
+		    ll = mline;
+		}
+	    }
+	    p = lp;
+	    mline = ll;
+	} else if (cmd == Th(z_emacsbackwardword) ||
+		   cmd == Th(z_vibackwardword) ||
+		   cmd == Th(z_backwardword)) {
+	    int i = lines - nlnct - 1, oi = i, ll = 0;
+	    Cmatch **lp = NULL;
+
+	    if (!mline)
+		goto bottom;
+	    while (i > 0) {
+		if (!mline) {
+		    if (i != oi && lp)
+			break;
+		    goto bottom;
+		} else {
+		    mline--;
+		    p -= mcols;
+		}
+		if (adjust_mcol(wishcol, &p, NULL))
+		    continue;
+		if (*p) {
+		    i--;
+		    lp = p;
+		    ll = mline;
+		}
+	    }
+	    p = lp;
+	    mline = ll;
+	} else if (cmd == Th(z_beginningofhistory)) {
+	    int ll;
+	    Cmatch **lp;
+	top:
+	    ll = mline;
+	    lp = p;
+	    while (mline) {
+		mline--;
+		p -= mcols;
+		if (adjust_mcol(wishcol, &p, NULL))
+		    continue;
+		if (*p) {
+		    lp = p;
+		    ll = mline;
+		}
+	    }
+	    mline = ll;
+	    p = lp;
+	} else if (cmd == Th(z_endofhistory)) {
+	    int ll;
+	    Cmatch **lp;
+	bottom:
+	    ll = mline;
+	    lp = p;
+	    while (mline < mlines - 1) {
+		mline++;
+		p += mcols;
+		if (adjust_mcol(wishcol, &p, NULL))
+		    continue;
+		if (*p) {
+		    lp = p;
+		    ll = mline;
+		}
+	    }
+	    mline = ll;
+	    p = lp;
 	} else if (cmd == Th(z_forwardchar) || cmd == Th(z_viforwardchar)) {
 	    int omcol = mcol;
 	    Cmatch *op = *p;
@@ -1093,10 +1902,8 @@
 		p--;
 	    }
 	    wishcol = mcols - 1;
-	} else if (cmd == Th(z_forwardword) ||
-		   cmd == Th(z_emacsforwardword) ||
-		   cmd == Th(z_viforwardword) ||
-		   cmd == Th(z_viforwardwordend)) {
+	} else if (cmd == Th(z_viforwardblankword) ||
+		   cmd == Th(z_viforwardblankwordend)) {
 	    Cmgroup g = *pg;
 	    int ol = mline;
 
@@ -1113,9 +1920,7 @@
 		if (adjust_mcol(wishcol, &p, &pg))
 		    continue;
 	    } while (ol != mline && (*pg == g || !*pg));
-	} else if (cmd == Th(z_backwardword) ||
-		   cmd == Th(z_emacsbackwardword) ||
-		   cmd == Th(z_vibackwardword)) {
+	} else if (cmd == Th(z_vibackwardblankword)) {
 	    Cmgroup g = *pg;
 	    int ol = mline;
 
@@ -1166,8 +1971,9 @@
 		freematches(u->lastmatches);
 
     selectlocalmap(NULL);
-    mselect = -1;
-    inselect = 0;
+    mselect = mlastcols = mlastlines = -1;
+    mstatus = NULL;
+    inselect = mhasstat = 0;
     if (acc) {
 	menucmp = lastambig = hasoldlist = 0;
 	do_single(*(minfo.cur));
@@ -1184,6 +1990,7 @@
 	    clearlist = 1;
 	zrefresh();
     }
+    mlbeg = -1;
     fdat = NULL;
 
     return (!noselect ^ acc);
Index: Src/Zle/compresult.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Zle/compresult.c,v
retrieving revision 1.7
diff -u -r1.7 compresult.c
--- Src/Zle/compresult.c	2000/04/13 08:09:13	1.7
+++ Src/Zle/compresult.c	2000/04/17 11:06:20
@@ -1157,7 +1157,7 @@
 }
 
 /**/
-mod_export void
+mod_export int
 calclist(int showall)
 {
     Cmgroup g;
@@ -1170,7 +1170,7 @@
     if (listdat.valid && onlyexpl == listdat.onlyexpl &&
 	menuacc == listdat.menuacc && showall == listdat.showall &&
 	lines == listdat.lines && columns == listdat.columns)
-	return;
+	return 0;
 
     for (g = amatches; g; g = g->next) {
 	char **pp = g->ylist;
@@ -1572,11 +1572,16 @@
     listdat.columns = columns;
     listdat.lines = lines;
     listdat.showall = showall;
+
+    return 1;
 }
 
 /**/
-mod_export int asklist(void)
+mod_export int
+asklist(void)
 {
+    int lmax = (complistmax ? (int) mathevali(complistmax) : 0);
+
     /* Set the cursor below the prompt. */
     trashzle();
     showinglist = listshown = 0;
@@ -1586,9 +1591,9 @@
 
     /* Maybe we have to ask if the user wants to see the list. */
     if ((!minfo.cur || !minfo.asked) &&
-	((complistmax > 0 && listdat.nlist >= complistmax) ||
-	 (complistmax < 0 && listdat.nlines <= -complistmax) ||
-	 (!complistmax && listdat.nlines >= lines))) {
+	((lmax > 0 && listdat.nlist >= lmax) ||
+	 (lmax < 0 && listdat.nlines <= -lmax) ||
+	 (!lmax && listdat.nlines >= lines))) {
 	int qup, l;
 
 	zsetterm();
@@ -1599,7 +1604,7 @@
 		     listdat.nlines));
 	qup = ((l + columns - 1) / columns) - 1;
 	fflush(shout);
-	if (getzlequery() != 'y') {
+	if (getzlequery(1) != 'y') {
 	    if (clearflag) {
 		putc('\r', shout);
 		tcmultout(TCUP, TCMULTUP, qup);
Index: Src/Zle/zle_tricky.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Zle/zle_tricky.c,v
retrieving revision 1.5
diff -u -r1.5 zle_tricky.c
--- Src/Zle/zle_tricky.c	2000/04/13 08:05:57	1.5
+++ Src/Zle/zle_tricky.c	2000/04/17 11:06:21
@@ -1997,7 +1997,7 @@
 	     fprintf(shout, "zsh: do you wish to see all %d lines? ", nlines));
 	qup = ((l + columns - 1) / columns) - 1;
 	fflush(shout);
-	if (getzlequery() != 'y') {
+	if (getzlequery(1) != 'y') {
 	    if (clearflag) {
 		putc('\r', shout);
 		tcmultout(TCUP, TCMULTUP, qup);
Index: Src/Zle/zle_utils.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Zle/zle_utils.c,v
retrieving revision 1.2
diff -u -r1.2 zle_utils.c
--- Src/Zle/zle_utils.c	2000/04/01 20:49:48	1.2
+++ Src/Zle/zle_utils.c	2000/04/17 11:06:21
@@ -277,6 +277,7 @@
  * question is assumed to have been printed already, and the    *
  * cursor is left immediately after the response echoed.        *
  * (Might cause a problem if this takes it onto the next line.) *
+ * If yesno is non-zero:                                        *
  * <Tab> is interpreted as 'y'; any other control character is  *
  * interpreted as 'n'.  If there are any characters in the      *
  * buffer, this is taken as a negative response, and no         *
@@ -284,31 +285,35 @@
 
 /**/
 mod_export int
-getzlequery(void)
+getzlequery(int yesno)
 {
     int c;
 #ifdef FIONREAD
     int val;
 
-    /* check for typeahead, which is treated as a negative response */
-    ioctl(SHTTY, FIONREAD, (char *)&val);
-    if (val) {
-	putc('n', shout);
-	return 'n';
+    if (yesno) {
+	/* check for typeahead, which is treated as a negative response */
+	ioctl(SHTTY, FIONREAD, (char *)&val);
+	if (val) {
+	    putc('n', shout);
+	    return 'n';
+	}
     }
 #endif
 
     /* get a character from the tty and interpret it */
     c = getkey(0);
-    if (c == '\t')
-	c = 'y';
-    else if (icntrl(c) || c == EOF)
-	c = 'n';
-    else
-	c = tulower(c);
-
+    if (yesno) {
+	if (c == '\t')
+	    c = 'y';
+	else if (icntrl(c) || c == EOF)
+	    c = 'n';
+	else
+	    c = tulower(c);
+    }
     /* echo response and return */
-    putc(c, shout);
+    if (c != '\n')
+	putc(c, shout);
     return c;
 }
 

--
Sven Wischnowsky                         wischnow@informatik.hu-berlin.de


^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2000-04-19  6:48 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2000-04-18  7:34 PATCH: scrolling completion lists (was: Re: Questions) Sven Wischnowsky
2000-04-18  8:47 ` Peter Stephenson
2000-04-18  9:16 ` Peter Stephenson
  -- strict thread matches above, loose matches on Subject: below --
2000-04-19  6:47 Sven Wischnowsky
2000-04-18  9:32 Sven Wischnowsky
2000-04-18  9:47 ` Peter Stephenson
2000-04-17 12:11 Sven Wischnowsky
2000-04-17 13:01 ` Peter Stephenson
2000-04-17 11:10 Sven Wischnowsky
2000-04-17 11:47 ` Peter Stephenson

Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/zsh/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).