vim-patch:9.2.0967: hit-enter prompt eats keys from a running mapping (#41359)

Problem:  The hit-enter prompt fires whenever a message scrolls the screen.
          When this happens while a mapping is being processed, it consumes
          the mapping's next key, causing unexpected behavior for users.
Solution: Similar to what 9.1.1969 did for stuffed characters, skip the
          hit-enter prompt when there are still keys pending from a mapping
          in the typeahead buffer.

related: neovim/neovim#38298
related: neovim/neovim#20635
related: neovim/neovim#30890
closes:  vim/vim#20753

AI assisted.

6025ea9e02

Co-authored-by: XiaowenHu96 <me@xiaowenhu.com>
This commit is contained in:
zeertzjq
2026-08-18 09:23:34 +08:00
committed by GitHub
parent bce3bf06a3
commit 82c751db4e
3 changed files with 54 additions and 4 deletions

View File

@@ -1453,10 +1453,12 @@ void wait_return(int redraw)
c = CAR; // just pretend CR was hit
quit_more = false;
got_int = false;
} 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.
} 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.
c = CAR;
} else {
State = MODE_HITRETURN;

View File

@@ -889,6 +889,27 @@ describe('messages', function()
]])
end)
-- oldtest: Test_hit_enter_no_eat_mapped_keys()
it('hit-enter prompt does not eat keys from a mapping', function()
screen = Screen.new(75, 10)
exec([[
set ruler more
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.
nnoremap X :echo "a\nb\nc\nd\ne\nf\ng\nh"<CR>gg
normal! 10G
]])
t.eq({ mode = 'n', blocking = false }, api.nvim_get_mode())
t.eq({ 10, 0 }, api.nvim_win_get_cursor(0))
feed('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.
t.eq({ mode = 'n', blocking = false }, api.nvim_get_mode())
t.eq({ 1, 0 }, api.nvim_win_get_cursor(0))
end)
-- oldtest: Test_fileinfo_after_last_bd()
it('fileinfo is shown after :bd on last listed buffer', function()
screen = Screen.new(50, 10)

View File

@@ -758,6 +758,33 @@ 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()
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.
nnoremap X :echo "a\nb\nc\nd\ne\nf\ng\nh"<CR>gg
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 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 assert_notmatch('Press ENTER', term_getline(buf, 10))
" clean up
call StopVimInTerminal(buf)
endfunc
" Test that fileinfo is shown after deleting the last listed buffer with :bd
func Test_fileinfo_after_last_bd()
CheckRunVimInTerminal