fix(extui): use visible to determine active "more" (#34327)

Problem:  Current window is checked to determine whether "more" window
          is open. Making it the current window is scheduled in case the
          cmdwin is open so this can be too late.
          "cmdline_hide" may be emitted when the topline is
          temporarily invalid (after incsearch->restore_viewstate()).
Solution: Use the window visibility to determine an active "more"
          window instead.
          Don't nvim__redraw->flush the "cmdline_hide" event (a normal
          will already happen).
This commit is contained in:
luukvbaal
2025-06-06 16:04:45 +02:00
committed by GitHub
parent e5c5b563ec
commit cb036cae5f
3 changed files with 21 additions and 14 deletions

View File

@@ -49,7 +49,7 @@ local function ui_callback(event, ...)
ext.tab_check_wins() ext.tab_check_wins()
handler(...) handler(...)
api.nvim__redraw({ api.nvim__redraw({
flush = true, flush = handler ~= ext.cmd.cmdline_hide or nil,
cursor = handler == ext.cmd[event] and true or nil, cursor = handler == ext.cmd[event] and true or nil,
win = handler == ext.cmd[event] and ext.wins.cmd or nil, win = handler == ext.cmd[event] and ext.wins.cmd or nil,
}) })

View File

@@ -99,6 +99,7 @@ function M.cmdline_pos(pos)
curpos[1], curpos[2] = M.row + 1, promptlen + pos curpos[1], curpos[2] = M.row + 1, promptlen + pos
-- Add matchparen highlighting to non-prompt part of cmdline. -- Add matchparen highlighting to non-prompt part of cmdline.
if pos > 0 and fn.exists('#matchparen') then if pos > 0 and fn.exists('#matchparen') then
api.nvim_win_set_cursor(ext.wins.cmd, { curpos[1], curpos[2] - 1 })
vim._with({ win = ext.wins.cmd, wo = { eventignorewin = '' } }, function() vim._with({ win = ext.wins.cmd, wo = { eventignorewin = '' } }, function()
api.nvim_exec_autocmds('CursorMoved', {}) api.nvim_exec_autocmds('CursorMoved', {})
end) end)

View File

@@ -36,6 +36,15 @@ local M = {
}, },
} }
function M.box:close()
self.width, M.virt.msg = 1, { {}, {} }
M.prev_msg = ext.cfg.msg.pos == 'box' and '' or M.prev_msg
api.nvim_buf_clear_namespace(ext.bufs.box, -1, 0, -1)
if api.nvim_win_is_valid(ext.wins.box) then
api.nvim_win_set_config(ext.wins.box, { hide = true })
end
end
--- Start a timer whose callback will remove the message from the message window. --- Start a timer whose callback will remove the message from the message window.
--- ---
---@param buf integer Buffer the message was written to. ---@param buf integer Buffer the message was written to.
@@ -51,12 +60,7 @@ function M.box:start_timer(buf, len)
if self.count > 0 then if self.count > 0 then
M.set_pos('box') M.set_pos('box')
else else
self.width = 1 self:close()
M.prev_msg = ext.cfg.msg.pos == 'box' and '' or M.prev_msg
api.nvim_buf_clear_namespace(ext.bufs.box, -1, 0, -1)
if api.nvim_win_is_valid(ext.wins.box) then
api.nvim_win_set_config(ext.wins.box, { hide = true })
end
end end
end, ext.cfg.msg.box.timeout) end, ext.cfg.msg.box.timeout)
end end
@@ -257,7 +261,7 @@ function M.show_msg(tar, content, replace_last, append, more)
local h = api.nvim_win_text_height(ext.wins.box, { start_row = start_row }) local h = api.nvim_win_text_height(ext.wins.box, { start_row = start_row })
if more and h.all > 1 then if more and h.all > 1 then
msg_to_more(tar) msg_to_more(tar)
api.nvim_win_set_width(ext.wins.box, M.box.width) M.box:close()
return return
end end
@@ -337,7 +341,7 @@ function M.msg_show(kind, content, _, _, append)
-- Verbose messages are sent too often to be meaningful in the cmdline: -- Verbose messages are sent too often to be meaningful in the cmdline:
-- always route to box regardless of cfg.msg.pos. -- always route to box regardless of cfg.msg.pos.
M.show_msg('box', content, false, append) M.show_msg('box', content, false, append)
elseif ext.cfg.msg.pos == 'cmd' and api.nvim_get_current_win() == ext.wins.more then elseif ext.cfg.msg.pos == 'cmd' and not api.nvim_win_get_config(ext.wins.more).hide then
-- Append message to already open 'more' window. -- Append message to already open 'more' window.
M.msg_history_show({ { 'spill', content } }) M.msg_history_show({ { 'spill', content } })
api.nvim_command('norm! G') api.nvim_command('norm! G')
@@ -411,13 +415,13 @@ function M.msg_history_show(entries)
end end
-- Appending messages while 'more' window is open. -- Appending messages while 'more' window is open.
local append_more = api.nvim_get_current_win() == ext.wins.more local clear = entries[1][1] ~= 'spill' or api.nvim_win_get_config(ext.wins.more).hide == true
if not append_more then if clear then
api.nvim_buf_set_lines(ext.bufs.more, 0, -1, false, {}) api.nvim_buf_set_lines(ext.bufs.more, 0, -1, false, {})
end end
for i, entry in ipairs(entries) do for i, entry in ipairs(entries) do
M.show_msg('more', entry[2], i == 1 and not append_more, false) M.show_msg('more', entry[2], i == 1 and clear, false)
end end
M.set_pos('more') M.set_pos('more')
@@ -439,18 +443,19 @@ function M.set_pos(type)
row = win == ext.wins.box and 0 or 1, row = win == ext.wins.box and 0 or 1,
col = 10000, col = 10000,
} }
api.nvim_win_set_config(win, config)
if type == 'box' then if type == 'box' 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.box, { row, 0 }) api.nvim_win_set_cursor(ext.wins.box, { row, 0 })
elseif type == 'more' and api.nvim_get_current_win() ~= win then elseif type == 'more' and api.nvim_win_get_config(win).hide then
-- Cannot leave the cmdwin to enter the "more" window, so close it. -- Cannot leave the cmdwin to enter the "more" window, so close it.
-- NOTE: regression w.r.t. the message grid, which allowed this. Resolving -- NOTE: regression w.r.t. the message grid, which allowed this. Resolving
-- that would require somehow bypassing textlock for the "more" window. -- that would require somehow bypassing textlock for the "more" window.
if fn.getcmdwintype() ~= '' then if fn.getcmdwintype() ~= '' then
api.nvim_command('quit') api.nvim_command('quit')
end end
-- It's 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()
api.nvim_set_current_win(win) api.nvim_set_current_win(win)
@@ -471,6 +476,7 @@ function M.set_pos(type)
}) })
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