aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/nvim/ex_docmd.c8
-rw-r--r--src/nvim/message.c4
-rw-r--r--src/nvim/testdir/test_cmdline.vim45
-rw-r--r--src/nvim/testdir/test_messages.vim32
-rw-r--r--test/functional/legacy/cmdline_spec.lua68
-rw-r--r--test/functional/legacy/messages_spec.lua37
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)