mirror of
https://github.com/neovim/neovim
synced 2025-07-18 18:21:46 +00:00
feat(diagnostic): add current_line
option for virtual_text
handler
This commit is contained in:
committed by
Christian Clason
parent
09f9f0a946
commit
38a52caec0
@ -621,6 +621,8 @@ Lua module: vim.diagnostic *diagnostic-api*
|
|||||||
• {severity}? (`vim.diagnostic.SeverityFilter`) Only show
|
• {severity}? (`vim.diagnostic.SeverityFilter`) Only show
|
||||||
virtual text for diagnostics matching the given
|
virtual text for diagnostics matching the given
|
||||||
severity |diagnostic-severity|
|
severity |diagnostic-severity|
|
||||||
|
• {current_line}? (`boolean`) Only show diagnostics for the
|
||||||
|
current line. (default `false`)
|
||||||
• {source}? (`boolean|"if_many"`) Include the diagnostic
|
• {source}? (`boolean|"if_many"`) Include the diagnostic
|
||||||
source in virtual text. Use `'if_many'` to only
|
source in virtual text. Use `'if_many'` to only
|
||||||
show sources if there is more than one
|
show sources if there is more than one
|
||||||
|
@ -243,6 +243,8 @@ DIAGNOSTICS
|
|||||||
|vim.diagnostic.jump()|.
|
|vim.diagnostic.jump()|.
|
||||||
• A "virtual_lines" diagnostic handler was added to render diagnostics using
|
• A "virtual_lines" diagnostic handler was added to render diagnostics using
|
||||||
virtual lines below the respective code.
|
virtual lines below the respective code.
|
||||||
|
• The "virtual_text" diagnostic handler accepts a `current_line` option to
|
||||||
|
only show virtual text at the cursor's line.
|
||||||
|
|
||||||
EDITOR
|
EDITOR
|
||||||
|
|
||||||
|
@ -190,6 +190,10 @@ end
|
|||||||
--- severity |diagnostic-severity|
|
--- severity |diagnostic-severity|
|
||||||
--- @field severity? vim.diagnostic.SeverityFilter
|
--- @field severity? vim.diagnostic.SeverityFilter
|
||||||
---
|
---
|
||||||
|
--- Only show diagnostics for the current line.
|
||||||
|
--- (default `false`)
|
||||||
|
--- @field current_line? boolean
|
||||||
|
---
|
||||||
--- Include the diagnostic source in virtual text. Use `'if_many'` to only
|
--- Include the diagnostic source in virtual text. Use `'if_many'` to only
|
||||||
--- show sources if there is more than one diagnostic source in the buffer.
|
--- show sources if there is more than one diagnostic source in the buffer.
|
||||||
--- Otherwise, any truthy value means to always show the diagnostic source.
|
--- Otherwise, any truthy value means to always show the diagnostic source.
|
||||||
@ -630,6 +634,26 @@ local function diagnostic_lines(diagnostics)
|
|||||||
return diagnostics_by_line
|
return diagnostics_by_line
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- @param diagnostics table<integer, vim.Diagnostic[]>
|
||||||
|
--- @return vim.Diagnostic[]
|
||||||
|
local function diagnostics_at_cursor(diagnostics)
|
||||||
|
local lnum = api.nvim_win_get_cursor(0)[1] - 1
|
||||||
|
|
||||||
|
if diagnostics[lnum] ~= nil then
|
||||||
|
return diagnostics[lnum]
|
||||||
|
end
|
||||||
|
|
||||||
|
local cursor_diagnostics = {}
|
||||||
|
for _, line_diags in pairs(diagnostics) do
|
||||||
|
for _, diag in ipairs(line_diags) do
|
||||||
|
if diag.end_lnum and lnum >= diag.lnum and lnum <= diag.end_lnum then
|
||||||
|
table.insert(cursor_diagnostics, diag)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return cursor_diagnostics
|
||||||
|
end
|
||||||
|
|
||||||
--- @param namespace integer
|
--- @param namespace integer
|
||||||
--- @param bufnr integer
|
--- @param bufnr integer
|
||||||
--- @param diagnostics vim.Diagnostic[]
|
--- @param diagnostics vim.Diagnostic[]
|
||||||
@ -1570,6 +1594,28 @@ M.handlers.underline = {
|
|||||||
end,
|
end,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
--- @param namespace integer
|
||||||
|
--- @param bufnr integer
|
||||||
|
--- @param diagnostics table<integer, vim.Diagnostic[]>
|
||||||
|
--- @param opts vim.diagnostic.Opts.VirtualText
|
||||||
|
local function render_virtual_text(namespace, bufnr, diagnostics, opts)
|
||||||
|
api.nvim_buf_clear_namespace(bufnr, namespace, 0, -1)
|
||||||
|
|
||||||
|
for line, line_diagnostics in pairs(diagnostics) do
|
||||||
|
local virt_texts = M._get_virt_text_chunks(line_diagnostics, opts)
|
||||||
|
|
||||||
|
if virt_texts then
|
||||||
|
api.nvim_buf_set_extmark(bufnr, namespace, line, 0, {
|
||||||
|
hl_mode = opts.hl_mode or 'combine',
|
||||||
|
virt_text = virt_texts,
|
||||||
|
virt_text_pos = opts.virt_text_pos,
|
||||||
|
virt_text_hide = opts.virt_text_hide,
|
||||||
|
virt_text_win_col = opts.virt_text_win_col,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
M.handlers.virtual_text = {
|
M.handlers.virtual_text = {
|
||||||
show = function(namespace, bufnr, diagnostics, opts)
|
show = function(namespace, bufnr, diagnostics, opts)
|
||||||
vim.validate('namespace', namespace, 'number')
|
vim.validate('namespace', namespace, 'number')
|
||||||
@ -1601,23 +1647,44 @@ M.handlers.virtual_text = {
|
|||||||
ns.user_data.virt_text_ns =
|
ns.user_data.virt_text_ns =
|
||||||
api.nvim_create_namespace(string.format('nvim.%s.diagnostic.virtual_text', ns.name))
|
api.nvim_create_namespace(string.format('nvim.%s.diagnostic.virtual_text', ns.name))
|
||||||
end
|
end
|
||||||
|
if not ns.user_data.virt_text_augroup then
|
||||||
|
ns.user_data.virt_text_augroup = api.nvim_create_augroup(
|
||||||
|
string.format('nvim.%s.diagnostic.virt_text', ns.name),
|
||||||
|
{ clear = true }
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
local virt_text_ns = ns.user_data.virt_text_ns
|
api.nvim_clear_autocmds({ group = ns.user_data.virt_text_augroup, buffer = bufnr })
|
||||||
local buffer_line_diagnostics = diagnostic_lines(diagnostics)
|
|
||||||
for line, line_diagnostics in pairs(buffer_line_diagnostics) do
|
|
||||||
local virt_texts = M._get_virt_text_chunks(line_diagnostics, opts.virtual_text)
|
|
||||||
|
|
||||||
if virt_texts then
|
local line_diagnostics = diagnostic_lines(diagnostics)
|
||||||
api.nvim_buf_set_extmark(bufnr, virt_text_ns, line, 0, {
|
|
||||||
hl_mode = opts.virtual_text.hl_mode or 'combine',
|
if opts.virtual_text.current_line == true then
|
||||||
virt_text = virt_texts,
|
api.nvim_create_autocmd('CursorMoved', {
|
||||||
virt_text_pos = opts.virtual_text.virt_text_pos,
|
buffer = bufnr,
|
||||||
virt_text_hide = opts.virtual_text.virt_text_hide,
|
group = ns.user_data.virt_text_augroup,
|
||||||
virt_text_win_col = opts.virtual_text.virt_text_win_col,
|
callback = function()
|
||||||
|
local lnum = api.nvim_win_get_cursor(0)[1] - 1
|
||||||
|
render_virtual_text(
|
||||||
|
ns.user_data.virt_text_ns,
|
||||||
|
bufnr,
|
||||||
|
{ [lnum] = diagnostics_at_cursor(line_diagnostics) },
|
||||||
|
opts.virtual_text
|
||||||
|
)
|
||||||
|
end,
|
||||||
})
|
})
|
||||||
|
-- Also show diagnostics for the current line before the first CursorMoved event.
|
||||||
|
local lnum = api.nvim_win_get_cursor(0)[1] - 1
|
||||||
|
render_virtual_text(
|
||||||
|
ns.user_data.virt_text_ns,
|
||||||
|
bufnr,
|
||||||
|
{ [lnum] = diagnostics_at_cursor(line_diagnostics) },
|
||||||
|
opts.virtual_text
|
||||||
|
)
|
||||||
|
else
|
||||||
|
render_virtual_text(ns.user_data.virt_text_ns, bufnr, line_diagnostics, opts.virtual_text)
|
||||||
end
|
end
|
||||||
end
|
|
||||||
save_extmarks(virt_text_ns, bufnr)
|
save_extmarks(ns.user_data.virt_text_ns, bufnr)
|
||||||
end,
|
end,
|
||||||
hide = function(namespace, bufnr)
|
hide = function(namespace, bufnr)
|
||||||
local ns = M.get_namespace(namespace)
|
local ns = M.get_namespace(namespace)
|
||||||
@ -1626,6 +1693,7 @@ M.handlers.virtual_text = {
|
|||||||
if api.nvim_buf_is_valid(bufnr) then
|
if api.nvim_buf_is_valid(bufnr) then
|
||||||
api.nvim_buf_clear_namespace(bufnr, ns.user_data.virt_text_ns, 0, -1)
|
api.nvim_buf_clear_namespace(bufnr, ns.user_data.virt_text_ns, 0, -1)
|
||||||
end
|
end
|
||||||
|
api.nvim_clear_autocmds({ group = ns.user_data.virt_text_augroup, buffer = bufnr })
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
}
|
}
|
||||||
@ -1814,28 +1882,6 @@ local function render_virtual_lines(namespace, bufnr, diagnostics)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param diagnostics table<integer, vim.Diagnostic[]>
|
|
||||||
--- @param namespace integer
|
|
||||||
--- @param bufnr integer
|
|
||||||
local function render_virtual_lines_at_current_line(diagnostics, namespace, bufnr)
|
|
||||||
local lnum = api.nvim_win_get_cursor(0)[1] - 1
|
|
||||||
local cursor_diagnostics = {}
|
|
||||||
|
|
||||||
if diagnostics[lnum] ~= nil then
|
|
||||||
cursor_diagnostics = diagnostics[lnum]
|
|
||||||
else
|
|
||||||
for _, line_diags in pairs(diagnostics) do
|
|
||||||
for _, diag in ipairs(line_diags) do
|
|
||||||
if diag.end_lnum and lnum >= diag.lnum and lnum <= diag.end_lnum then
|
|
||||||
table.insert(cursor_diagnostics, diag)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
render_virtual_lines(namespace, bufnr, cursor_diagnostics)
|
|
||||||
end
|
|
||||||
|
|
||||||
M.handlers.virtual_lines = {
|
M.handlers.virtual_lines = {
|
||||||
show = function(namespace, bufnr, diagnostics, opts)
|
show = function(namespace, bufnr, diagnostics, opts)
|
||||||
vim.validate('namespace', namespace, 'number')
|
vim.validate('namespace', namespace, 'number')
|
||||||
@ -1876,11 +1922,19 @@ M.handlers.virtual_lines = {
|
|||||||
buffer = bufnr,
|
buffer = bufnr,
|
||||||
group = ns.user_data.virt_lines_augroup,
|
group = ns.user_data.virt_lines_augroup,
|
||||||
callback = function()
|
callback = function()
|
||||||
render_virtual_lines_at_current_line(line_diagnostics, ns.user_data.virt_lines_ns, bufnr)
|
render_virtual_lines(
|
||||||
|
ns.user_data.virt_lines_ns,
|
||||||
|
bufnr,
|
||||||
|
diagnostics_at_cursor(line_diagnostics)
|
||||||
|
)
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
-- Also show diagnostics for the current line before the first CursorMoved event.
|
-- Also show diagnostics for the current line before the first CursorMoved event.
|
||||||
render_virtual_lines_at_current_line(line_diagnostics, ns.user_data.virt_lines_ns, bufnr)
|
render_virtual_lines(
|
||||||
|
ns.user_data.virt_lines_ns,
|
||||||
|
bufnr,
|
||||||
|
diagnostics_at_cursor(line_diagnostics)
|
||||||
|
)
|
||||||
else
|
else
|
||||||
render_virtual_lines(ns.user_data.virt_lines_ns, bufnr, diagnostics)
|
render_virtual_lines(ns.user_data.virt_lines_ns, bufnr, diagnostics)
|
||||||
end
|
end
|
||||||
|
@ -2160,6 +2160,25 @@ describe('vim.diagnostic', function()
|
|||||||
eq(1, #result)
|
eq(1, #result)
|
||||||
eq(' An error there!', result[1][4].virt_text[3][1])
|
eq(' An error there!', result[1][4].virt_text[3][1])
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
it('can only show virtual_text for the current line', function()
|
||||||
|
local result = exec_lua(function()
|
||||||
|
vim.api.nvim_win_set_cursor(0, { 1, 0 })
|
||||||
|
|
||||||
|
vim.diagnostic.config({ virtual_text = { current_line = true } })
|
||||||
|
|
||||||
|
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||||||
|
_G.make_error('Error here!', 0, 0, 0, 0, 'foo_server'),
|
||||||
|
_G.make_error('Another error there!', 1, 0, 1, 0, 'foo_server'),
|
||||||
|
})
|
||||||
|
|
||||||
|
local extmarks = _G.get_virt_text_extmarks(_G.diagnostic_ns)
|
||||||
|
return extmarks
|
||||||
|
end)
|
||||||
|
|
||||||
|
eq(1, #result)
|
||||||
|
eq(' Error here!', result[1][4].virt_text[3][1])
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
describe('handlers.virtual_lines', function()
|
describe('handlers.virtual_lines', function()
|
||||||
|
Reference in New Issue
Block a user