diff options
-rw-r--r-- | src/nvim/ex_docmd.c | 8 | ||||
-rw-r--r-- | src/nvim/message.c | 4 | ||||
-rw-r--r-- | src/nvim/testdir/test_cmdline.vim | 45 | ||||
-rw-r--r-- | src/nvim/testdir/test_messages.vim | 32 | ||||
-rw-r--r-- | test/functional/legacy/cmdline_spec.lua | 68 | ||||
-rw-r--r-- | test/functional/legacy/messages_spec.lua | 37 |
6 files changed, 190 insertions, 4 deletions
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 52841b6021..534cc6dcfb 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -6089,13 +6089,17 @@ static void ex_redrawstatus(exarg_T *eap) int r = RedrawingDisabled; int p = p_lz; - RedrawingDisabled = 0; - p_lz = false; if (eap->forceit) { status_redraw_all(); } else { status_redraw_curbuf(); } + if (msg_scrolled) { + return; // redraw later + } + + RedrawingDisabled = 0; + p_lz = false; update_screen(VIsual_active ? UPD_INVERTED : 0); RedrawingDisabled = r; p_lz = p; diff --git a/src/nvim/message.c b/src/nvim/message.c index dc2b91d1b1..c93e825a5d 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -596,10 +596,10 @@ void msg_source(int attr) } recursive = true; - msg_scroll = true; // this will take more than one line no_wait_return++; char *p = get_emsg_source(); if (p != NULL) { + msg_scroll = true; // this will take more than one line msg_attr(p, attr); xfree(p); } @@ -739,7 +739,7 @@ static bool emsg_multiline(const char *s, bool multiline) } // Display name and line number for the source of the error. - // Sets "msg_scroll". + msg_scroll = true; msg_source(attr); // Display the error message itself. diff --git a/src/nvim/testdir/test_cmdline.vim b/src/nvim/testdir/test_cmdline.vim index 7443ff8fa4..9fc92b8f25 100644 --- a/src/nvim/testdir/test_cmdline.vim +++ b/src/nvim/testdir/test_cmdline.vim @@ -127,6 +127,51 @@ func Test_wildmenu_screendump() call delete('XTest_wildmenu') endfunc +func Test_redraw_in_autocmd() + CheckScreendump + + let lines =<< trim END + set cmdheight=2 + autocmd CmdlineChanged * redraw + END + call writefile(lines, 'XTest_redraw', 'D') + + let buf = RunVimInTerminal('-S XTest_redraw', {'rows': 8}) + call term_sendkeys(buf, ":for i in range(3)\<CR>") + call VerifyScreenDump(buf, 'Test_redraw_in_autocmd_1', {}) + + call term_sendkeys(buf, "let i =") + call VerifyScreenDump(buf, 'Test_redraw_in_autocmd_2', {}) + + " clean up + call term_sendkeys(buf, "\<CR>") + call StopVimInTerminal(buf) +endfunc + +func Test_redrawstatus_in_autocmd() + CheckScreendump + + let lines =<< trim END + set laststatus=2 + set statusline=%=:%{getcmdline()} + autocmd CmdlineChanged * if getcmdline() == 'foobar' | redrawstatus | endif + END + call writefile(lines, 'XTest_redrawstatus', 'D') + + let buf = RunVimInTerminal('-S XTest_redrawstatus', {'rows': 8}) + " :redrawstatus is postponed if messages have scrolled + call term_sendkeys(buf, ":echo \"one\\ntwo\\nthree\\nfour\"\<CR>") + call term_sendkeys(buf, ":foobar") + call VerifyScreenDump(buf, 'Test_redrawstatus_in_autocmd_1', {}) + " it is not postponed if messages have not scrolled + call term_sendkeys(buf, "\<Esc>:foobar") + call VerifyScreenDump(buf, 'Test_redrawstatus_in_autocmd_2', {}) + + " clean up + call term_sendkeys(buf, "\<CR>") + call StopVimInTerminal(buf) +endfunc + func Test_changing_cmdheight() CheckScreendump diff --git a/src/nvim/testdir/test_messages.vim b/src/nvim/testdir/test_messages.vim index a83fcd7138..0f348c22cb 100644 --- a/src/nvim/testdir/test_messages.vim +++ b/src/nvim/testdir/test_messages.vim @@ -171,6 +171,38 @@ func Test_echospace() set ruler& showcmd& endfunc +func Test_warning_scroll() + CheckRunVimInTerminal + let lines =<< trim END + call test_override('ui_delay', 50) + set noruler + set readonly + undo + END + call writefile(lines, 'XTestWarningScroll', 'D') + let buf = RunVimInTerminal('', #{rows: 8}) + + " When the warning comes from a script, messages are scrolled so that the + " stacktrace is visible. + call term_sendkeys(buf, ":source XTestWarningScroll\n") + " only match the final colon in the line that shows the source + call WaitForAssert({-> assert_match(':$', term_getline(buf, 5))}) + call WaitForAssert({-> assert_equal('line 4:W10: Warning: Changing a readonly file', term_getline(buf, 6))}) + call WaitForAssert({-> assert_equal('Already at oldest change', term_getline(buf, 7))}) + call WaitForAssert({-> assert_equal('Press ENTER or type command to continue', term_getline(buf, 8))}) + call term_sendkeys(buf, "\n") + + " When the warning does not come from a script, messages are not scrolled. + call term_sendkeys(buf, ":enew\n") + call term_sendkeys(buf, ":set readonly\n") + call term_sendkeys(buf, 'u') + call WaitForAssert({-> assert_equal('W10: Warning: Changing a readonly file', term_getline(buf, 8))}) + call WaitForAssert({-> assert_equal('Already at oldest change', term_getline(buf, 8))}) + + " clean up + call StopVimInTerminal(buf) +endfunc + " Test more-prompt (see :help more-prompt). func Test_message_more() CheckRunVimInTerminal diff --git a/test/functional/legacy/cmdline_spec.lua b/test/functional/legacy/cmdline_spec.lua index 99d2d0f30e..8325f7eeb0 100644 --- a/test/functional/legacy/cmdline_spec.lua +++ b/test/functional/legacy/cmdline_spec.lua @@ -140,6 +140,74 @@ describe('cmdline', function() :^ | ]]) end) + + -- oldtest: Test_redraw_in_autocmd() + it('cmdline cursor position is correct after :redraw with cmdheight=2', function() + local screen = Screen.new(30, 6) + screen:set_default_attr_ids({ + [0] = {bold = true, foreground = Screen.colors.Blue}, -- NonText + }) + screen:attach() + exec([[ + set cmdheight=2 + autocmd CmdlineChanged * redraw + ]]) + feed(':for i in range(3)<CR>') + screen:expect([[ + | + {0:~ }| + {0:~ }| + {0:~ }| + :for i in range(3) | + : ^ | + ]]) + feed(':let i =') + -- Note: this may still be considered broken, ref #18140 + screen:expect([[ + | + {0:~ }| + {0:~ }| + {0:~ }| + : :let i =^ | + | + ]]) + end) + + -- oldtest: Test_redrawstatus_in_autocmd() + it(':redrawstatus in cmdline mode', function() + local screen = Screen.new(60, 6) + screen:set_default_attr_ids({ + [0] = {bold = true, foreground = Screen.colors.Blue}, -- NonText + [1] = {bold = true, reverse = true}, -- MsgSeparator, StatusLine + }) + screen:attach() + exec([[ + set laststatus=2 + set statusline=%=:%{getcmdline()} + autocmd CmdlineChanged * if getcmdline() == 'foobar' | redrawstatus | endif + ]]) + -- :redrawstatus is postponed if messages have scrolled + feed([[:echo "one\ntwo\nthree\nfour"<CR>]]) + feed(':foobar') + screen:expect([[ + {1: }| + one | + two | + three | + four | + :foobar^ | + ]]) + -- it is not postponed if messages have not scrolled + feed('<Esc>:foobar') + screen:expect([[ + | + {0:~ }| + {0:~ }| + {0:~ }| + {1: :foobar}| + :foobar^ | + ]]) + end) end) describe('cmdwin', function() diff --git a/test/functional/legacy/messages_spec.lua b/test/functional/legacy/messages_spec.lua index 159cf7a551..c76ce62ef0 100644 --- a/test/functional/legacy/messages_spec.lua +++ b/test/functional/legacy/messages_spec.lua @@ -10,6 +10,43 @@ before_each(clear) describe('messages', function() local screen + -- oldtest: Test_warning_scroll() + it('a warning causes scrolling if and only if it has a stacktrace', function() + screen = Screen.new(75, 6) + screen:set_default_attr_ids({ + [0] = {bold = true, foreground = Screen.colors.Blue}, -- NonText + [1] = {bold = true, foreground = Screen.colors.SeaGreen}, -- MoreMsg + [2] = {bold = true, reverse = true}, -- MsgSeparator + [3] = {foreground = Screen.colors.Red}, -- WarningMsg + }) + screen:attach() + + -- When the warning comes from a script, messages are scrolled so that the + -- stacktrace is visible. + -- It is a bit hard to assert the screen when sourcing a script, so skip this part. + + -- When the warning does not come from a script, messages are not scrolled. + command('enew') + command('set readonly') + feed('u') + screen:expect({grid = [[ + | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {3:W10: Warning: Changing a readonly file}^ | + ]], timeout = 500}) + screen:expect([[ + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + Already at oldest change | + ]]) + end) + describe('more prompt', function() before_each(function() screen = Screen.new(75, 6) |