fix(ui2): immediately open target windows on new tabpage (#38170)

Problem:  Previous tests for this relied on other events opening the
          targets, which are not guaranteed to happen.
Solution: Open target windows when entering a new tabpage.
This commit is contained in:
luukvbaal
2026-03-06 17:32:17 +01:00
committed by GitHub
parent d19dc6339d
commit 6275f533d1
3 changed files with 38 additions and 42 deletions

View File

@@ -51,46 +51,35 @@ local M = {
},
},
}
--- @type vim.api.keyset.win_config
local wincfg = { -- Default cfg for nvim_open_win().
relative = 'laststatus',
style = 'minimal',
col = 0,
row = 1,
width = 10000,
height = 1,
noautocmd = true,
focusable = false,
}
local tab = 0
---Ensure target buffers and windows are still valid.
function M.check_targets()
local curtab = api.nvim_get_current_tabpage()
for i, type in ipairs({ 'cmd', 'dialog', 'msg', 'pager' }) do
local setopt = not api.nvim_buf_is_valid(M.bufs[type])
if setopt then
M.bufs[type] = api.nvim_create_buf(false, false)
end
local oldbuf = api.nvim_buf_is_valid(M.bufs[type]) and M.bufs[type]
local oldwin, setopt = api.nvim_win_is_valid(M.wins[type]) and M.wins[type], not oldbuf
M.bufs[type] = oldbuf or api.nvim_create_buf(false, false)
if
tab ~= curtab
or not api.nvim_win_is_valid(M.wins[type])
or not api.nvim_win_get_config(M.wins[type]).zindex -- no longer floating
then
local cfg = vim.tbl_deep_extend('force', wincfg, {
mouse = type ~= 'cmd' and true or nil,
anchor = type ~= 'cmd' and 'SE' or nil,
hide = type ~= 'cmd' or M.cmdheight == 0 or nil,
border = type ~= 'msg' and 'none' or nil,
-- kZIndexMessages < cmd zindex < kZIndexCmdlinePopupMenu (grid_defs.h), pager below others.
zindex = 201 - i,
_cmdline_offset = type == 'cmd' and 0 or nil,
})
if tab ~= curtab and api.nvim_win_is_valid(M.wins[type]) then
cfg = api.nvim_win_get_config(M.wins[type])
api.nvim_win_close(M.wins[type], true)
end
if tab ~= curtab and oldwin then
-- Ensure dynamically set window configuration (M.msg.set_pos()) is copied
-- over when switching tabpage. TODO: move to tabpage instead after #35816.
M.wins[type] = api.nvim_open_win(M.bufs[type], false, api.nvim_win_get_config(oldwin))
api.nvim_win_close(oldwin, true)
setopt = true
elseif not oldwin or not api.nvim_win_get_config(M.wins[type]).zindex then
-- Open a new window when closed or no longer floating (e.g. wincmd J).
local cfg = { col = 0, row = 1, width = 10000, height = 1, mouse = false, noautocmd = true }
cfg.focusable = false
cfg.style = 'minimal'
cfg.relative = 'laststatus'
cfg.anchor = type ~= 'cmd' and 'SE' or nil
cfg.mouse = type == 'pager' or nil
cfg.border = type ~= 'msg' and 'none' or nil
cfg._cmdline_offset = type == 'cmd' and 0 or nil
cfg.hide = type ~= 'cmd' or M.cmdheight == 0 or nil
-- kZIndexMessages < cmd zindex < kZIndexCmdlinePopupMenu (grid_defs.h), pager below others.
cfg.zindex = 201 - i
M.wins[type] = api.nvim_open_win(M.bufs[type], false, cfg)
setopt = true
elseif api.nvim_win_get_buf(M.wins[type]) ~= M.bufs[type] then
@@ -170,14 +159,10 @@ function M.enable(opts)
if M.cfg.enable == false then
-- Detach and cleanup windows, buffers and autocommands.
for _, win in pairs(M.wins) do
if api.nvim_win_is_valid(win) then
api.nvim_win_close(win, true)
end
pcall(api.nvim_win_close, win, true)
end
for _, buf in pairs(M.bufs) do
if api.nvim_buf_is_valid(buf) then
api.nvim_buf_delete(buf, {})
end
pcall(api.nvim_buf_delete, buf, {})
end
api.nvim_clear_autocmds({ group = M.augroup })
vim.ui_detach(M.ns)
@@ -232,6 +217,7 @@ function M.enable(opts)
api.nvim_create_autocmd({ 'VimResized', 'TabEnter' }, {
group = M.augroup,
callback = function()
M.check_targets()
M.msg.set_pos()
end,
desc = 'Set cmdline and message window dimensions after shell resize or tabpage change.',

View File

@@ -504,7 +504,7 @@ function M.set_pos(tgt)
local lines = o.lines - (win == ui.wins.pager and ui.cmdheight + (o.ls == 3 and 2 or 0) or 0)
cfg.height = math.min(texth.all, math.ceil(lines * (win == ui.wins.pager and 1 or 0.5)))
cfg.border = win ~= ui.wins.msg and { '', top, '', '', '', '', '', '' } or nil
cfg.focusable = tgt == 'cmd' or nil
cfg.mouse = tgt == 'cmd' or nil
cfg.row = (win == ui.wins.msg and 0 or 1) - ui.cmd.wmnumode
cfg.row = cfg.row - ((win == ui.wins.pager and o.laststatus == 3) and 1 or 0)
local title = { 'f/d/j: screen/page/line down, b/u/k: up, <Esc>: stop paging', 'MsgSeparator' }
@@ -561,6 +561,7 @@ function M.set_pos(tgt)
api.nvim_win_set_config(ui.wins.dialog, { title = '' })
api.nvim__redraw({ flush = true })
vim.on_key(nil, M.dialog_on_key)
M.dialog_on_key = nil
return ''
end

View File

@@ -129,7 +129,7 @@ describe('messages2', function()
-- Switching tabpage closes expanded cmdline #37659.
command('tabnew | echo "foo\nbar"')
screen:expect([[
{24: + [No Name] }{5: }{100:2}{5: [No Name] }{2: }{24:X}|
{24: + [No Name] }{5: [No Name] }{2: }{24:X}|
^ |
{1:~ }|*9
{3: }|
@@ -170,7 +170,7 @@ describe('messages2', function()
]])
end)
it('new buffer, window and options after closing a buffer', function()
it('new buffer, window and options after closing a buffer or switching tabpage', function()
command('set nomodifiable | echom "foo" | messages')
screen:expect([[
|
@@ -181,6 +181,15 @@ describe('messages2', function()
]])
command('bdelete | messages')
screen:expect_unchanged()
set_msg_target_zero_ch()
command('quit | echo "foo\nbar" | tabnew')
screen:expect([[
{24: [No Name] }{5: [No Name] }{2: }{24:X}|
^ |
{1:~ }|*10
{1:~ }{4:foo}|
{1:~ }{4:bar}|
]])
end)
it('screenclear and empty message clears messages', function()