diff src/message.c @ 446:7472c565592a v7.0117

updated for version 7.0117
author vimboss
date Wed, 27 Jul 2005 21:13:01 +0000
parents 256118bd00f4
children 8347d456f7e5
line wrap: on
line diff
--- a/src/message.c
+++ b/src/message.c
@@ -29,7 +29,12 @@ static void msg_home_replace_attr __ARGS
 static char_u *screen_puts_mbyte __ARGS((char_u *s, int l, int attr));
 #endif
 static void msg_puts_attr_len __ARGS((char_u *str, int maxlen, int attr));
-static void t_puts __ARGS((int t_col, char_u *t_s, char_u *s, int attr));
+static void msg_puts_display __ARGS((char_u *str, int maxlen, int attr, int recurse));
+static void msg_scroll_up __ARGS((void));
+static void store_sb_text __ARGS((char_u **sb_str, char_u *s, int attr, int *sb_col, int finish));
+static void t_puts __ARGS((int *t_col, char_u *t_s, char_u *s, int attr));
+static void msg_puts_printf __ARGS((char_u *str, int maxlen));
+static int do_more_prompt __ARGS((int typed_char));
 static void msg_screen_putchar __ARGS((int c, int attr));
 static int  msg_check_screen __ARGS((void));
 static void redir_write __ARGS((char_u *s, int maxlen));
@@ -924,6 +929,22 @@ wait_return(redraw)
 		c = K_IGNORE;
 	    }
 #endif
