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 #10807)
diff --git a/src/ex_getln.c b/src/ex_getln.c
index a5196fc..2a1fe3d 100644
--- a/src/ex_getln.c
+++ b/src/ex_getln.c
@@ -3892,6 +3892,7 @@
return;
}
+ sb_text_restart_cmdline();
msg_start();
redrawcmdprompt();
@@ -4106,7 +4107,7 @@
#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 *
diff --git a/src/message.c b/src/message.c
index 7ba82fa..50a1749 100644
--- a/src/message.c
+++ b/src/message.c
@@ -2535,6 +2535,7 @@
|| 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 @@
}
/*
- * 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();
}
/*
diff --git a/src/proto/message.pro b/src/proto/message.pro
index d3ec949..3f8a8fe 100644
--- a/src/proto/message.pro
+++ b/src/proto/message.pro
@@ -48,6 +48,7 @@
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);
diff --git a/src/testdir/test_messages.vim b/src/testdir/test_messages.vim
index 1967a3e..acdbe18 100644
--- a/src/testdir/test_messages.vim
+++ b/src/testdir/test_messages.vim
@@ -176,7 +176,9 @@
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 @@
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))})
diff --git a/src/version.c b/src/version.c
index e576860..c0a0315 100644
--- a/src/version.c
+++ b/src/version.c
@@ -736,6 +736,8 @@
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 99,
+/**/
98,
/**/
97,