changeset 29515:e988bbf50e09 v9.0.0099

patch 9.0.0099: scrollback can be wrong after redrawing the command line Commit: https://github.com/vim/vim/commit/46af7bc08debbf408d025680eeef136fb3b528ef Author: zeertzjq <zeertzjq@outlook.com> Date: Thu Jul 28 12:34:09 2022 +0100 patch 9.0.0099: scrollback can be wrong after redrawing the command line Problem: Scrollback can be wrong after redrawing the command line. Solution: Clear unfinished scrollback when redrawing. (closes https://github.com/vim/vim/issues/10807)
author Bram Moolenaar <Bram@vim.org>
date Thu, 28 Jul 2022 13:45:04 +0200
parents d5fdad5eaf16
children 877887b3a205
files src/ex_getln.c src/message.c src/proto/message.pro src/testdir/test_messages.vim src/version.c
diffstat 5 files changed, 56 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/src/ex_getln.c
+++ b/src/ex_getln.c
@@ -3892,6 +3892,7 @@ redrawcmd(void)
 	return;
     }
 
+    sb_text_restart_cmdline();
     msg_start();
     redrawcmdprompt();
 
@@ -4106,7 +4107,7 @@ get_cmdline_info(void)
 
 #if defined(FEAT_EVAL) || defined(FEAT_CMDWIN) || defined(PROTO)
 /*
- * Get pointer to the command line info to use. save_ccline() may clear
+ * Get pointer to the command line info to use. save_cmdline() may clear
  * ccline and put the previous value in prev_ccline.
  */
     static cmdline_info_T *
--- a/src/message.c
+++ b/src/message.c
@@ -2535,6 +2535,7 @@ store_sb_text(
 	    || do_clear_sb_text == SB_CLEAR_CMDLINE_DONE)
     {
 	clear_sb_text(do_clear_sb_text == SB_CLEAR_ALL);
+	msg_sb_eol();  // prevent messages from overlapping
 	do_clear_sb_text = SB_CLEAR_NONE;
     }
 
@@ -2579,23 +2580,58 @@ may_clear_sb_text(void)
 }
 
 /*
- * Starting to edit the command line, do not clear messages now.
+ * Starting to edit the command line: do not clear messages now.
  */
     void
 sb_text_start_cmdline(void)
 {
-    do_clear_sb_text = SB_CLEAR_CMDLINE_BUSY;
-    msg_sb_eol();
+    if (do_clear_sb_text == SB_CLEAR_CMDLINE_BUSY)
+	// Invoking command line recursively: the previous-level command line
+	// doesn't need to be remembered as it will be redrawn when returning
+	// to that level.
+	sb_text_restart_cmdline();
+    else
+    {
+	msg_sb_eol();
+	do_clear_sb_text = SB_CLEAR_CMDLINE_BUSY;
+    }
 }
 
 /*
- * Ending to edit the command line.  Clear old lines but the last one later.
+ * Redrawing the command line: clear the last unfinished line.
+ */
+    void
+sb_text_restart_cmdline(void)
+{
+    msgchunk_T *tofree;
+
+    // Needed when returning from nested command line.
+    do_clear_sb_text = SB_CLEAR_CMDLINE_BUSY;
+
+    if (last_msgchunk == NULL || last_msgchunk->sb_eol)
+	// No unfinished line: don't clear anything.
+	return;
+
+    tofree = msg_sb_start(last_msgchunk);
+    last_msgchunk = tofree->sb_prev;
+    if (last_msgchunk != NULL)
+	last_msgchunk->sb_next = NULL;
+    while (tofree != NULL)
+    {
+	msgchunk_T *tofree_next = tofree->sb_next;
+
+	vim_free(tofree);
+	tofree = tofree_next;
+    }
+}
+
+/*
+ * Ending to edit the command line: clear old lines but the last one later.
  */
     void
 sb_text_end_cmdline(void)
 {
     do_clear_sb_text = SB_CLEAR_CMDLINE_DONE;
-    msg_sb_eol();
 }
 
 /*
--- a/src/proto/message.pro
+++ b/src/proto/message.pro
@@ -48,6 +48,7 @@ void msg_puts_attr(char *s, int attr);
 int message_filtered(char_u *msg);
 void may_clear_sb_text(void);
 void sb_text_start_cmdline(void);
+void sb_text_restart_cmdline(void);
 void sb_text_end_cmdline(void);
 void clear_sb_text(int all);
 void show_sb_text(void);
--- a/src/testdir/test_messages.vim
+++ b/src/testdir/test_messages.vim
@@ -176,7 +176,9 @@ func Test_message_more()
   let buf = RunVimInTerminal('', {'rows': 6})
   call term_sendkeys(buf, ":call setline(1, range(1, 100))\n")
 
-  call term_sendkeys(buf, ":%p#\n")
+  call term_sendkeys(buf, ":%pfoo\<C-H>\<C-H>\<C-H>#")
+  call WaitForAssert({-> assert_equal(':%p#', term_getline(buf, 6))})
+  call term_sendkeys(buf, "\n")
   call WaitForAssert({-> assert_equal('  5 5', term_getline(buf, 5))})
   call WaitForAssert({-> assert_equal('-- More --', term_getline(buf, 6))})
 
@@ -252,6 +254,13 @@ func Test_message_more()
   call WaitForAssert({-> assert_equal('100 100', term_getline(buf, 5))})
   call WaitForAssert({-> assert_equal('Press ENTER or type command to continue', term_getline(buf, 6))})
 
+  " A command line that doesn't print text is appended to scrollback,
+  " even if it invokes a nested command line.
+  call term_sendkeys(buf, ":\<C-R>=':'\<CR>:\<CR>g<")
+  call WaitForAssert({-> assert_equal('100 100', term_getline(buf, 4))})
+  call WaitForAssert({-> assert_equal(':::', term_getline(buf, 5))})
+  call WaitForAssert({-> assert_equal('Press ENTER or type command to continue', term_getline(buf, 6))})
+
   call term_sendkeys(buf, ":%p#\n")
   call WaitForAssert({-> assert_equal('  5 5', term_getline(buf, 5))})
   call WaitForAssert({-> assert_equal('-- More --', term_getline(buf, 6))})
--- a/src/version.c
+++ b/src/version.c
@@ -736,6 +736,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    99,
+/**/
     98,
 /**/
     97,