From 88a72efb465c35df49a2e9c576272f08f6dd93d6 Mon Sep 17 00:00:00 2001 From: glepnir Date: Mon, 16 Mar 2026 21:50:13 +0800 Subject: [PATCH] fix(diagnostic): open_float() handles config.float function #31577 Problem: The `float` field of vim.diagnostic.config can be a function, but diagnostic.open_float() does not handle it correctly. Solution: Add handling for it in open_float(). --- runtime/doc/diagnostic.txt | 2 +- runtime/lua/vim/diagnostic.lua | 13 +++--- test/functional/lua/diagnostic_spec.lua | 56 +++++++++++++++---------- 3 files changed, 43 insertions(+), 28 deletions(-) diff --git a/runtime/doc/diagnostic.txt b/runtime/doc/diagnostic.txt index 0792c36d71..d398563ec0 100644 --- a/runtime/doc/diagnostic.txt +++ b/runtime/doc/diagnostic.txt @@ -545,7 +545,7 @@ Lua module: vim.diagnostic *diagnostic-api* Use virtual lines for diagnostics. • {signs}? (`boolean|vim.diagnostic.Opts.Signs|fun(namespace: integer, bufnr:integer): vim.diagnostic.Opts.Signs`, default: `true`) Use signs for diagnostics |diagnostic-signs|. - • {float}? (`boolean|vim.diagnostic.Opts.Float|fun(namespace: integer, bufnr:integer): vim.diagnostic.Opts.Float`) + • {float}? (`boolean|vim.diagnostic.Opts.Float|fun(namespace?: integer|integer[], bufnr:integer): vim.diagnostic.Opts.Float`) Options for floating windows. See |vim.diagnostic.Opts.Float|. • {status}? (`vim.diagnostic.Opts.Status`) Options for the diff --git a/runtime/lua/vim/diagnostic.lua b/runtime/lua/vim/diagnostic.lua index 5b9dfaec7e..84fd65785b 100644 --- a/runtime/lua/vim/diagnostic.lua +++ b/runtime/lua/vim/diagnostic.lua @@ -92,7 +92,7 @@ end --- @field signs? boolean|vim.diagnostic.Opts.Signs|fun(namespace: integer, bufnr:integer): vim.diagnostic.Opts.Signs --- --- Options for floating windows. See |vim.diagnostic.Opts.Float|. ---- @field float? boolean|vim.diagnostic.Opts.Float|fun(namespace: integer, bufnr:integer): vim.diagnostic.Opts.Float +--- @field float? boolean|vim.diagnostic.Opts.Float|fun(namespace?: integer|integer[], bufnr:integer): vim.diagnostic.Opts.Float --- --- Options for the statusline component. --- @field status? vim.diagnostic.Opts.Status @@ -2439,10 +2439,13 @@ function M.open_float(opts, ...) -- Resolve options with user settings from vim.diagnostic.config -- Unlike the other decoration functions (e.g. set_virtual_text, set_signs, etc.) `open_float` -- does not have a dedicated table for configuration options; instead, the options are mixed in - -- with its `opts` table which also includes "keyword" parameters. So we create a dedicated - -- options table that inherits missing keys from the global configuration before resolving. - local t = global_diagnostic_options.float - local float_opts = vim.tbl_extend('keep', opts, type(t) == 'table' and t or {}) + -- with its `opts` table. We create a dedicated options table (`float_opts`) that inherits + -- missing keys from the global configuration (`global_diagnostic_options.float`), which can + -- be a table or a function. + local o = global_diagnostic_options + local t = type(o.float) == 'table' and o.float + or (type(o.float) == 'function' and o.float(opts.namespace, bufnr) or {}) + local float_opts = vim.tbl_extend('keep', opts, t) opts = get_resolved_options({ float = float_opts }, nil, bufnr).float end diff --git a/test/functional/lua/diagnostic_spec.lua b/test/functional/lua/diagnostic_spec.lua index 7a93ffd705..ee0292d6a2 100644 --- a/test/functional/lua/diagnostic_spec.lua +++ b/test/functional/lua/diagnostic_spec.lua @@ -3215,28 +3215,40 @@ describe('vim.diagnostic', function() ) end) - it( - 'creates floating window and returns float bufnr and winnr without header, if requested', - function() - -- One line (since no header): - -- 1. - eq( - 1, - exec_lua(function() - local diagnostics = { - _G.make_error('Syntax error', 0, 1, 0, 3), - } - vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) - vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) - local float_bufnr, winnr = - vim.diagnostic.open_float(_G.diagnostic_bufnr, { header = false }) - local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) - vim.api.nvim_win_close(winnr, true) - return #lines - end) - ) - end - ) + it('creates floating window without header and supports function-based float config', function() + -- One line (since no header): + -- 1. + eq( + { 1, '╭', '┌' }, + exec_lua(function() + local diagnostics = { + _G.make_error('Syntax error', 0, 1, 0, 3), + } + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) + local float_bufnr, winnr = + vim.diagnostic.open_float(_G.diagnostic_bufnr, { header = false }) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + vim.diagnostic.config({ + float = function(_, bufnr) + return { border = bufnr == _G.diagnostic_bufnr and 'rounded' or 'single' } + end, + }) + _, winnr = vim.diagnostic.open_float() + local border1 = vim.api.nvim_win_get_config(winnr).border + vim.api.nvim_win_close(winnr, true) + + local other_bufnr = vim.api.nvim_create_buf(true, true) + vim.api.nvim_win_set_buf(0, other_bufnr) + vim.diagnostic.set(_G.diagnostic_ns, other_bufnr, diagnostics) + local _, winnr1 = vim.diagnostic.open_float() + local border2 = vim.api.nvim_win_get_config(winnr1).border + vim.api.nvim_win_close(winnr1, true) + return { #lines, border1[1], border2[1] } + end) + ) + end) it('clamps diagnostic line numbers within the valid range', function() eq(