mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
feat(diagnostic): add option to include diagnostic source
Add an option to virtual text display and floating window previews to include diagnostic source in the diagnostic message.
This commit is contained in:
parent
17b7968f02
commit
d43151ea0b
@ -47,6 +47,7 @@ A diagnostic is a Lua table with the following keys:
|
|||||||
end_col: The final column of the diagnostic
|
end_col: The final column of the diagnostic
|
||||||
severity: The severity of the diagnostic |vim.diagnostic.severity|
|
severity: The severity of the diagnostic |vim.diagnostic.severity|
|
||||||
message: The diagnostic text
|
message: The diagnostic text
|
||||||
|
source: The source of the diagnostic
|
||||||
|
|
||||||
Diagnostics use the same indexing as the rest of the Nvim API (i.e. 0-based
|
Diagnostics use the same indexing as the rest of the Nvim API (i.e. 0-based
|
||||||
rows and columns). |api-indexing|
|
rows and columns). |api-indexing|
|
||||||
@ -226,6 +227,9 @@ config({opts}, {namespace}) *vim.diagnostic.config()*
|
|||||||
• severity: Only show virtual text for
|
• severity: Only show virtual text for
|
||||||
diagnostics matching the given severity
|
diagnostics matching the given severity
|
||||||
|diagnostic-severity|
|
|diagnostic-severity|
|
||||||
|
• source: (string) Include the diagnostic
|
||||||
|
source in virtual text. One of "always"
|
||||||
|
or "if_many".
|
||||||
|
|
||||||
• signs: (default true) Use signs for
|
• signs: (default true) Use signs for
|
||||||
diagnostics. Options:
|
diagnostics. Options:
|
||||||
@ -532,6 +536,9 @@ show_position_diagnostics({opts}, {bufnr}, {position})
|
|||||||
• severity: See |diagnostic-severity|.
|
• severity: See |diagnostic-severity|.
|
||||||
• show_header: (boolean, default true) Show
|
• show_header: (boolean, default true) Show
|
||||||
"Diagnostics:" header
|
"Diagnostics:" header
|
||||||
|
• source: (string) Include the diagnostic
|
||||||
|
source in the message. One of "always" or
|
||||||
|
"if_many".
|
||||||
{bufnr} number|nil Buffer number. Defaults to the
|
{bufnr} number|nil Buffer number. Defaults to the
|
||||||
current buffer.
|
current buffer.
|
||||||
{position} table|nil The (0,0)-indexed position. Defaults
|
{position} table|nil The (0,0)-indexed position. Defaults
|
||||||
|
@ -47,6 +47,35 @@ local function filter_by_severity(severity, diagnostics)
|
|||||||
return vim.tbl_filter(function(t) return t.severity <= min_severity and t.severity >= max_severity end, diagnostics)
|
return vim.tbl_filter(function(t) return t.severity <= min_severity and t.severity >= max_severity end, diagnostics)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@private
|
||||||
|
local function prefix_source(source, diagnostics)
|
||||||
|
vim.validate { source = {source, function(v)
|
||||||
|
return v == "always" or v == "if_many"
|
||||||
|
end, "Invalid value for option 'source'" } }
|
||||||
|
|
||||||
|
if source == "if_many" then
|
||||||
|
local sources = {}
|
||||||
|
for _, d in pairs(diagnostics) do
|
||||||
|
if d.source then
|
||||||
|
sources[d.source] = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if #vim.tbl_keys(sources) <= 1 then
|
||||||
|
return diagnostics
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return vim.tbl_map(function(d)
|
||||||
|
if not d.source then
|
||||||
|
return d
|
||||||
|
end
|
||||||
|
|
||||||
|
local t = vim.deepcopy(d)
|
||||||
|
t.message = string.format("%s: %s", d.source, d.message)
|
||||||
|
return t
|
||||||
|
end, diagnostics)
|
||||||
|
end
|
||||||
|
|
||||||
---@private
|
---@private
|
||||||
local function resolve_optional_value(option, namespace, bufnr)
|
local function resolve_optional_value(option, namespace, bufnr)
|
||||||
local enabled_val = {}
|
local enabled_val = {}
|
||||||
@ -336,7 +365,9 @@ end
|
|||||||
---@param diagnostics table: The diagnostics to display
|
---@param diagnostics table: The diagnostics to display
|
||||||
---@return table {popup_bufnr, win_id}
|
---@return table {popup_bufnr, win_id}
|
||||||
local function show_diagnostics(opts, diagnostics)
|
local function show_diagnostics(opts, diagnostics)
|
||||||
if vim.tbl_isempty(diagnostics) then return end
|
if vim.tbl_isempty(diagnostics) then
|
||||||
|
return
|
||||||
|
end
|
||||||
local lines = {}
|
local lines = {}
|
||||||
local highlights = {}
|
local highlights = {}
|
||||||
local show_header = vim.F.if_nil(opts.show_header, true)
|
local show_header = vim.F.if_nil(opts.show_header, true)
|
||||||
@ -345,6 +376,10 @@ local function show_diagnostics(opts, diagnostics)
|
|||||||
table.insert(highlights, {0, "Bold"})
|
table.insert(highlights, {0, "Bold"})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if opts.source then
|
||||||
|
diagnostics = prefix_source(opts.source, diagnostics)
|
||||||
|
end
|
||||||
|
|
||||||
for i, diagnostic in ipairs(diagnostics) do
|
for i, diagnostic in ipairs(diagnostics) do
|
||||||
local prefix = string.format("%d. ", i)
|
local prefix = string.format("%d. ", i)
|
||||||
local hiname = floating_highlight_map[diagnostic.severity]
|
local hiname = floating_highlight_map[diagnostic.severity]
|
||||||
@ -487,6 +522,8 @@ end
|
|||||||
--- - virtual_text: (default true) Use virtual text for diagnostics. Options:
|
--- - virtual_text: (default true) Use virtual text for diagnostics. Options:
|
||||||
--- * severity: Only show virtual text for diagnostics matching the given
|
--- * severity: Only show virtual text for diagnostics matching the given
|
||||||
--- severity |diagnostic-severity|
|
--- severity |diagnostic-severity|
|
||||||
|
--- * source: (string) Include the diagnostic source in virtual
|
||||||
|
--- text. One of "always" or "if_many".
|
||||||
--- - signs: (default true) Use signs for diagnostics. Options:
|
--- - signs: (default true) Use signs for diagnostics. Options:
|
||||||
--- * severity: Only show signs for diagnostics matching the given severity
|
--- * severity: Only show signs for diagnostics matching the given severity
|
||||||
--- |diagnostic-severity|
|
--- |diagnostic-severity|
|
||||||
@ -826,6 +863,10 @@ function M._set_virtual_text(namespace, bufnr, diagnostics, opts)
|
|||||||
bufnr = get_bufnr(bufnr)
|
bufnr = get_bufnr(bufnr)
|
||||||
opts = get_resolved_options({ virtual_text = opts }, namespace, bufnr).virtual_text
|
opts = get_resolved_options({ virtual_text = opts }, namespace, bufnr).virtual_text
|
||||||
|
|
||||||
|
if opts and opts.source then
|
||||||
|
diagnostics = prefix_source(opts.source, diagnostics)
|
||||||
|
end
|
||||||
|
|
||||||
local buffer_line_diagnostics = diagnostic_lines(diagnostics)
|
local buffer_line_diagnostics = diagnostic_lines(diagnostics)
|
||||||
for line, line_diagnostics in pairs(buffer_line_diagnostics) do
|
for line, line_diagnostics in pairs(buffer_line_diagnostics) do
|
||||||
if opts and opts.severity then
|
if opts and opts.severity then
|
||||||
@ -1007,6 +1048,8 @@ end
|
|||||||
--- - namespace: (number) Limit diagnostics to the given namespace
|
--- - namespace: (number) Limit diagnostics to the given namespace
|
||||||
--- - severity: See |diagnostic-severity|.
|
--- - severity: See |diagnostic-severity|.
|
||||||
--- - show_header: (boolean, default true) Show "Diagnostics:" header
|
--- - show_header: (boolean, default true) Show "Diagnostics:" header
|
||||||
|
--- - source: (string) Include the diagnostic source in
|
||||||
|
--- the message. One of "always" or "if_many".
|
||||||
---@param bufnr number|nil Buffer number. Defaults to the current buffer.
|
---@param bufnr number|nil Buffer number. Defaults to the current buffer.
|
||||||
---@param position table|nil The (0,0)-indexed position. Defaults to the current cursor position.
|
---@param position table|nil The (0,0)-indexed position. Defaults to the current cursor position.
|
||||||
---@return tuple ({popup_bufnr}, {win_id})
|
---@return tuple ({popup_bufnr}, {win_id})
|
||||||
|
@ -103,6 +103,7 @@ local function diagnostic_lsp_to_vim(diagnostics, bufnr, client_id)
|
|||||||
end_col = line_byte_from_position(buf_lines, _end.line, _end.character, offset_encoding),
|
end_col = line_byte_from_position(buf_lines, _end.line, _end.character, offset_encoding),
|
||||||
severity = severity_lsp_to_vim(diagnostic.severity),
|
severity = severity_lsp_to_vim(diagnostic.severity),
|
||||||
message = diagnostic.message,
|
message = diagnostic.message,
|
||||||
|
source = diagnostic.source,
|
||||||
user_data = {
|
user_data = {
|
||||||
lsp = {
|
lsp = {
|
||||||
code = diagnostic.code,
|
code = diagnostic.code,
|
||||||
@ -132,6 +133,7 @@ local function diagnostic_vim_to_lsp(diagnostics)
|
|||||||
},
|
},
|
||||||
severity = severity_vim_to_lsp(diagnostic.severity),
|
severity = severity_vim_to_lsp(diagnostic.severity),
|
||||||
message = diagnostic.message,
|
message = diagnostic.message,
|
||||||
|
source = diagnostic.source,
|
||||||
}, diagnostic.user_data and (diagnostic.user_data.lsp or {}) or {})
|
}, diagnostic.user_data and (diagnostic.user_data.lsp or {}) or {})
|
||||||
end, diagnostics)
|
end, diagnostics)
|
||||||
end
|
end
|
||||||
|
@ -14,48 +14,32 @@ describe('vim.diagnostic', function()
|
|||||||
exec_lua [[
|
exec_lua [[
|
||||||
require('vim.diagnostic')
|
require('vim.diagnostic')
|
||||||
|
|
||||||
function make_error(msg, x1, y1, x2, y2)
|
function make_diagnostic(msg, x1, y1, x2, y2, severity, source)
|
||||||
return {
|
return {
|
||||||
lnum = x1,
|
lnum = x1,
|
||||||
col = y1,
|
col = y1,
|
||||||
end_lnum = x2,
|
end_lnum = x2,
|
||||||
end_col = y2,
|
end_col = y2,
|
||||||
message = msg,
|
message = msg,
|
||||||
severity = vim.diagnostic.severity.ERROR,
|
severity = severity,
|
||||||
|
source = source,
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
function make_warning(msg, x1, y1, x2, y2)
|
function make_error(msg, x1, y1, x2, y2, source)
|
||||||
return {
|
return make_diagnostic(msg, x1, y1, x2, y2, vim.diagnostic.severity.ERROR, source)
|
||||||
lnum = x1,
|
|
||||||
col = y1,
|
|
||||||
end_lnum = x2,
|
|
||||||
end_col = y2,
|
|
||||||
message = msg,
|
|
||||||
severity = vim.diagnostic.severity.WARN,
|
|
||||||
}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function make_info(msg, x1, y1, x2, y2)
|
function make_warning(msg, x1, y1, x2, y2, source)
|
||||||
return {
|
return make_diagnostic(msg, x1, y1, x2, y2, vim.diagnostic.severity.WARN, source)
|
||||||
lnum = x1,
|
|
||||||
col = y1,
|
|
||||||
end_lnum = x2,
|
|
||||||
end_col = y2,
|
|
||||||
message = msg,
|
|
||||||
severity = vim.diagnostic.severity.INFO,
|
|
||||||
}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function make_hint(msg, x1, y1, x2, y2)
|
function make_info(msg, x1, y1, x2, y2, source)
|
||||||
return {
|
return make_diagnostic(msg, x1, y1, x2, y2, vim.diagnostic.severity.INFO, source)
|
||||||
lnum = x1,
|
end
|
||||||
col = y1,
|
|
||||||
end_lnum = x2,
|
function make_hint(msg, x1, y1, x2, y2, source)
|
||||||
end_col = y2,
|
return make_diagnostic(msg, x1, y1, x2, y2, vim.diagnostic.severity.HINT, source)
|
||||||
message = msg,
|
|
||||||
severity = vim.diagnostic.severity.HINT,
|
|
||||||
}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function count_diagnostics(bufnr, severity, namespace)
|
function count_diagnostics(bufnr, severity, namespace)
|
||||||
@ -590,6 +574,63 @@ describe('vim.diagnostic', function()
|
|||||||
eq({'Error', 'Warn', 'Info'}, result[1])
|
eq({'Error', 'Warn', 'Info'}, result[1])
|
||||||
eq({'Info', 'Warn', 'Error'}, result[2])
|
eq({'Info', 'Warn', 'Error'}, result[2])
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
it('can show diagnostic sources in virtual text', function()
|
||||||
|
local result = exec_lua [[
|
||||||
|
local diagnostics = {
|
||||||
|
make_error('Some error', 0, 0, 0, 0, 'source x'),
|
||||||
|
}
|
||||||
|
|
||||||
|
vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics, {
|
||||||
|
underline = false,
|
||||||
|
virtual_text = {
|
||||||
|
prefix = '',
|
||||||
|
source = 'always',
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
local extmarks = vim.api.nvim_buf_get_extmarks(diagnostic_bufnr, diagnostic_ns, 0, -1, {details = true})
|
||||||
|
local virt_text = extmarks[1][4].virt_text[2][1]
|
||||||
|
return virt_text
|
||||||
|
]]
|
||||||
|
eq(' source x: Some error', result)
|
||||||
|
|
||||||
|
result = exec_lua [[
|
||||||
|
vim.diagnostic.config({
|
||||||
|
underline = false,
|
||||||
|
virtual_text = {
|
||||||
|
prefix = '',
|
||||||
|
source = 'if_many',
|
||||||
|
}
|
||||||
|
}, diagnostic_ns)
|
||||||
|
|
||||||
|
local extmarks = vim.api.nvim_buf_get_extmarks(diagnostic_bufnr, diagnostic_ns, 0, -1, {details = true})
|
||||||
|
local virt_text = extmarks[1][4].virt_text[2][1]
|
||||||
|
return virt_text
|
||||||
|
]]
|
||||||
|
eq(' Some error', result)
|
||||||
|
|
||||||
|
result = exec_lua [[
|
||||||
|
local diagnostics = {
|
||||||
|
make_error('Some error', 0, 0, 0, 0, 'source x'),
|
||||||
|
make_error('Another error', 1, 1, 1, 1, 'source y'),
|
||||||
|
}
|
||||||
|
|
||||||
|
vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics, {
|
||||||
|
underline = false,
|
||||||
|
virtual_text = {
|
||||||
|
prefix = '',
|
||||||
|
source = 'if_many',
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
local extmarks = vim.api.nvim_buf_get_extmarks(diagnostic_bufnr, diagnostic_ns, 0, -1, {details = true})
|
||||||
|
local virt_text = {extmarks[1][4].virt_text[2][1], extmarks[2][4].virt_text[2][1]}
|
||||||
|
return virt_text
|
||||||
|
]]
|
||||||
|
eq(' source x: Some error', result[1])
|
||||||
|
eq(' source y: Another error', result[2])
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
describe('set()', function()
|
describe('set()', function()
|
||||||
@ -854,6 +895,49 @@ describe('vim.diagnostic', function()
|
|||||||
return #vim.api.nvim_buf_get_lines(popup_bufnr, 0, -1, false)
|
return #vim.api.nvim_buf_get_lines(popup_bufnr, 0, -1, false)
|
||||||
]])
|
]])
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
it('can show diagnostic source', function()
|
||||||
|
exec_lua [[vim.api.nvim_win_set_buf(0, diagnostic_bufnr)]]
|
||||||
|
|
||||||
|
eq({"1. Syntax error"}, exec_lua [[
|
||||||
|
local diagnostics = {
|
||||||
|
make_error("Syntax error", 0, 1, 0, 3, "source x"),
|
||||||
|
}
|
||||||
|
vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics)
|
||||||
|
local popup_bufnr, winnr = vim.diagnostic.show_line_diagnostics {
|
||||||
|
show_header = false,
|
||||||
|
source = "if_many",
|
||||||
|
}
|
||||||
|
local lines = vim.api.nvim_buf_get_lines(popup_bufnr, 0, -1, false)
|
||||||
|
vim.api.nvim_win_close(winnr, true)
|
||||||
|
return lines
|
||||||
|
]])
|
||||||
|
|
||||||
|
eq({"1. source x: Syntax error"}, exec_lua [[
|
||||||
|
local popup_bufnr, winnr = vim.diagnostic.show_line_diagnostics {
|
||||||
|
show_header = false,
|
||||||
|
source = "always",
|
||||||
|
}
|
||||||
|
local lines = vim.api.nvim_buf_get_lines(popup_bufnr, 0, -1, false)
|
||||||
|
vim.api.nvim_win_close(winnr, true)
|
||||||
|
return lines
|
||||||
|
]])
|
||||||
|
|
||||||
|
eq({"1. source x: Syntax error", "2. source y: Another error"}, exec_lua [[
|
||||||
|
local diagnostics = {
|
||||||
|
make_error("Syntax error", 0, 1, 0, 3, "source x"),
|
||||||
|
make_error("Another error", 0, 1, 0, 3, "source y"),
|
||||||
|
}
|
||||||
|
vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics)
|
||||||
|
local popup_bufnr, winnr = vim.diagnostic.show_line_diagnostics {
|
||||||
|
show_header = false,
|
||||||
|
source = "if_many",
|
||||||
|
}
|
||||||
|
local lines = vim.api.nvim_buf_get_lines(popup_bufnr, 0, -1, false)
|
||||||
|
vim.api.nvim_win_close(winnr, true)
|
||||||
|
return lines
|
||||||
|
]])
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
describe('set_signs()', function()
|
describe('set_signs()', function()
|
||||||
|
Loading…
Reference in New Issue
Block a user