commit f2988e05db451099645e32a427d5aaf4cae53bb4
parent bfe42c84de053abe125f7a61116bc8a97ec32cde
Author: luukvbaal <luukvbaal@gmail.com>
Date: Fri, 27 Jun 2025 21:13:01 +0200
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.
Diffstat:
4 files changed, 84 insertions(+), 16 deletions(-)
diff --git 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
@@ -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
@@ -54,4 +54,38 @@ describe('cmdline2', function()
/foo^ |
]])
end)
+
+ it('block mode', function()
+ feed(':if 1<CR>')
+ screen:expect([[
+ |
+ {1:~ }|*11
+ {16::}{15:if} {26:1} |
+ {16::} ^ |
+ ]])
+ feed('echo "foo"<CR>')
+ 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('<CR>')
+ screen:expect([[
+ ^ |
+ {1:~ }|*12
+ |
+ ]])
+ end)
end)
diff --git 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"<CR>]])
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 <cmd>echo "foo\nbar" <bar> ls<CR>]])
- 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('<Esc>')
+ screen:expect([[
+ ^ |
+ {1:~ }|*12
+ 0,0-1 All|
]])
-- edit_unputchar() does not clear already updated screen #34515.
- feed('qix<Esc>dwi<C-r>')
+ feed('ix<Esc>dwi<C-r>')
screen:expect([[
{18:^"} |
{1:~ }|*12