+	    if (p_more && !p_cp && (c == 'b' || c == 'k' || c == 'u'))
+	    {
+		/* scroll back to show older messages */
+		do_more_prompt(c);
+		if (quit_more)
+		{
+		    c = CAR;		/* just pretend CR was hit */
+		    quit_more = FALSE;
+		    got_int = FALSE;
+		}
+		else
+		{
+		    c = K_IGNORE;
+		    hit_return_msg();
+		}
+	    }
 	} while ((had_got_int && c == Ctrl_C)
 				|| c == K_IGNORE
 #ifdef FEAT_GUI
@@ -1031,14 +1052,18 @@ wait_return(redraw)
     static void
 hit_return_msg()
 {
-    if (msg_didout)		    /* start on a new line */
+    int		save_p_more = p_more;
+
+    p_more = FALSE;	/* don't want see this message when scrolling back */
+    if (msg_didout)	/* start on a new line */
 	msg_putchar('\n');
     if (got_int)
 	MSG_PUTS(_("Interrupt: "));
 
-    MSG_PUTS_ATTR(_("Hit ENTER or type command to continue"), hl_attr(HLF_R));
+    MSG_PUTS_ATTR(_("Press ENTER or type command to continue"), hl_attr(HLF_R));
     if (!msg_use_printf())
 	msg_clr_eos();
+    p_more = save_p_more;
 }
 
 /*
@@ -1515,7 +1540,7 @@ msg_prt_line(s, list)
     if (*s == NUL && !(list && lcs_eol != NUL))
 	msg_putchar(' ');
 
-    for (;;)
+    while (!got_int)
     {
 	if (n_extra)
 	{
@@ -1711,22 +1736,10 @@ msg_puts_attr_len(str, maxlen, attr)
     int		maxlen;
     int		attr;
 {
-    int		oldState;
-    char_u	*s = str;
-    char_u	*p;
-    char_u	buf[4];
-    char_u	*t_s = str;	/* string from "t_s" to "s" is still todo */
-    int		t_col = 0;	/* screen cells todo, 0 when "t_s" not used */
-#ifdef FEAT_MBYTE
-    int		l;
-    int		cw;
-#endif
-    int		c;
-
     /*
      * If redirection is on, also write to the redirection file.
      */
-    redir_write(s, maxlen);
+    redir_write(str, maxlen);
 
     /*
      * Don't print anything when using ":silent cmd".
@@ -1737,7 +1750,7 @@ msg_puts_attr_len(str, maxlen, attr)
     /* if MSG_HIST flag set, add message to history */
     if ((attr & MSG_HIST) && maxlen < 0)
     {
-	add_msg_hist(s, -1, attr);
+	add_msg_hist(str, -1, attr);
 	attr &= ~MSG_HIST;
     }
 
@@ -1759,72 +1772,42 @@ msg_puts_attr_len(str, maxlen, attr)
      * cursor is.
      */
     if (msg_use_printf())
-    {
-#ifdef WIN3264
-	if (!(silent_mode && p_verbose == 0))
-	    mch_settmode(TMODE_COOK);	/* handle '\r' and '\n' correctly */
-#endif
-	while (*s != NUL && (maxlen < 0 || (int)(s - str) < maxlen))
-	{
-	    if (!(silent_mode && p_verbose == 0))
-	    {
-		p = &buf[0];
-		/* NL --> CR NL translation (for Unix, not for "--version") */
-		/* NL --> CR translation (for Mac) */
-		if (*s == '\n' && !info_message)
-		    *p++ = '\r';
-#if defined(USE_CR) && !defined(MACOS_X_UNIX)
-		else
+	msg_puts_printf(str, maxlen);
+    else
+	msg_puts_display(str, maxlen, attr, FALSE);
+}
+
+/*
+ * The display part of msg_puts_attr_len().
+ * May be called recursively to display scroll-back text.
+ */
+    static void
+msg_puts_display(str, maxlen, attr, recurse)
+    char_u	*str;
+    int		maxlen;
+    int		attr;
+    int		recurse;
+{
+    char_u	*s = str;
+    char_u	*t_s = str;	/* string from "t_s" to "s" is still todo */
+    int		t_col = 0;	/* screen cells todo, 0 when "t_s" not used */
+#ifdef FEAT_MBYTE
+    int		l;
+    int		cw;
 #endif
-		    *p++ = *s;
-		*p = '\0';
-		if (info_message)	/* informative message, not an error */
-		    mch_msg((char *)buf);
-		else
-		    mch_errmsg((char *)buf);
-	    }
-
-	    /* primitive way to compute the current column */
-#ifdef FEAT_RIGHTLEFT
-	    if (cmdmsg_rl)
-	    {
-		if (*s == '\r' || *s == '\n')
-		    msg_col = Columns - 1;
-		else
-		    --msg_col;
-	    }
-	    else
-#endif
-	    {
-		if (*s == '\r' || *s == '\n')
-		    msg_col = 0;
-		else
-		    ++msg_col;
-	    }
-	    ++s;
-	}
-	msg_didout = TRUE;	    /* assume that line is not empty */
-
-#ifdef WIN3264
-	if (!(silent_mode && p_verbose == 0))
-	    mch_settmode(TMODE_RAW);
-#endif
-	return;
-    }
+    char_u	*sb_str = str;
+    int		sb_col = msg_col;
+    int		wrap;
 
     did_wait_return = FALSE;
     while (*s != NUL && (maxlen < 0 || (int)(s - str) < maxlen))
     {
 	/*
-	 * The screen is scrolled up when:
-	 * - When outputting a newline in the last row
-	 * - when outputting a character in the last column of the last row
-	 *   (some terminals scroll automatically, some don't. To avoid
-	 *   problems we scroll ourselves)
+	 * We are at the end of the screen line when:
+	 * - When outputting a newline.
+	 * - When outputting a character in the last column.
 	 */
-	if (msg_row >= Rows - 1
-		&& (*s == '\n'
-		    || (
+	if (!recurse && msg_row >= Rows - 1 && (*s == '\n' || (
 #ifdef FEAT_RIGHTLEFT
 		    cmdmsg_rl
 		    ? (
@@ -1844,47 +1827,55 @@ msg_puts_attr_len(str, maxlen, attr)
 # endif
 		      ))))
 	{
+	    /*
+	     * The screen is scrolled up when at the last row (some terminals
+	     * scroll automatically, some don't.  To avoid problems we scroll
+	     * ourselves).
+	     */
 	    if (t_col > 0)
-	    {
 		/* output postponed text */
-		t_puts(t_col, t_s, s, attr);
-		t_col = 0;
-	    }
+		t_puts(&t_col, t_s, s, attr);
 
 	    /* When no more prompt an no more room, truncate here */
 	    if (msg_no_more && lines_left == 0)
 		break;
-#ifdef FEAT_GUI
-	    /* Remove the cursor before scrolling, ScreenLines[] is going to
-	     * become invalid. */
-	    if (gui.in_use)
-		gui_undraw_cursor();
-#endif
-	    /* scrolling up always works */
-	    screen_del_lines(0, 0, 1, (int)Rows, TRUE, NULL);
-
-	    if (!can_clear((char_u *)" "))
-	    {
-		/* Scrolling up doesn't result in the right background.  Set
-		 * the background here.  It's not efficient, but avoids that
-		 * we have to do it all over the code. */
-		screen_fill((int)Rows - 1, (int)Rows, 0,
-						   (int)Columns, ' ', ' ', 0);
-
-		/* Also clear the last char of the last but one line if it was
-		 * not cleared before to avoid a scroll-up. */
-		if (ScreenAttrs[LineOffset[Rows - 2] + Columns - 1]
-							       == (sattr_T)-1)
-		    screen_fill((int)Rows - 2, (int)Rows - 1,
-				 (int)Columns - 1, (int)Columns, ' ', ' ', 0);
-	    }
+
+	    /* Scroll the screen up one line. */
+	    msg_scroll_up();
 
 	    msg_row = Rows - 2;
 	    if (msg_col >= Columns)	/* can happen after screen resize */
 		msg_col = Columns - 1;
 
+	    /* Display char in last column before showing more-prompt. */
+	    if (*s >= ' '
+#ifdef FEAT_RIGHTLEFT
+		    && !cmdmsg_rl
+#endif
+	       )
+	    {
+#ifdef FEAT_MBYTE
+		if (has_mbyte)
+		{
+		    if (enc_utf8 && maxlen >= 0)
+			/* avoid including composing chars after the end */
+			l = utfc_ptr2len_check_len(s,
+						   (int)((str + maxlen) - s));
+		    else
+			l = (*mb_ptr2len_check)(s);
+		    s = screen_puts_mbyte(s, l, attr);
+		}
+		else
+#endif
+		    msg_screen_putchar(*s++, attr);
+	    }
+
+	    if (p_more)
+		/* store text for scrolling back */
+		store_sb_text(&sb_str, s, attr, &sb_col, TRUE);
+
 	    ++msg_scrolled;
-	    need_wait_return = TRUE;	/* may need wait_return in main() */
+	    need_wait_return = TRUE; /* may need wait_return in main() */
 	    if (must_redraw < VALID)
 		must_redraw = VALID;
 	    redraw_cmdline = TRUE;
@@ -1892,170 +1883,38 @@ msg_puts_attr_len(str, maxlen, attr)
 		--cmdline_row;
 
 	    /*
-	     * if screen is completely filled wait for a character
+	     * If screen is completely filled and 'more' is set then wait
+	     * for a character.
 	     */
 	    if (p_more && --lines_left == 0 && State != HITRETURN
 					    && !msg_no_more && !exmode_active)
 	    {
-		oldState = State;
-		State = ASKMORE;
-#ifdef FEAT_MOUSE
-		setmouse();
-#endif
-		msg_moremsg(FALSE);
-		for (;;)
-		{
-		    /*
-		     * Get a typed character directly from the user.
-		     */
-		    c = get_keystroke();
-
-#if defined(FEAT_MENU) && defined(FEAT_GUI)
-		    if (c == K_MENU)
-		    {
-			int idx = get_menu_index(current_menu, ASKMORE);
-
-			/* Used a menu.  If it starts with CTRL-Y, it must
-			 * be a "Copy" for the clipboard.  Otherwise
-			 * assume that we end */
-			if (idx == MENU_INDEX_INVALID)
-			    continue;
-			c = *current_menu->strings[idx];
-			if (c != NUL && current_menu->strings[idx][1] != NUL)
-			    ins_typebuf(current_menu->strings[idx] + 1,
-				    current_menu->noremap[idx], 0, TRUE,
-				    current_menu->silent[idx]);
-		    }
-#endif
-
-		    switch (c)
-		    {
-		    case BS:
-		    case 'k':
-		    case K_UP:
-			if (!more_back_used)
-			{
-			    msg_moremsg(TRUE);
-			    continue;
-			}
-			more_back = 1;
-			lines_left = 1;
-			break;
-		    case CAR:		/* one extra line */
-		    case NL:
-		    case 'j':
-		    case K_DOWN:
-			lines_left = 1;
-			break;
-		    case ':':		/* start new command line */
 #ifdef FEAT_CON_DIALOG
-			if (!confirm_msg_used)
-#endif
-			{
-			    /* Since got_int is set all typeahead will be
-			     * flushed, but we want to keep this ':', remember
-			     * that in a special way. */
-			    typeahead_noflush(':');
-			    cmdline_row = Rows - 1;   /* put ':' on this line */
-			    skip_redraw = TRUE;	      /* skip redraw once */
-			    need_wait_return = FALSE; /* don't wait in main() */
-			}
-			/*FALLTHROUGH*/
-		    case 'q':		/* quit */
-		    case Ctrl_C:
-		    case ESC:
-#ifdef FEAT_CON_DIALOG
-			if (confirm_msg_used)
-			{
-			    /* Jump to the choices of the dialog. */
-			    s = confirm_msg_tail;
-			    lines_left = Rows - 1;
-			}
-			else
-#endif
-			{
-			    got_int = TRUE;
-			    quit_more = TRUE;
-			}
-			break;
-		    case 'u':		/* Up half a page */
-		    case K_PAGEUP:
-			if (!more_back_used)
-			{
-			    msg_moremsg(TRUE);
-			    continue;
-			}
-			more_back = Rows / 2;
-			/*FALLTHROUGH*/
-		    case 'd':		/* Down half a page */
-			lines_left = Rows / 2;
-			break;
-		    case 'b':		/* one page back */
-			if (!more_back_used)
-			{
-			    msg_moremsg(TRUE);
-			    continue;
-			}
-			more_back = Rows - 1;
-			/*FALLTHROUGH*/
-		    case ' ':		/* one extra page */
-		    case K_PAGEDOWN:
-		    case K_LEFTMOUSE:
-			lines_left = Rows - 1;
-			break;
-
-#ifdef FEAT_CLIPBOARD
-		    case Ctrl_Y:
-			/* Strange way to allow copying (yanking) a modeless
-			 * selection at the more prompt.  Use CTRL-Y,
-			 * because the same is used in Cmdline-mode and at the
-			 * hit-enter prompt.  However, scrolling one line up
-			 * might be expected... */
-			if (clip_star.state == SELECT_DONE)
-			    clip_copy_modeless_selection(TRUE);
-			continue;
-#endif
-		    default:		/* no valid response */
-			msg_moremsg(TRUE);
-			continue;
-		    }
-		    break;
-		}
-
-		/* clear the --more-- message */
-		screen_fill((int)Rows - 1, (int)Rows,
-						0, (int)Columns, ' ', ' ', 0);
-		State = oldState;
-#ifdef FEAT_MOUSE
-		setmouse();
+		if (do_more_prompt(NUL))
+		    s = confirm_msg_tail;
+#else
+		(void)do_more_prompt(NUL);
 #endif
 		if (quit_more)
-		{
-		    msg_row = Rows - 1;
-		    msg_col = 0;
-		    return;	    /* the string is not displayed! */
-		}
-#ifdef FEAT_RIGHTLEFT
-		if (cmdmsg_rl)
-		    msg_col = Columns - 1;
-#endif
+		    return;
 	    }
 	}
 
-	if (t_col > 0
-		&& (vim_strchr((char_u *)"\n\r\b\t", *s) != NULL
-		    || *s == BELL
+	wrap = *s == '\n'
 		    || msg_col + t_col >= Columns
 #ifdef FEAT_MBYTE
 		    || (has_mbyte && (*mb_ptr2cells)(s) > 1
 					    && msg_col + t_col >= Columns - 1)
 #endif
-		    ))
-	{
+		    ;
+	if (t_col > 0 && (wrap || *s == '\r' || *s == '\b'
+						 || *s == '\t' || *s == BELL))
 	    /* output any postponed text */
-	    t_puts(t_col, t_s, s, attr);
-	    t_col = 0;
-	}
+	    t_puts(&t_col, t_s, s, attr);
+
+	if (wrap && p_more && !recurse)
+	    /* store text for scrolling back */
+	    store_sb_text(&sb_str, s, attr, &sb_col, TRUE);
 
 	if (*s == '\n')		    /* go to next line */
 	{
@@ -2073,7 +1932,7 @@ msg_puts_attr_len(str, maxlen, attr)
 	    if (msg_col)
 		--msg_col;
 	}
-	else if (*s == TAB)	    /* translate into spaces */
+	else if (*s == TAB)	    /* translate Tab into spaces */
 	{
 	    do
 		msg_screen_putchar(' ', attr);
@@ -2141,17 +2000,172 @@ msg_puts_attr_len(str, maxlen, attr)
 
     /* output any postponed text */
     if (t_col > 0)
-	t_puts(t_col, t_s, s, attr);
+	t_puts(&t_col, t_s, s, attr);
+    if (p_more && !recurse)
+	store_sb_text(&sb_str, s, attr, &sb_col, FALSE);
 
     msg_check();
 }
 
 /*
+ * Scroll the screen up one line for displaying the next message line.
+ */
+    static void
+msg_scroll_up()
+{
+#ifdef FEAT_GUI
+    /* Remove the cursor before scrolling, ScreenLines[] is going
+     * to become invalid. */
+    if (gui.in_use)
+	gui_undraw_cursor();
+#endif
+    /* scrolling up always works */
+    screen_del_lines(0, 0, 1, (int)Rows, TRUE, NULL);
+
+    if (!can_clear((char_u *)" "))
+    {
+	/* Scrolling up doesn't result in the right background.  Set the
+	 * background here.  It's not efficient, but avoids that we have to do
+	 * it all over the code. */
+	screen_fill((int)Rows - 1, (int)Rows, 0, (int)Columns, ' ', ' ', 0);
+
+	/* Also clear the last char of the last but one line if it was not
+	 * cleared before to avoid a scroll-up. */
+	if (ScreenAttrs[LineOffset[Rows - 2] + Columns - 1] == (sattr_T)-1)
+	    screen_fill((int)Rows - 2, (int)Rows - 1,
+				 (int)Columns - 1, (int)Columns, ' ', ' ', 0);
+    }
+}
+
+/*
+ * To be able to scroll back at the "more" and "hit-enter" prompts we need to
+ * store the displayed text and remember where screen lines start.
+ */
+typedef struct msgchunk_S msgchunk_T;
+struct msgchunk_S
+{
+    msgchunk_T	*sb_next;
+    msgchunk_T	*sb_prev;
+    char	sb_eol;		/* TRUE when line ends after this text */
+    int		sb_msg_col;	/* column in which text starts */
+    int		sb_attr;	/* text attributes */
+    char_u	sb_text[1];	/* text to be displayed, actually longer */
+};
+
+static msgchunk_T *last_msgchunk = NULL; /* last displayed text */
+
+static msgchunk_T *msg_sb_start __ARGS((msgchunk_T *mps));
+static msgchunk_T *disp_sb_line __ARGS((int row, msgchunk_T *smp));
+
+/*
+ * Store part of a printed message for displaying when scrolling back.
+ */
+    static void
+store_sb_text(sb_str, s, attr, sb_col, finish)
+    char_u	**sb_str;	/* start of string */
+    char_u	*s;		/* just after string */
+    int		attr;
+    int		*sb_col;
+    int		finish;		/* line ends */
+{
+    msgchunk_T	*mp;
+
+    if (s > *sb_str)
+    {
+	mp = (msgchunk_T *)alloc((int)(sizeof(msgchunk_T) + (s - *sb_str)));
+	if (mp != NULL)
+	{
+	    mp->sb_eol = finish;
+	    mp->sb_msg_col = *sb_col;
+	    mp->sb_attr = attr;
+	    vim_strncpy(mp->sb_text, *sb_str, s - *sb_str);
+
+	    if (last_msgchunk == NULL)
+	    {
+		last_msgchunk = mp;
+		mp->sb_prev = NULL;
+	    }
+	    else
+	    {
+		mp->sb_prev = last_msgchunk;
+		last_msgchunk->sb_next = mp;
+		last_msgchunk = mp;
+	    }
+	    mp->sb_next = NULL;
+	}
+    }
+    else if (finish && last_msgchunk != NULL)
+	last_msgchunk->sb_eol = TRUE;
+
+    *sb_str = s;
+    *sb_col = 0;
+}
+
+/*
+ * Clear any text remembered for scrolling back.
+ * Called when redrawing the screen.
+ */
+    void
+clear_sb_text()
+{
+    msgchunk_T	*mp;
+
+    while (last_msgchunk != NULL)
+    {
+	mp = last_msgchunk->sb_prev;
+	vim_free(last_msgchunk);
+	last_msgchunk = mp;
+    }
+    last_msgchunk = NULL;
+}
+
+/*
+ * Move to the start of screen line in already displayed text.
+ */
+    static msgchunk_T *
+msg_sb_start(mps)
+    msgchunk_T *mps;
+{
+    msgchunk_T *mp = mps;
+
+    while (mp != NULL && mp->sb_prev != NULL && !mp->sb_prev->sb_eol)
+	mp = mp->sb_prev;
+    return mp;
+}
+
+/*
+ * Display a screen line from previously displayed text at row "row".
+ * Returns a pointer to the text for the next line (can be NULL).
+ */
+    static msgchunk_T *
+disp_sb_line(row, smp)
+    int		row;
+    msgchunk_T	*smp;
+{
+    msgchunk_T	*mp = smp;
+    char_u	*p;
+
+    for (;;)
+    {
+	msg_row = row;
+	msg_col = mp->sb_msg_col;
+	p = mp->sb_text;
+	if (*p == '\n')	    /* don't display the line break */
+	    ++p;
+	msg_puts_display(p, -1, mp->sb_attr, TRUE);
+	if (mp->sb_eol || mp->sb_next == NULL)
+	    break;
+	mp = mp->sb_next;
+    }
+    return mp->sb_next;
+}
+
+/*
  * Output any postponed text for msg_puts_attr_len().
  */
     static void
 t_puts(t_col, t_s, s, attr)
-    int		t_col;
+    int		*t_col;
     char_u	*t_s;
     char_u	*s;
     int		attr;
@@ -2159,7 +2173,8 @@ t_puts(t_col, t_s, s, attr)
     /* output postponed text */
     msg_didout = TRUE;		/* remember that line is not empty */
     screen_puts_len(t_s, (int)(s - t_s), msg_row, msg_col, attr);
-    msg_col += t_col;
+    msg_col += *t_col;
+    *t_col = 0;
 #ifdef FEAT_MBYTE
     /* If the string starts with a composing character don't increment the
      * column position for it. */
@@ -2173,7 +2188,6 @@ t_puts(t_col, t_s, s, attr)
     }
 }
 
-
 /*
  * Returns TRUE when messages should be printed with mch_errmsg().
  * This is used when there is no valid screen, so we can see error messages.
@@ -2193,6 +2207,309 @@ msg_use_printf()
 	       );
 }
 
+/*
+ * Print a message when there is no valid screen.
+ */
+    static void
+msg_puts_printf(str, maxlen)
+    char_u	*str;
+    int		maxlen;
+{
+    char_u	*s = str;
+    char_u	buf[4];
+    char_u	*p;
+
+#ifdef WIN3264
+    if (!(silent_mode && p_verbose == 0))
+	mch_settmode(TMODE_COOK);	/* handle '\r' and '\n' correctly */
+#endif
+    while (*s != NUL && (maxlen < 0 || (int)(s - str) < maxlen))
+    {
+	if (!(silent_mode && p_verbose == 0))
+	{
+	    /* NL --> CR NL translation (for Unix, not for "--version") */
+	    /* NL --> CR translation (for Mac) */
+	    p = &buf[0];
+	    if (*s == '\n' && !info_message)
+		*p++ = '\r';
+#if defined(USE_CR) && !defined(MACOS_X_UNIX)
+	    else
+#endif
+		*p++ = *s;
+	    *p = '\0';
+	    if (info_message)	/* informative message, not an error */
+		mch_msg((char *)buf);
+	    else
+		mch_errmsg((char *)buf);
+	}
+
+	/* primitive way to compute the current column */
+#ifdef FEAT_RIGHTLEFT
+	if (cmdmsg_rl)
+	{
+	    if (*s == '\r' || *s == '\n')
+		msg_col = Columns - 1;
+	    else
+		--msg_col;
+	}
+	else
+#endif
+	{
+	    if (*s == '\r' || *s == '\n')
+		msg_col = 0;
+	    else
+		++msg_col;
+	}
+	++s;
+    }
+    msg_didout = TRUE;	    /* assume that line is not empty */
+
+#ifdef WIN3264
+    if (!(silent_mode && p_verbose == 0))
+	mch_settmode(TMODE_RAW);
+#endif
+}
+
+/*
+ * Show the more-prompt and handle the user response.
+ * This takes care of scrolling back and displaying previously displayed text.
+ * When at hit-enter prompt "typed_char" is the already typed character.
+ * Returns TRUE when jumping ahead to "confirm_msg_tail".
+ */
+    static int
+do_more_prompt(typed_char)
+    int		typed_char;
+{
+    int		used_typed_char = typed_char;
+    int		oldState = State;
+    int		c;
+#ifdef FEAT_CON_DIALOG
+    int		retval = FALSE;
+#endif
+    int		scroll;
+    msgchunk_T	*mp_last = NULL;
+    msgchunk_T	*mp;
+    int		i;
+
+    State = ASKMORE;
+#ifdef FEAT_MOUSE
+    setmouse();
+#endif
+    msg_moremsg(FALSE);
+    for (;;)
+    {
+	/*
+	 * Get a typed character directly from the user.
+	 */
+	if (used_typed_char != NUL)
+	{
+	    c = used_typed_char;	/* was typed at hit-enter prompt */
+	    used_typed_char = NUL;
+	}
+	else
+	    c = get_keystroke();
+
+#if defined(FEAT_MENU) && defined(FEAT_GUI)
+	if (c == K_MENU)
+	{
+	    int idx = get_menu_index(current_menu, ASKMORE);
+
+	    /* Used a menu.  If it starts with CTRL-Y, it must
+	     * be a "Copy" for the clipboard.  Otherwise
+	     * assume that we end */
+	    if (idx == MENU_INDEX_INVALID)
+		continue;
+	    c = *current_menu->strings[idx];
+	    if (c != NUL && current_menu->strings[idx][1] != NUL)
+		ins_typebuf(current_menu->strings[idx] + 1,
+				current_menu->noremap[idx], 0, TRUE,
+						   current_menu->silent[idx]);
+	}
+#endif
+
+	scroll = 0;
+	switch (c)
+	{
+	case BS:		/* scroll one line back */
+	case K_BS:
+	case 'k':
+	case K_UP:
+	    scroll = -1;
+	    break;
+
+	case CAR:		/* one extra line */
+	case NL:
+	case 'j':
+	case K_DOWN:
+	    scroll = 1;
+	    break;
+
+	case 'u':		/* Up half a page */
+	case K_PAGEUP:
+	    scroll = -(Rows / 2);
+	    break;
+
+	case 'd':		/* Down half a page */
+	    scroll = Rows / 2;
+	    break;
+
+	case 'b':		/* one page back */
+	    scroll = -(Rows - 1);
+	    break;
+
+	case ' ':		/* one extra page */
+	case K_PAGEDOWN:
+	case K_LEFTMOUSE:
+	    scroll = Rows - 1;
+	    break;
+
+	case ':':		/* start new command line */
+#ifdef FEAT_CON_DIALOG
+	    if (!confirm_msg_used)
+#endif
+	    {
+		/* Since got_int is set all typeahead will be flushed, but we
+		 * want to keep this ':', remember that in a special way. */
+		typeahead_noflush(':');
+		cmdline_row = Rows - 1;		/* put ':' on this line */
+		skip_redraw = TRUE;		/* skip redraw once */
+		need_wait_return = FALSE;	/* don't wait in main() */
+	    }
+	    /*FALLTHROUGH*/
+	case 'q':		/* quit */
+	case Ctrl_C:
+	case ESC:
+#ifdef FEAT_CON_DIALOG
+	    if (confirm_msg_used)
+	    {
+		/* Jump to the choices of the dialog. */
+		retval = TRUE;
+		lines_left = Rows - 1;
+	    }
+	    else
+#endif
+	    {
+		got_int = TRUE;
+		quit_more = TRUE;
+	    }
+	    break;
+
+#ifdef FEAT_CLIPBOARD
+	case Ctrl_Y:
+	    /* Strange way to allow copying (yanking) a modeless
+	     * selection at the more prompt.  Use CTRL-Y,
+	     * because the same is used in Cmdline-mode and at the
+	     * hit-enter prompt.  However, scrolling one line up
+	     * might be expected... */
+	    if (clip_star.state == SELECT_DONE)
+		clip_copy_modeless_selection(TRUE);
+	    continue;
+#endif
+	default:		/* no valid response */
+	    msg_moremsg(TRUE);
+	    continue;
+	}
+
+	if (scroll != 0)
+	{
+	    if (scroll < 0)
+	    {
+		/* go to start of last line */
+		if (mp_last == NULL)
+		    mp = msg_sb_start(last_msgchunk);
+		else if (mp_last->sb_prev != NULL)
+		    mp = msg_sb_start(mp_last->sb_prev);
+		else
+		    mp = NULL;
+
+		/* go to start of line at top of the screen */
+		for (i = 0; i < Rows - 2 && mp != NULL && mp->sb_prev != NULL;
+									  ++i)
+		    mp = msg_sb_start(mp->sb_prev);
+
+		if (mp != NULL && mp->sb_prev != NULL)
+		{
+		    /* Find line to be displayed at top. */
+		    for (i = 0; i > scroll; --i)
+		    {
+			if (mp == NULL || mp->sb_prev == NULL)
+			    break;
+			mp = msg_sb_start(mp->sb_prev);
+			if (mp_last == NULL)
+			    mp_last = msg_sb_start(last_msgchunk);
+			else
+			    mp_last = msg_sb_start(mp_last->sb_prev);
+		    }
+
+		    if (scroll == -1 && screen_ins_lines(0, 0, 1,
+						       (int)Rows, NULL) == OK)
+		    {
+			/* clear last line, display line at top */
+			screen_fill((int)Rows - 1, (int)Rows, 0,
+						   (int)Columns, ' ', ' ', 0);
+			(void)disp_sb_line(0, mp);
+		    }
+		    else
+		    {
+			/* redisplay */
+			screenclear();
+			for (i = 0; i < Rows - 1; ++i)
+			    mp = disp_sb_line(i, mp);
+		    }
+		    scroll = 0;
+		}
+	    }
+	    else
+	    {
+		/* First display any text that we scrolled back. */
+		while (scroll > 0 && mp_last != NULL)
+		{
+		    /* scroll up, display line at bottom */
+		    msg_scroll_up();
+		    screen_fill((int)Rows - 2, (int)Rows - 1, 0,
+						   (int)Columns, ' ', ' ', 0);
+		    mp_last = disp_sb_line((int)Rows - 2, mp_last);
+		    --scroll;
+		}
+	    }
+
+	    if (scroll <= 0)
+	    {
+		/* displayed the requested text, more prompt again */
+		msg_moremsg(FALSE);
+		continue;
+	    }
+
+	    /* display more text, return to caller */
+	    lines_left = scroll;
+	}
+
+	break;
+    }
+
+    /* clear the --more-- message */
+    screen_fill((int)Rows - 1, (int)Rows, 0, (int)Columns, ' ', ' ', 0);
+    State = oldState;
+#ifdef FEAT_MOUSE
+    setmouse();
+#endif
+    if (quit_more)
+    {
+	msg_row = Rows - 1;
+	msg_col = 0;
+    }
+#ifdef FEAT_RIGHTLEFT
+    else if (cmdmsg_rl)
+	msg_col = Columns - 1;
+#endif
+
+#ifdef FEAT_CON_DIALOG
+    return retval;
+#else
+    return FALSE;
+#endif
+}
+
 #if defined(USE_MCH_ERRMSG) || defined(PROTO)
 
 #ifdef mch_errmsg
@@ -2344,15 +2661,15 @@ msg_screen_putchar(c, attr)
 msg_moremsg(full)
     int	    full;
 {
-    int	    attr;
+    int		attr;
+    char_u	*s = (char_u *)_("-- More --");
 
     attr = hl_attr(HLF_M);
-    screen_puts((char_u *)_("-- More --"), (int)Rows - 1, 0, attr);
+    screen_puts(s, (int)Rows - 1, 0, attr);
     if (full)
-	screen_puts(more_back_used
-	    ? (char_u *)_(" (RET/BS: line, SPACE/b: page, d/u: half page, q: quit)")
-	    : (char_u *)_(" (RET: line, SPACE: page, d: half page, q: quit)"),
-	    (int)Rows - 1, 10, attr);
+	screen_puts((char_u *)
+		_(" SPACE/d/j: screen/page/line down, b/u/k: up, q: quit "),
+		(int)Rows - 1, vim_strsize(s), attr);
 }
 
 /*