From 82c751db4ee910dae9157ab1e29dfbeb2574e7f4 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 18 Aug 2026 09:23:34 +0800 Subject: [PATCH] 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. https://github.com/vim/vim/commit/6025ea9e029b0681df37ee19e0d3992fb7f4d7fd Co-authored-by: XiaowenHu96 --- src/nvim/message.c | 10 +++++---- test/functional/legacy/messages_spec.lua | 21 ++++++++++++++++++ test/old/testdir/test_messages.vim | 27 ++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 4 deletions(-) diff --git a/src/nvim/message.c b/src/nvim/message.c index bfb16fa273..d55b0f65ec 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -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; diff --git a/test/functional/legacy/messages_spec.lua b/test/functional/legacy/messages_spec.lua index 786e916d00..8a359dac76 100644 --- a/test/functional/legacy/messages_spec.lua +++ b/test/functional/legacy/messages_spec.lua @@ -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"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) diff --git a/test/old/testdir/test_messages.vim b/test/old/testdir/test_messages.vim index 3c1080b5e4..bd4a6df075 100644 --- a/test/old/testdir/test_messages.vim +++ b/test/old/testdir/test_messages.vim @@ -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"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