# HG changeset patch # User Bram Moolenaar # Date 1659008704 -7200 # Node ID e988bbf50e09d72736cf4acba7dd004b8b47638e # Parent d5fdad5eaf165d705df9d2334dd89f92ea059569 patch 9.0.0099: scrollback can be wrong after redrawing the command line Commit: https://github.com/vim/vim/commit/46af7bc08debbf408d025680eeef136fb3b528ef Author: zeertzjq 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) diff --git a/src/ex_getln.c b/src/ex_getln.c --- 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 * diff --git a/src/message.c b/src/message.c --- 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(); } /* diff --git a/src/proto/message.pro b/src/proto/message.pro --- 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); diff --git a/src/testdir/test_messages.vim b/src/testdir/test_messages.vim --- 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\\\#") + 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, ":\=':'\:\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 --- 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,