vim-patch:9.2.0985: Multiline messages not visible when mapping starts cmdline (#41405)

Problem:  Multiline messages exceeding 'cmdheight' not visible when a
          mapping starts cmdline immediately after it (after 9.2.0967).
Solution: Revert patch 9.2.0967 and use a different solution (zeertzjq).

fixes:  vim/vim#21098
closes: vim/vim#21101

fb4866a2dd
This commit is contained in:
zeertzjq
2026-08-21 07:46:34 +08:00
committed by GitHub
parent 2dd6e9d6a2
commit af37d459a6
3 changed files with 48 additions and 20 deletions

View File

@@ -1453,12 +1453,10 @@ void wait_return(int redraw)
c = CAR; // just pretend CR was hit
quit_more = false;
got_int = false;
} else if (!stuff_empty() || !typebuf_typed()) {
// When there are stuffed characters or pending mapped characters, the
// next character will dismiss the hit-enter prompt immediately. A
// stuffed character then has to be put back, while a mapped character
// may even be swallowed (e.g. "g" treated as a message-scrollback key),
// so instead just don't show the hit-enter prompt at all.
} else if (!stuff_empty()) {
// When there are stuffed characters, the next stuffed character will
// dismiss the hit-enter prompt immediately and have to be put back, so
// instead just don't show the hit-enter prompt at all.
c = CAR;
} else {
State = MODE_HITRETURN;
@@ -1512,7 +1510,7 @@ void wait_return(int redraw)
// Also accept scroll-down commands when messages fill the screen,
// to avoid that typing one 'j' too many makes the messages
// disappear.
if (p_more) {
if (KeyTyped && p_more) {
if (c == 'b' || c == Ctrl_B || c == 'k' || c == 'u' || c == 'g'
|| c == K_UP || c == K_PAGEUP) {
if (msg_scrolled > Rows) {
@@ -1551,7 +1549,8 @@ void wait_return(int redraw)
if (c == K_LEFTMOUSE || c == K_MIDDLEMOUSE || c == K_RIGHTMOUSE
|| c == K_X1MOUSE || c == K_X2MOUSE) {
jump_to_mouse(MOUSE_SETPOS, NULL, 0);
} else if (vim_strchr("\r\n ", c) == NULL && c != Ctrl_C && c != 'q') {
} else if (!KeyTyped
|| (vim_strchr("\r\n ", c) == NULL && c != Ctrl_C && c != 'q')) {
// Put the character back in the typeahead buffer. Don't use the
// stuff buffer, because lmaps wouldn't work.
requeue_key(vgetc_char, vgetc_mod_mask, 0,

View File

@@ -889,15 +889,15 @@ describe('messages', function()
]])
end)
-- oldtest: Test_hit_enter_no_eat_mapped_keys()
it('hit-enter prompt does not eat keys from a mapping', function()
-- oldtest: Test_hit_enter_during_mapping()
it('hit-enter prompt during a mapping', function()
screen = Screen.new(75, 10)
exec([[
set ruler more
set ruler
call setline(1, range(1, 20))
" The 8-line :echo scrolls the screen and would raise a hit-enter prompt;
" the mapping then runs "gg" to move the cursor to line 1.
" The 8-line :echo leads to a hit-enter prompt.
nnoremap X :echo "a\nb\nc\nd\ne\nf\ng\nh"<CR>gg
nnoremap \b :echo "a\nb\nc\nd\ne\nf\ng\nh"<CR>:b<Space>
normal! 10G
]])
t.eq({ mode = 'n', blocking = false }, api.nvim_get_mode())
@@ -908,6 +908,22 @@ describe('messages', function()
-- cursor stays put. With the fix "gg" runs and moves the cursor to line 1.
t.eq({ mode = 'n', blocking = false }, api.nvim_get_mode())
t.eq({ 1, 0 }, api.nvim_win_get_cursor(0))
-- If a mapping starts cmdline after multiline messages exceeding 'cmdheight',
-- the messages should still be visible.
feed('\\b')
screen:expect([[
{3: }|
a |
b |
c |
d |
e |
f |
g |
h |
:b ^ |
]])
end)
-- oldtest: Test_fileinfo_after_last_bd()

View File

@@ -758,29 +758,42 @@ func Test_long_formatprg_no_hit_enter()
call StopVimInTerminal(buf)
endfunc
" A message shown while a mapping is still being processed must not raise a
" hit-enter prompt that eats the mapping's remaining keys.
func Test_hit_enter_no_eat_mapped_keys()
" A message shown while a mapping is still being processed must not eat the
" mapping's remaining keys.
" If a mapping starts cmdline after multiline messages exceeding 'cmdheight',
" the messages should still be visible.
func Test_hit_enter_during_mapping()
CheckRunVimInTerminal
let lines =<< trim END
set ruler
call setline(1, range(1, 20))
" The 8-line :echo scrolls the screen and would raise a hit-enter prompt;
" the mapping then runs "gg" to move the cursor to line 1.
" The 8-line :echo leads to a hit-enter prompt.
nnoremap X :echo "a\nb\nc\nd\ne\nf\ng\nh"<CR>gg
nnoremap \b :echo "a\nb\nc\nd\ne\nf\ng\nh"<CR>:b<Space>
normal! 10G
END
call writefile(lines, 'XtestHitEnterMap', 'D')
let buf = RunVimInTerminal('-S XtestHitEnterMap', #{rows: 10})
call WaitForAssert({-> assert_match('10,1', term_getline(buf, 10))})
call WaitForAssert({-> assert_match(' 10,1 ', term_getline(buf, 10))})
call term_sendkeys(buf, "X")
" Without the fix the hit-enter prompt eats the mapping's "g" keys and the
" cursor stays put. With the fix "gg" runs and moves the cursor to line 1.
call WaitForAssert({-> assert_match('1,1', term_getline(buf, 10))})
call WaitForAssert({-> assert_match(' 1,1 ', term_getline(buf, 10))})
call assert_notmatch('Press ENTER', term_getline(buf, 10))
call term_sendkeys(buf, '\b')
call WaitForAssert({-> assert_match('^:b ', term_getline(buf, 10))})
call assert_match('^a *$', term_getline(buf, 2))
call assert_match('^b *$', term_getline(buf, 3))
call assert_match('^c *$', term_getline(buf, 4))
call assert_match('^d *$', term_getline(buf, 5))
call assert_match('^e *$', term_getline(buf, 6))
call assert_match('^f *$', term_getline(buf, 7))
call assert_match('^g *$', term_getline(buf, 8))
call assert_match('^h *$', term_getline(buf, 9))
" clean up
call StopVimInTerminal(buf)
endfunc