From f2988e05db451099645e32a427d5aaf4cae53bb4 Mon Sep 17 00:00:00 2001 From: luukvbaal Date: Fri, 27 Jun 2025 21:13:01 +0200 Subject: [PATCH] feat(extui): don't enter pager for routed message #34679 Problem: Messages routed to the pager to be shown in full, enter the pager automatically, yielding another "press-q-prompt". Solution: Only enter the pager when requested explicitly. Otherwise, close the pager on the next typed mapping, unless that mapping entered the pager. --- runtime/lua/vim/_extui/cmdline.lua | 2 +- runtime/lua/vim/_extui/messages.lua | 35 +++++++++++++++++++++------ test/functional/ui/cmdline2_spec.lua | 34 ++++++++++++++++++++++++++ test/functional/ui/messages2_spec.lua | 29 ++++++++++++++++------ 4 files changed, 84 insertions(+), 16 deletions(-) diff --git a/runtime/lua/vim/_extui/cmdline.lua b/runtime/lua/vim/_extui/cmdline.lua index c257d07ebb..3f669277fb 100644 --- a/runtime/lua/vim/_extui/cmdline.lua +++ b/runtime/lua/vim/_extui/cmdline.lua @@ -114,7 +114,7 @@ end ---@param level integer ---@param abort boolean function M.cmdline_hide(level, abort) - if M.row > 0 or level > 1 then + if M.row > 0 or level > (fn.getcmdwintype() == '' and 1 or 2) then return -- No need to hide when still in nested cmdline or cmdline_block. end diff --git a/runtime/lua/vim/_extui/messages.lua b/runtime/lua/vim/_extui/messages.lua index 312a2a2a0e..455b323e03 100644 --- a/runtime/lua/vim/_extui/messages.lua +++ b/runtime/lua/vim/_extui/messages.lua @@ -227,7 +227,7 @@ function M.show_msg(tar, content, replace_last, append, pager) count = M[tar].count + ((restart or msg == '\n') and 0 or 1) -- Ensure cmdline is clear when writing the first message. - if tar == 'cmd' and not will_pager and dupe == 0 and M.cmd.count == 0 then + if tar == 'cmd' and not will_pager and dupe == 0 and M.cmd.count == 0 and ext.cmd.row == 0 then api.nvim_buf_set_lines(ext.bufs.cmd, 0, -1, false, {}) end end @@ -450,6 +450,7 @@ function M.msg_history_show(entries) M.set_pos('pager') end +local routed = false --- Adjust dimensions of the message windows after certain events. --- ---@param type? 'cmd'|'dialog'|'msg'|'pager' Type of to be positioned window (nil for all). @@ -472,16 +473,37 @@ function M.set_pos(type) -- Ensure last line is visible and first line is at top of window. local row = (texth.all > height and texth.end_row or 0) + 1 api.nvim_win_set_cursor(ext.wins.msg, { row, 0 }) - elseif type == 'pager' and api.nvim_win_get_config(win).hide then - -- Cannot leave the cmdwin to enter the pager, so close it. - -- NOTE: regression w.r.t. the message grid, which allowed this. Resolving - -- that would require somehow bypassing textlock for the pager. + elseif type == 'pager' then if fn.getcmdwintype() ~= '' then - api.nvim_command('quit') + if will_pager then + config.relative, config.win, config.row, config.col = 'win', 0, 0, 0 + else + -- Cannot leave the cmdwin to enter the pager, so close it. + -- NOTE: regression w.r.t. the message grid, which allowed this. + -- Resolving that would require somehow bypassing textlock for the pager. + api.nvim_command('quit') + end end + routed = will_pager -- It's actually closed one event iteration later so schedule in case it was open. vim.schedule(function() + -- For a routed message, hide pager on user input (unless that input focused the pager). + if routed then + vim.on_key(function(_, typed) + if typed then + vim.schedule(function() + if routed and api.nvim_win_is_valid(win) and api.nvim_get_current_win() ~= win then + api.nvim_win_set_config(win, { hide = true }) + end + end) + end + vim.on_key(nil, ext.ns) + end, ext.ns) + return + end + + -- When explicitly opened, enter and hide when window other than the cmdwin is entered. api.nvim_set_current_win(win) api.nvim_create_autocmd({ 'WinEnter', 'CmdwinEnter', 'CmdwinLeave' }, { callback = function(ev) @@ -492,7 +514,6 @@ function M.set_pos(type) if api.nvim_win_is_valid(win) then api.nvim_win_set_config(win, config) end - -- Delete autocmd when a window other than the cmdwin is entered. return ev.event == 'WinEnter' end, desc = 'Hide inactive pager window.', diff --git a/test/functional/ui/cmdline2_spec.lua b/test/functional/ui/cmdline2_spec.lua index f2d0a28f5a..6d119887dd 100644 --- a/test/functional/ui/cmdline2_spec.lua +++ b/test/functional/ui/cmdline2_spec.lua @@ -54,4 +54,38 @@ describe('cmdline2', function() /foo^ | ]]) end) + + it('block mode', function() + feed(':if 1') + screen:expect([[ + | + {1:~ }|*11 + {16::}{15:if} {26:1} | + {16::} ^ | + ]]) + feed('echo "foo"') + screen:expect([[ + | + {1:~ }|*9 + {16::}{15:if} {26:1} | + {16::} {15:echo} {26:"foo"} | + {15:foo} | + {16::} ^ | + ]]) + feed('endif') + screen:expect([[ + | + {1:~ }|*9 + {16::}{15:if} {26:1} | + {16::} {15:echo} {26:"foo"} | + {15:foo} | + {16::} {15:endif}^ | + ]]) + feed('') + screen:expect([[ + ^ | + {1:~ }|*12 + | + ]]) + end) end) diff --git a/test/functional/ui/messages2_spec.lua b/test/functional/ui/messages2_spec.lua index 29e632b6ca..65c8afed3c 100644 --- a/test/functional/ui/messages2_spec.lua +++ b/test/functional/ui/messages2_spec.lua @@ -48,29 +48,42 @@ describe('messages2', function() -- Multiple messages in same event loop iteration are appended. feed([[q:echo "foo\nbar" | echo "baz"]]) screen:expect([[ - | + ^ | {1:~ }|*8 ─────────────────────────────────────────────────────| - {4:^foo }| + {4:foo }| {4:bar }| {4:baz }| - 1,1 All| + 0,0-1 All| + ]]) + -- Any key press closes the routed pager. + feed('j') + screen:expect([[ + ^ | + {1:~ }|*12 + 0,0-1 All| ]]) -- No error for ruler virt_text msg_row exceeding buffer length. command([[map Q echo "foo\nbar" ls]]) - feed('qQ') + feed('Q') screen:expect([[ - | + ^ | {1:~ }|*7 ─────────────────────────────────────────────────────| - {4:^foo }| + {4:foo }| {4:bar }| {4: }| {4: 1 %a "[No Name]" line 1 }| - 1,1 All| + 0,0-1 All| + ]]) + feed('') + screen:expect([[ + ^ | + {1:~ }|*12 + 0,0-1 All| ]]) -- edit_unputchar() does not clear already updated screen #34515. - feed('qixdwi') + feed('ixdwi') screen:expect([[ {18:^"} | {1:~ }|*12