feat(extui): show dismissed message in cmdline (#34745)

Problem:  An accidental key press can dismiss a routed message to be
          shown in full before the user was able to read it.
          'verbose' message routing based on an outdated condition results
          in "last_set" messages being separated from its message pair.
Solution: Show a message to be shown in full in the cmdline window instead
          of the pager. Keep it there and update the spill indicator when
          the message is dismissed.
          Remove the 'verbose' message routing.
This commit is contained in:
luukvbaal
2025-07-09 11:17:18 +02:00
committed by GitHub
parent 88774965e5
commit 3c9484b550
2 changed files with 133 additions and 115 deletions

View File

@@ -4,9 +4,8 @@ local ext = require('vim._extui.shared')
---@class vim._extui.messages ---@class vim._extui.messages
local M = { local M = {
-- Message window. Used for regular messages with 'cmdheight' == 0 or, -- Message window. Used for regular messages with 'cmdheight' == 0 or,
-- cfg.msg.target == 'msg'. Also used for verbose messages regardless of -- cfg.msg.target == 'msg'. Automatically resizes to the text dimensions up to
-- cfg.msg.target. Automatically resizes to the text dimensions up to a point, -- a point, at which point only the most recent messages will fit and be shown.
-- at which point only the most recent messages will fit and be shown.
-- A timer is started for each message whose callback will remove the message -- A timer is started for each message whose callback will remove the message
-- from the window again. -- from the window again.
msg = { msg = {
@@ -20,7 +19,6 @@ local M = {
-- to indicate the number of spilled lines and repeated messages. -- to indicate the number of spilled lines and repeated messages.
cmd = { cmd = {
count = 0, -- Number of messages currently in the message window. count = 0, -- Number of messages currently in the message window.
lines = 0, -- Number of lines in cmdline buffer (including wrapped lines).
msg_row = -1, -- Last row of message to distinguish for placing virt_text. msg_row = -1, -- Last row of message to distinguish for placing virt_text.
last_col = o.columns, -- Crop text to start column of 'last' virt_text. last_col = o.columns, -- Crop text to start column of 'last' virt_text.
last_emsg = 0, -- Time an error was printed that should not be overwritten. last_emsg = 0, -- Time an error was printed that should not be overwritten.
@@ -37,7 +35,7 @@ local M = {
} }
function M.msg:close() function M.msg:close()
self.width, M.virt.msg = 1, { {}, {} } self.width, M.virt.msg[M.virt.idx.dupe][1] = 1, nil
M.prev_msg = ext.cfg.msg.target == 'msg' and '' or M.prev_msg M.prev_msg = ext.cfg.msg.target == 'msg' and '' or M.prev_msg
api.nvim_buf_clear_namespace(ext.bufs.msg, -1, 0, -1) api.nvim_buf_clear_namespace(ext.bufs.msg, -1, 0, -1)
if api.nvim_win_is_valid(ext.wins.msg) then if api.nvim_win_is_valid(ext.wins.msg) then
@@ -65,12 +63,13 @@ function M.msg:start_timer(buf, len)
end, ext.cfg.msg.timeout) end, ext.cfg.msg.timeout)
end end
local cmd_on_key = nil
--- Place or delete a virtual text mark in the cmdline or message window. --- Place or delete a virtual text mark in the cmdline or message window.
--- ---
---@param type 'last'|'msg' ---@param type 'last'|'msg'
local function set_virttext(type) local function set_virttext(type)
if type == 'last' and (ext.cmdheight == 0 or M.virt.delayed) then if (type == 'last' and (ext.cmdheight == 0 or M.virt.delayed)) or cmd_on_key then
return return -- Don't show virtual text while cmdline, error or full message in cmdline is shown.
end end
-- Concatenate the components of M.virt[type] and calculate the concatenated width. -- Concatenate the components of M.virt[type] and calculate the concatenated width.
@@ -91,13 +90,13 @@ local function set_virttext(type)
local tar = type == 'msg' and ext.cfg.msg.target or 'cmd' local tar = type == 'msg' and ext.cfg.msg.target or 'cmd'
local win = ext.wins[tar] local win = ext.wins[tar]
local erow = tar == 'cmd' and math.min(M.cmd.msg_row, api.nvim_buf_line_count(ext.bufs.cmd) - 1) local erow = tar == 'cmd' and math.min(M.cmd.msg_row, api.nvim_buf_line_count(ext.bufs.cmd) - 1)
local h = api.nvim_win_text_height(win, { local texth = api.nvim_win_text_height(win, {
max_height = api.nvim_win_get_height(win), max_height = api.nvim_win_get_height(win),
start_row = tar == 'msg' and fn.line('w0', ext.wins.msg) - 1 or nil, start_row = tar == 'msg' and fn.line('w0', ext.wins.msg) - 1 or nil,
end_row = erow or nil, end_row = erow or nil,
}) })
local row = h.end_row ---@type integer local row = texth.end_row
local col = fn.virtcol2col(win, row + 1, h.end_vcol) local col = fn.virtcol2col(win, row + 1, texth.end_vcol)
local scol = fn.screenpos(win, row + 1, col).col ---@type integer local scol = fn.screenpos(win, row + 1, col).col ---@type integer
if type == 'msg' then if type == 'msg' then
@@ -116,7 +115,7 @@ local function set_virttext(type)
local mwidth = tar == 'msg' and M.msg.width or M.cmd.last_col local mwidth = tar == 'msg' and M.msg.width or M.cmd.last_col
if scol - offset + width > mwidth then if scol - offset + width > mwidth then
col = fn.virtcol2col(win, row + 1, h.end_vcol - (scol - offset + width - mwidth)) col = fn.virtcol2col(win, row + 1, texth.end_vcol - (scol - offset + width - mwidth))
end end
-- Give virt_text the same highlight as the message tail. -- Give virt_text the same highlight as the message tail.
@@ -128,7 +127,7 @@ local function set_virttext(type)
else else
local mode = #M.virt.last[M.virt.idx.mode] local mode = #M.virt.last[M.virt.idx.mode]
local pad = o.columns - width ---@type integer local pad = o.columns - width ---@type integer
local newlines = math.max(0, ext.cmdheight - h.all) local newlines = math.max(0, ext.cmdheight - texth.all)
row = row + newlines row = row + newlines
M.cmd.last_col = mode > 0 and 0 or o.columns - (newlines > 0 and 0 or width) M.cmd.last_col = mode > 0 and 0 or o.columns - (newlines > 0 and 0 or width)
@@ -149,7 +148,7 @@ local function set_virttext(type)
end end
-- Crop text on last screen row and find byte offset to place mark at. -- Crop text on last screen row and find byte offset to place mark at.
local vcol = h.end_vcol - (scol - M.cmd.last_col) ---@type integer local vcol = texth.end_vcol - (scol - M.cmd.last_col)
col = vcol <= 0 and 0 or fn.virtcol2col(win, row + 1, vcol) col = vcol <= 0 and 0 or fn.virtcol2col(win, row + 1, vcol)
M.prev_msg = mode > 0 and '' or M.prev_msg M.prev_msg = mode > 0 and '' or M.prev_msg
M.virt.msg = mode > 0 and { {}, {} } or M.virt.msg M.virt.msg = mode > 0 and { {}, {} } or M.virt.msg
@@ -176,31 +175,39 @@ end
-- We need to keep track of the current message column to be able to -- We need to keep track of the current message column to be able to
-- append or overwrite messages for :echon or carriage returns. -- append or overwrite messages for :echon or carriage returns.
local col, will_pager, hlopts = 0, false, { undo_restore = false, invalidate = true, priority = 1 } local col, will_full, hlopts = 0, false, { undo_restore = false, invalidate = true, priority = 1 }
--- Move message to pager, appending if window was already open. --- Move messages to cmdline or pager to show in full.
local function msg_to_pager(tar) local function msg_to_full(src)
if will_pager then if will_full then
return return
end end
will_pager, M.prev_msg = true, '' will_full, M.prev_msg = true, ''
vim.schedule(function() vim.schedule(function()
-- Copy and clear message from src to enlarged cmdline that is dismissed by any
-- key press, or append to pager in case that is already open (not hidden).
local hidden = api.nvim_win_get_config(ext.wins.pager).hide local hidden = api.nvim_win_get_config(ext.wins.pager).hide
local marks = api.nvim_buf_get_extmarks(ext.bufs[tar], -1, 0, -1, { details = true }) local tar = hidden and 'cmd' or 'pager'
local lines = api.nvim_buf_get_lines(ext.bufs[tar], 0, -1, false) if tar ~= src then
api.nvim_buf_set_lines(ext.bufs.pager, hidden and 0 or -1, -1, false, lines) local srow = hidden and 0 or api.nvim_buf_line_count(ext.bufs.pager)
local rows = api.nvim_buf_line_count(ext.bufs.pager) - #lines local marks = api.nvim_buf_get_extmarks(ext.bufs[src], -1, 0, -1, { details = true })
api.nvim_buf_set_lines(ext.bufs[tar], 0, -1, false, {}) local lines = api.nvim_buf_get_lines(ext.bufs[src], 0, -1, false)
for _, mark in ipairs(marks) do api.nvim_buf_set_lines(ext.bufs[src], 0, -1, false, {})
hlopts.end_col, hlopts.hl_group = mark[4].end_col, mark[4].hl_group api.nvim_buf_set_lines(ext.bufs[tar], srow, -1, false, lines)
api.nvim_buf_set_extmark(ext.bufs.pager, ext.ns, mark[2] + rows, mark[3], hlopts) for _, mark in ipairs(marks) do
hlopts.end_col, hlopts.hl_group = mark[4].end_col, mark[4].hl_group
api.nvim_buf_set_extmark(ext.bufs[tar], ext.ns, srow + mark[2], mark[3], hlopts)
end
api.nvim_command('norm! G')
M.virt.msg[M.virt.idx.spill][1] = nil
else
for _, id in pairs(M.virt.ids) do
api.nvim_buf_del_extmark(ext.bufs.cmd, ext.ns, id)
end
end end
M.msg:close() M.msg:close()
M.set_pos('pager') M.set_pos(tar)
if not hidden then M[src].count, col, will_full = 0, 0, false
api.nvim_command('norm! G')
end
M[tar].count, col, will_pager = 0, 0, false
end) end)
end end
@@ -208,8 +215,8 @@ end
---@param content MsgContent ---@param content MsgContent
---@param replace_last boolean ---@param replace_last boolean
---@param append boolean ---@param append boolean
---@param pager boolean? If true, route messages that exceed the target window to the pager. ---@param full boolean? If true, show messages that exceed target window in full.
function M.show_msg(tar, content, replace_last, append, pager) function M.show_msg(tar, content, replace_last, append, full)
local msg, restart, cr, dupe, count = '', false, false, 0, 0 local msg, restart, cr, dupe, count = '', false, false, 0, 0
append = append and col > 0 append = append and col > 0
@@ -227,7 +234,7 @@ function M.show_msg(tar, content, replace_last, append, pager)
count = M[tar].count + ((restart or msg == '\n') and 0 or 1) count = M[tar].count + ((restart or msg == '\n') and 0 or 1)
-- Ensure cmdline is clear when writing the first message. -- Ensure cmdline is clear when writing the first message.
if tar == 'cmd' and not will_pager and dupe == 0 and M.cmd.count == 0 and ext.cmd.row == 0 then if tar == 'cmd' and not will_full 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, {}) api.nvim_buf_set_lines(ext.bufs.cmd, 0, -1, false, {})
end end
end end
@@ -240,7 +247,7 @@ function M.show_msg(tar, content, replace_last, append, pager)
local line_count = api.nvim_buf_line_count(ext.bufs[tar]) local line_count = api.nvim_buf_line_count(ext.bufs[tar])
---@type integer Start row after last line in the target buffer, unless ---@type integer Start row after last line in the target buffer, unless
---this is the first message, or in case of a repeated or replaced message. ---this is the first message, or in case of a repeated or replaced message.
local row = M[tar] and count <= 1 and not will_pager and (tar == 'cmd' and ext.cmd.row or 0) local row = M[tar] and count <= 1 and not will_full and (tar == 'cmd' and ext.cmd.row or 0)
or line_count - ((replace_last or restart or cr or append) and 1 or 0) or line_count - ((replace_last or restart or cr or append) and 1 or 0)
local curline = (cr or append) and api.nvim_buf_get_lines(ext.bufs[tar], row, row + 1, false)[1] local curline = (cr or append) and api.nvim_buf_get_lines(ext.bufs[tar], row, row + 1, false)[1]
local start_row, width = row, M.msg.width local start_row, width = row, M.msg.width
@@ -278,9 +285,9 @@ function M.show_msg(tar, content, replace_last, append, pager)
if tar == 'msg' then if tar == 'msg' then
api.nvim_win_set_width(ext.wins.msg, width) api.nvim_win_set_width(ext.wins.msg, width)
local h = api.nvim_win_text_height(ext.wins.msg, { start_row = start_row }) local texth = api.nvim_win_text_height(ext.wins.msg, { start_row = start_row })
if pager and h.all > 1 then if full and texth.all > 1 then
msg_to_pager(tar) msg_to_full(tar)
return return
end end
@@ -302,21 +309,21 @@ function M.show_msg(tar, content, replace_last, append, pager)
ext.cmd.cmdline_show({}, 0, ':', '', ext.cmd.indent, 0, 0) ext.cmd.cmdline_show({}, 0, ':', '', ext.cmd.indent, 0, 0)
api.nvim__redraw({ flush = true, cursor = true, win = ext.wins.cmd }) api.nvim__redraw({ flush = true, cursor = true, win = ext.wins.cmd })
else else
local h = api.nvim_win_text_height(ext.wins.cmd, {}) api.nvim_win_set_cursor(ext.wins.cmd, { 1, 0 }) -- ensure first line is visible
local want_pager = pager or will_pager or not api.nvim_win_get_config(ext.wins.pager).hide
if want_pager and h.all > ext.cmdheight then
msg_to_pager(tar)
return
end
api.nvim_win_set_cursor(ext.wins[tar], { 1, 0 })
if ext.cmd.highlighter then if ext.cmd.highlighter then
ext.cmd.highlighter.active[ext.bufs.cmd] = nil ext.cmd.highlighter.active[ext.bufs.cmd] = nil
end end
-- Place [+x] indicator for lines that spill over 'cmdheight'. -- Place [+x] indicator for lines that spill over 'cmdheight'.
M.cmd.lines, M.cmd.msg_row = h.all, h.end_row local texth = api.nvim_win_text_height(ext.wins.cmd, {})
local spill = M.cmd.lines > ext.cmdheight and ('[+%d]'):format(M.cmd.lines - ext.cmdheight) local spill = texth.all > ext.cmdheight and ('[+%d]'):format(texth.all - ext.cmdheight)
M.virt.msg[M.virt.idx.spill][1] = spill and { 0, spill } or nil M.virt.msg[M.virt.idx.spill][1] = spill and { 0, spill } or nil
M.cmd.msg_row = texth.end_row
local want_full = full or will_full or not api.nvim_win_get_config(ext.wins.pager).hide
if want_full and texth.all > ext.cmdheight then
msg_to_full(tar)
return
end
end end
end end
@@ -331,7 +338,7 @@ function M.show_msg(tar, content, replace_last, append, pager)
-- Reset message state the next event loop iteration. -- Reset message state the next event loop iteration.
if start_row == 0 or ext.cmd.row > 0 then if start_row == 0 or ext.cmd.row > 0 then
vim.schedule(function() vim.schedule(function()
col, M.cmd.lines, M.cmd.count = 0, 0, 0 col, M.cmd.count = 0, 0
end) end)
end end
end end
@@ -359,10 +366,6 @@ function M.msg_show(kind, content, replace_last, _, append)
M.virt.last[M.virt.idx.search] = content M.virt.last[M.virt.idx.search] = content
M.virt.last[M.virt.idx.cmd] = { { 0, (' '):rep(11) } } M.virt.last[M.virt.idx.cmd] = { { 0, (' '):rep(11) } }
set_virttext('last') set_virttext('last')
elseif kind == 'verbose' then
-- Verbose messages are sent too often to be meaningful in the cmdline.
-- always route to message window regardless of cfg.msg.target.
M.show_msg('msg', content, false, append)
elseif ext.cmd.prompt or kind == 'wildlist' then elseif ext.cmd.prompt or kind == 'wildlist' then
-- Route to dialog that stays open so long as the cmdline prompt is active. -- Route to dialog that stays open so long as the cmdline prompt is active.
replace_last = api.nvim_win_get_config(ext.wins.dialog).hide or kind == 'wildlist' replace_last = api.nvim_win_get_config(ext.wins.dialog).hide or kind == 'wildlist'
@@ -386,13 +389,13 @@ function M.msg_show(kind, content, replace_last, _, append)
M.virt.last[M.virt.idx.search][1] = nil M.virt.last[M.virt.idx.search][1] = nil
end end
-- Typed "inspection" messages should be routed to the pager. -- Typed "inspection" messages should be shown in full.
local inspect = { 'echo', 'echomsg', 'lua_print' } local inspect = { 'echo', 'echomsg', 'lua_print' }
local pager = kind == 'list_cmd' or (ext.cmd.level >= 0 and vim.tbl_contains(inspect, kind)) local full = kind == 'list_cmd' or (ext.cmd.level >= 0 and vim.tbl_contains(inspect, kind))
M.show_msg(tar, content, replace_last, append, pager) M.show_msg(tar, content, replace_last, append, full)
-- Don't remember search_cmd message as actual message. -- Don't remember search_cmd message as actual message.
if kind == 'search_cmd' then if kind == 'search_cmd' then
M.cmd.lines, M.cmd.count, M.prev_msg = 0, 0, '' M.cmd.count, M.prev_msg = 0, ''
end end
end end
end end
@@ -402,7 +405,7 @@ function M.msg_clear()
api.nvim_buf_set_lines(ext.bufs.cmd, 0, -1, false, {}) api.nvim_buf_set_lines(ext.bufs.cmd, 0, -1, false, {})
api.nvim_buf_set_lines(ext.bufs.msg, 0, -1, false, {}) api.nvim_buf_set_lines(ext.bufs.msg, 0, -1, false, {})
api.nvim_win_set_config(ext.wins.msg, { hide = true }) api.nvim_win_set_config(ext.wins.msg, { hide = true })
M.dupe, M[ext.cfg.msg.target].count, M.cmd.msg_row, M.cmd.lines, M.msg.width = 0, 0, -1, 1, 1 M.dupe, M[ext.cfg.msg.target].count, M.cmd.msg_row, M.msg.width = 0, 0, -1, 1
M.prev_msg, M.virt.msg = '', { {}, {} } M.prev_msg, M.virt.msg = '', { {}, {} }
end end
@@ -437,11 +440,15 @@ end
--- Open the message history in the pager. --- Open the message history in the pager.
--- ---
---@param entries MsgHistory[] ---@param entries MsgHistory[]
function M.msg_history_show(entries) ---@param prev_cmd boolean
function M.msg_history_show(entries, prev_cmd)
if #entries == 0 then if #entries == 0 then
return return
end end
if prev_cmd then
M.msg_clear() -- Showing output of previous command, clear in case still visible.
end
api.nvim_buf_set_lines(ext.bufs.pager, 0, -1, false, {}) api.nvim_buf_set_lines(ext.bufs.pager, 0, -1, false, {})
for i, entry in ipairs(entries) do for i, entry in ipairs(entries) do
M.show_msg('pager', entry[2], i == 1, entry[3]) M.show_msg('pager', entry[2], i == 1, entry[3])
@@ -450,77 +457,86 @@ function M.msg_history_show(entries)
M.set_pos('pager') M.set_pos('pager')
end end
local routed = false
--- Adjust dimensions of the message windows after certain events. --- Adjust dimensions of the message windows after certain events.
--- ---
---@param type? 'cmd'|'dialog'|'msg'|'pager' Type of to be positioned window (nil for all). ---@param type? 'cmd'|'dialog'|'msg'|'pager' Type of to be positioned window (nil for all).
function M.set_pos(type) function M.set_pos(type)
local function win_set_pos(win) local function win_set_pos(win)
local texth = type and api.nvim_win_text_height(win, {}) or 0 local texth = type and api.nvim_win_text_height(win, {}) or {}
local height = type and math.min(texth.all, math.ceil(o.lines * 0.5)) local height = type and math.min(texth.all, math.ceil(o.lines * 0.5))
local top = { vim.opt.fcs:get().horiz or o.ambw == 'single' and '' or '-', 'WinSeparator' } local top = { vim.opt.fcs:get().horiz or o.ambw == 'single' and '' or '-', 'WinSeparator' }
local border = (type == 'pager' or type == 'dialog') and { '', top, '', '', '', '', '', '' } local border = type ~= 'msg' and { '', top, '', '', '', '', '', '' } or nil
local save_config = type == 'cmd' and api.nvim_win_get_config(win) or {}
local config = { local config = {
hide = false, hide = false,
relative = 'laststatus', relative = 'laststatus',
border = border or nil, border = border,
height = height, height = height,
row = win == ext.wins.msg and 0 or 1, row = type == 'msg' and 0 or 1,
col = 10000, col = 10000,
focusable = type == 'cmd' or nil, -- Allow entering the cmdline window.
} }
api.nvim_win_set_config(win, config)
if type == 'msg' then if type == 'cmd' then
-- Temporarily showing a full message in the cmdline, until next key press.
local save_spill = M.virt.msg[M.virt.idx.spill][1]
local spill = texth.all > height and ('[+%d]'):format(texth.all - height)
M.virt.msg[M.virt.idx.spill][1] = spill and { 0, spill } or nil
set_virttext('msg')
M.virt.msg[M.virt.idx.spill][1] = save_spill
cmd_on_key = vim.on_key(function(_, typed)
if not typed or fn.keytrans(typed) == '<MouseMove>' then
return
end
vim.schedule(function()
api.nvim_win_set_config(win, save_config)
cmd_on_key = nil
local entered = api.nvim_get_current_win() == win
-- Show or clear the message depending on if the pager was opened.
if entered or not api.nvim_win_get_config(ext.wins.pager).hide then
M.virt.msg[M.virt.idx.spill][1] = nil
api.nvim_buf_set_lines(ext.bufs.cmd, 0, -1, false, {})
if entered then
api.nvim_command('norm! g<') -- User entered the cmdline window: open the pager.
end
elseif ext.cfg.msg.target == 'cmd' and ext.cmd.level <= 0 then
set_virttext('msg')
end
api.nvim__redraw({ flush = true }) -- NOTE: redundant unless cmdline was opened.
end)
vim.on_key(nil, ext.ns)
end, ext.ns)
elseif type == 'msg' then
-- Ensure last line is visible and first line is at top of window. -- 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 local row = (texth.all > height and texth.end_row or 0) + 1
api.nvim_win_set_cursor(ext.wins.msg, { row, 0 }) api.nvim_win_set_cursor(ext.wins.msg, { row, 0 })
elseif type == 'pager' then elseif type == 'pager' then
if fn.getcmdwintype() ~= '' then if fn.getcmdwintype() ~= '' then
if will_pager then -- Cannot leave the cmdwin to enter the pager, so close it.
config.relative, config.win, config.row, config.col = 'win', 0, 0, 0 -- NOTE: regression w.r.t. the message grid, which allowed this.
else -- Resolving that would require somehow bypassing textlock for the pager.
-- Cannot leave the cmdwin to enter the pager, so close it. api.nvim_command('quit')
-- 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 end
routed = will_pager -- Cmdwin is actually closed one event iteration later so schedule in case it was open.
-- It's actually closed one event iteration later so schedule in case it was open.
vim.schedule(function() 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_set_current_win(win)
-- Make pager relative to cmdwin when it is opened, restore when it is closed.
api.nvim_create_autocmd({ 'WinEnter', 'CmdwinEnter', 'CmdwinLeave' }, { api.nvim_create_autocmd({ 'WinEnter', 'CmdwinEnter', 'CmdwinLeave' }, {
callback = function(ev) callback = function(ev)
-- Make pager relative to cmdwin when it is opened, restore when it is closed.
config = ev.event == 'CmdwinLeave' and config
or ev.event == 'WinEnter' and { hide = true }
or { relative = 'win', win = 0, row = 0, col = 0 }
if api.nvim_win_is_valid(win) then if api.nvim_win_is_valid(win) then
api.nvim_win_set_config(win, config) local cfg = ev.event == 'CmdwinLeave' and config
or ev.event == 'WinEnter' and { hide = true }
or { relative = 'win', win = 0, row = 0, col = 0 }
api.nvim_win_set_config(win, cfg)
end end
return ev.event == 'WinEnter' return ev.event == 'WinEnter'
end, end,
desc = 'Hide inactive pager window.', desc = 'Hide or reposition pager window.',
}) })
end) end)
end end
api.nvim_win_set_config(win, config)
end end
for t, win in pairs(ext.wins) do for t, win in pairs(ext.wins) do

View File

@@ -33,7 +33,7 @@ describe('messages2', function()
─────────────────────────────────────────────────────| ─────────────────────────────────────────────────────|
{4:fo^o }| {4:fo^o }|
{4:bar }| {4:bar }|
foo[+1] 1,3 All| 1,3 All|
]]) ]])
-- New message clears spill indicator. -- New message clears spill indicator.
feed('Q') feed('Q')
@@ -45,38 +45,40 @@ describe('messages2', function()
{4:bar }| {4:bar }|
{9:E354: Invalid register name: '^@'} 1,3 All| {9:E354: Invalid register name: '^@'} 1,3 All|
]]) ]])
-- Multiple messages in same event loop iteration are appended. -- Multiple messages in same event loop iteration are appended and shown in full.
feed([[q:echo "foo\nbar" | echo "baz"<CR>]]) feed([[q:echo "foo" | echo "bar\nbaz\n"->repeat(&lines)<CR>]])
screen:expect([[ screen:expect([[
^ | ^ |
{1:~ }|*8 {1:~ }|*5
─────────────────────────────────────────────────────| ─────────────────────────────────────────────────────|
{4:foo }| foo |
{4:bar }| bar |
{4:baz }| baz |
0,0-1 All| bar |
baz |
bar |
baz[+23] |
]]) ]])
-- Any key press closes the routed pager. -- Any key press resizes the cmdline and updates the spill indicator.
feed('j') feed('j')
screen:expect([[ screen:expect([[
^ | ^ |
{1:~ }|*12 {1:~ }|*12
0,0-1 All| foo[+29] 0,0-1 All|
]]) ]])
-- No error for ruler virt_text msg_row exceeding buffer length. -- No error for ruler virt_text msg_row exceeding buffer length.
command([[map Q <cmd>echo "foo\nbar" <bar> ls<CR>]]) command([[map Q <cmd>echo "foo\nbar" <bar> ls<CR>]])
feed('Q') feed('Q')
screen:expect([[ screen:expect([[
^ | ^ |
{1:~ }|*7 {1:~ }|*8
─────────────────────────────────────────────────────| ─────────────────────────────────────────────────────|
{4:foo }| foo |
{4:bar }| bar |
{4: }| |
{4: 1 %a "[No Name]" line 1 }| 1 %a "[No Name]" line 1 |
0,0-1 All|
]]) ]])
feed('<Esc>') feed('<C-L>')
screen:expect([[ screen:expect([[
^ | ^ |
{1:~ }|*12 {1:~ }|*12