From d1604e0f38fbbd0b952f2314b348a01afbeb3a12 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 12 Dec 2025 08:07:55 +0800 Subject: [PATCH] vim-patch:9.1.1969: Wrong cursor position after formatting with long 'formatprg' (#36918) Problem: Wrong cursor position after formatting with long 'formatprg'. Solution: Don't show hit-enter prompt when there are stuffed characters. Previously a stuffed character at the hit-enter prompt will dismiss the prompt immediately and be put in the typeahead buffer, which leads to incorrect behavior as the typeahead buffer is processed after the stuff buffers. Using vungetc() when KeyStuffed is TRUE can fix this problem, but since the hit-enter prompt isn't visible anyway (and is likely not desired here), just skip the prompt instead, which also avoids a wait when using "wait" instead of "hit-enter" in 'messagesopt'. fixes: vim/vim#18905 closes: vim/vim#18906 https://github.com/vim/vim/commit/50325c3d591806c57b04512dc103214acd0f2f18 (cherry picked from commit 18642a63be4f9c196f758cc365443231759faaae) --- src/nvim/getchar.c | 2 +- src/nvim/message.c | 5 +++ test/functional/legacy/messages_spec.lua | 50 ++++++++++++++++++++++++ test/old/testdir/test_messages.vim | 25 ++++++++++++ 4 files changed, 81 insertions(+), 1 deletion(-) diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index af7ab6c2a6..b88aee0805 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -426,7 +426,7 @@ bool stuff_empty(void) } /// @return true if readbuf1 is empty. There may still be redo characters in -/// redbuf2. +/// readbuf2. bool readbuf1_empty(void) FUNC_ATTR_PURE { diff --git a/src/nvim/message.c b/src/nvim/message.c index 2372c0b26a..c09b22fff3 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -1273,6 +1273,11 @@ void wait_return(int redraw) msg_puts(" "); // make sure the cursor is on the right line c = CAR; // no need for a return in ex mode 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. + c = CAR; } else { State = MODE_HITRETURN; setmouse(); diff --git a/test/functional/legacy/messages_spec.lua b/test/functional/legacy/messages_spec.lua index 8eb2436cbe..c0a95252b8 100644 --- a/test/functional/legacy/messages_spec.lua +++ b/test/functional/legacy/messages_spec.lua @@ -1,3 +1,4 @@ +local t = require('test.testutil') local n = require('test.functional.testnvim')() local Screen = require('test.functional.ui.screen') @@ -6,6 +7,7 @@ local command = n.command local exec = n.exec local feed = n.feed local api = n.api +local fn = n.fn local nvim_dir = n.nvim_dir local assert_alive = n.assert_alive @@ -751,4 +753,52 @@ describe('messages', function() | ]]) end) + + -- oldtest: Test_long_formatprg_no_hit_enter() + it("long 'formatprg' doesn't cause hit-enter prompt or wrong cursor pos", function() + t.skip(fn.executable('sed') == 0, 'missing "sed" command') + + screen = Screen.new(75, 10) + exec([[ + setlocal scrolloff=0 + call setline(1, range(1, 40)) + let &l:formatprg = $'sed{repeat(' ', &columns)}p' + normal 20Gmz + normal 10Gzt + ]]) + screen:expect([[ + ^10 | + 11 | + 12 | + 13 | + 14 | + 15 | + 16 | + 17 | + 18 | + | + ]]) + feed('gq2j') + screen:expect([[ + 10 |*2 + 11 |*2 + 12 | + ^12 | + 13 | + 14 | + 15 | + | + ]]) + feed(':messages') + screen:expect([[ + 10 |*2 + 11 |*2 + 12 | + ^12 | + 13 | + 14 | + 15 | + 3 lines filtered | + ]]) + end) end) diff --git a/test/old/testdir/test_messages.vim b/test/old/testdir/test_messages.vim index a1531f3d73..5cda0fcf29 100644 --- a/test/old/testdir/test_messages.vim +++ b/test/old/testdir/test_messages.vim @@ -681,4 +681,29 @@ func Test_messagesopt_wait() call StopVimInTerminal(buf) endfunc +" Check that using a long 'formatprg' doesn't cause a hit-enter prompt or +" wrong cursor position. +func Test_long_formatprg_no_hit_enter() + CheckScreendump + CheckExecutable sed + + let lines =<< trim END + setlocal scrolloff=0 + call setline(1, range(1, 40)) + let &l:formatprg = $'sed{repeat(' ', &columns)}p' + normal 20Gmz + normal 10Gzt + END + call writefile(lines, 'XtestLongFormatprg', 'D') + let buf = RunVimInTerminal('-S XtestLongFormatprg', #{rows: 10}) + call VerifyScreenDump(buf, 'Test_long_formatprg_no_hit_enter_1', {}) + call term_sendkeys(buf, 'gq2j') + call VerifyScreenDump(buf, 'Test_long_formatprg_no_hit_enter_2', {}) + call term_sendkeys(buf, ":messages\") + call VerifyScreenDump(buf, 'Test_long_formatprg_no_hit_enter_3', {}) + + " clean up + call StopVimInTerminal(buf) +endfunc + " vim: shiftwidth=2 sts=2 expandtab