mirror of
https://github.com/neovim/neovim.git
synced 2026-07-31 04:39:07 +00:00
fix(lsp): preview window converted to normal window is auto-closed (#40770)
Problem: A floating preview window (hover, signature help) converted to a normal window (e.g. with CTRL-W_H or nvim_win_set_config()) is still closed by the open_floating_preview() autocommands, and a later preview may focus or close it as if it were still a float. Solution: When the preview window is no longer floating, remove its auto-close autocommands and stop tracking it as the buffer's floating preview. Closes #36659
This commit is contained in:
@@ -417,6 +417,9 @@ These existing features changed their behavior.
|
||||
• Markdown inline highlighting now conceals the backslash in backslash escapes.
|
||||
• Markdown inline backslash escapes and hard line breaks no longer use the
|
||||
`@string.escape` capture.
|
||||
• |vim.lsp.util.open_floating_preview()| windows (e.g. |vim.lsp.buf.hover()|)
|
||||
converted to normal windows (e.g. with |CTRL-W_H|) are no longer closed
|
||||
automatically.
|
||||
|
||||
==============================================================================
|
||||
REMOVED FEATURES *news-removed*
|
||||
|
||||
@@ -950,6 +950,12 @@ local function find_window_by_var(name, value)
|
||||
end
|
||||
end
|
||||
|
||||
---@param winnr integer
|
||||
---@return boolean `true` if `winnr` is a valid floating window
|
||||
local function is_float(winnr)
|
||||
return api.nvim_win_is_valid(winnr) and vim.fn.win_gettype(winnr) == 'popup'
|
||||
end
|
||||
|
||||
---Returns true if the line is empty or only contains whitespace.
|
||||
---@param line string
|
||||
---@return boolean
|
||||
@@ -1305,6 +1311,21 @@ local function close_preview_window(winnr, bufnrs)
|
||||
|
||||
local augroup = 'nvim.preview_window_' .. winnr
|
||||
pcall(api.nvim_del_augroup_by_name, augroup)
|
||||
|
||||
-- Preview window was converted to a normal window (e.g. |CTRL-W_H|):
|
||||
-- keep it open and stop managing it.
|
||||
if api.nvim_win_is_valid(winnr) and not is_float(winnr) then
|
||||
local srcbuf = vim.w[winnr].lsp_floating_bufnr
|
||||
if
|
||||
srcbuf
|
||||
and api.nvim_buf_is_valid(srcbuf)
|
||||
and vim.b[srcbuf].lsp_floating_preview == winnr
|
||||
then
|
||||
vim.b[srcbuf].lsp_floating_preview = nil
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
pcall(api.nvim_win_close, winnr, true)
|
||||
end)
|
||||
end
|
||||
@@ -1508,13 +1529,13 @@ function M.open_floating_preview(contents, syntax, opts)
|
||||
if opts.focus_id and opts.focusable ~= false and opts.focus then
|
||||
-- Go back to previous window if we are in a focusable one
|
||||
local current_winnr = api.nvim_get_current_win()
|
||||
if vim.w[current_winnr][opts.focus_id] then
|
||||
if vim.w[current_winnr][opts.focus_id] and is_float(current_winnr) then
|
||||
api.nvim_command('wincmd p')
|
||||
return bufnr, current_winnr
|
||||
end
|
||||
do
|
||||
local win = find_window_by_var(opts.focus_id, bufnr)
|
||||
if win and api.nvim_win_is_valid(win) and vim.fn.pumvisible() == 0 then
|
||||
if win and is_float(win) and vim.fn.pumvisible() == 0 then
|
||||
-- focus and return the existing buf, win
|
||||
api.nvim_set_current_win(win)
|
||||
api.nvim_command('stopinsert')
|
||||
@@ -1526,7 +1547,7 @@ function M.open_floating_preview(contents, syntax, opts)
|
||||
-- check if another floating preview already exists for this buffer
|
||||
-- and close it if needed
|
||||
local existing_float = vim.b[bufnr].lsp_floating_preview
|
||||
if existing_float and api.nvim_win_is_valid(existing_float) then
|
||||
if existing_float and is_float(existing_float) then
|
||||
api.nvim_win_close(existing_float, true)
|
||||
end
|
||||
floating_bufnr = api.nvim_create_buf(false, true)
|
||||
|
||||
@@ -1385,6 +1385,35 @@ describe('vim.lsp.util', function()
|
||||
-- b:lsp_floating_preview should be cleared.
|
||||
eq('Key not found: lsp_floating_preview', pcall_err(api.nvim_buf_get_var, 0, var_name))
|
||||
end)
|
||||
|
||||
it('converted to a normal window is unmanaged, not closed #36659', function()
|
||||
local converted = exec_lua(function()
|
||||
local opts = { focus_id = 'focus_test' }
|
||||
local cur_winnr = vim.api.nvim_get_current_win()
|
||||
vim.lsp.util.open_floating_preview({ 'test' }, '', opts)
|
||||
local converted = vim.b.lsp_floating_preview
|
||||
vim.api.nvim_win_set_config(converted, { win = cur_winnr, split = 'right' })
|
||||
-- close events unmanage the converted window instead of closing it
|
||||
vim.api.nvim_exec_autocmds('CursorMoved', { buffer = 0 })
|
||||
assert(
|
||||
vim.wait(1000, function()
|
||||
return vim.b.lsp_floating_preview == nil
|
||||
end),
|
||||
'preview should be untracked after close event'
|
||||
)
|
||||
-- reusing the focus_id opens a new float instead of refocusing the converted window
|
||||
local _, new_win = vim.lsp.util.open_floating_preview({ 'test' }, '', opts)
|
||||
assert(new_win ~= converted, 'expected a new float')
|
||||
-- also when triggered from inside the converted window
|
||||
vim.api.nvim_set_current_win(converted)
|
||||
local _, newer_win = vim.lsp.util.open_floating_preview({ 'test' }, '', opts)
|
||||
assert(newer_win ~= converted, 'expected a new float')
|
||||
assert(vim.api.nvim_get_current_win() == converted, 'focus changed')
|
||||
return converted
|
||||
end)
|
||||
eq(true, api.nvim_win_is_valid(converted))
|
||||
eq('', api.nvim_win_get_config(converted).relative)
|
||||
end)
|
||||
end)
|
||||
|
||||
it('open_floating_preview zindex greater than current window', function()
|
||||
|
||||
Reference in New Issue
Block a user