mirror of
https://github.com/neovim/neovim.git
synced 2026-08-14 19:39:33 +00:00
Problem: vim.diagnostic.set() defers extmark position computation for an unloaded buffer via a once=true BufRead autocmd, registering a new one on every call without replacing the previous one. Each pending autocmd also retains that call's diagnostics. Solution: Instead of registering an autocmd per set() call, register a single static BufRead autocmd that computes positions from the diagnostic cache for any buffer with cached diagnostics when it is read. This removes the per-call registration entirely (nothing left to accumulate) and means diagnostics cleared while the buffer was unloaded no longer produce stale extmarks.
4548 lines
147 KiB
Lua
4548 lines
147 KiB
Lua
local t = require('test.testutil')
|
||
local n = require('test.functional.testnvim')()
|
||
local Screen = require('test.functional.ui.screen')
|
||
|
||
local describe, it, before_each = t.describe, t.it, t.before_each
|
||
local command = n.command
|
||
local clear = n.clear
|
||
local exec_lua = n.exec_lua
|
||
local eq = t.eq
|
||
local neq = t.neq
|
||
local matches = t.matches
|
||
local retry = t.retry
|
||
local api = n.api
|
||
local pcall_err = t.pcall_err
|
||
local fn = n.fn
|
||
|
||
describe('vim.diagnostic', function()
|
||
before_each(function()
|
||
clear()
|
||
|
||
exec_lua(function()
|
||
require('vim.diagnostic')
|
||
|
||
local function make_diagnostic(msg, lnum, col, end_lnum, end_col, severity, source, code)
|
||
return {
|
||
lnum = lnum,
|
||
col = col,
|
||
end_lnum = end_lnum,
|
||
end_col = end_col,
|
||
message = msg,
|
||
severity = severity,
|
||
source = source,
|
||
code = code,
|
||
}
|
||
end
|
||
|
||
function _G.make_error(msg, lnum, col, end_lnum, end_col, source, code)
|
||
return make_diagnostic(
|
||
msg,
|
||
lnum,
|
||
col,
|
||
end_lnum,
|
||
end_col,
|
||
vim.diagnostic.severity.ERROR,
|
||
source,
|
||
code
|
||
)
|
||
end
|
||
|
||
function _G.make_warning(msg, lnum, col, end_lnum, end_col, source, code)
|
||
return make_diagnostic(
|
||
msg,
|
||
lnum,
|
||
col,
|
||
end_lnum,
|
||
end_col,
|
||
vim.diagnostic.severity.WARN,
|
||
source,
|
||
code
|
||
)
|
||
end
|
||
|
||
function _G.make_info(msg, lnum, col, end_lnum, end_col, source, code)
|
||
return make_diagnostic(
|
||
msg,
|
||
lnum,
|
||
col,
|
||
end_lnum,
|
||
end_col,
|
||
vim.diagnostic.severity.INFO,
|
||
source,
|
||
code
|
||
)
|
||
end
|
||
|
||
function _G.make_hint(msg, lnum, col, end_lnum, end_col, source, code)
|
||
return make_diagnostic(
|
||
msg,
|
||
lnum,
|
||
col,
|
||
end_lnum,
|
||
end_col,
|
||
vim.diagnostic.severity.HINT,
|
||
source,
|
||
code
|
||
)
|
||
end
|
||
|
||
function _G.count_diagnostics(bufnr, severity, namespace)
|
||
return #vim.diagnostic.get(bufnr, { severity = severity, namespace = namespace })
|
||
end
|
||
|
||
function _G.count_extmarks(bufnr, namespace)
|
||
local ns = vim.diagnostic.get_namespace(namespace)
|
||
local extmarks = 0
|
||
if ns.user_data.virt_text_ns then
|
||
extmarks = extmarks
|
||
+ #vim.api.nvim_buf_get_extmarks(bufnr, ns.user_data.virt_text_ns, 0, -1, {})
|
||
end
|
||
if ns.user_data.underline_ns then
|
||
extmarks = extmarks
|
||
+ #vim.api.nvim_buf_get_extmarks(bufnr, ns.user_data.underline_ns, 0, -1, {})
|
||
end
|
||
return extmarks
|
||
end
|
||
|
||
function _G.get_virt_text_extmarks(ns)
|
||
ns = vim.diagnostic.get_namespace(ns)
|
||
local virt_text_ns = ns.user_data.virt_text_ns
|
||
return vim.api.nvim_buf_get_extmarks(
|
||
_G.diagnostic_bufnr,
|
||
virt_text_ns,
|
||
0,
|
||
-1,
|
||
{ details = true }
|
||
)
|
||
end
|
||
|
||
function _G.get_virt_lines_extmarks(ns)
|
||
ns = vim.diagnostic.get_namespace(ns)
|
||
local virt_lines_ns = ns.user_data.virt_lines_ns
|
||
return vim.api.nvim_buf_get_extmarks(
|
||
_G.diagnostic_bufnr,
|
||
virt_lines_ns,
|
||
0,
|
||
-1,
|
||
{ details = true }
|
||
)
|
||
end
|
||
|
||
---@param ns integer
|
||
function _G.get_underline_extmarks(ns)
|
||
---@type integer
|
||
local underline_ns = vim.diagnostic.get_namespace(ns).user_data.underline_ns
|
||
return vim.api.nvim_buf_get_extmarks(
|
||
_G.diagnostic_bufnr,
|
||
underline_ns,
|
||
0,
|
||
-1,
|
||
{ details = true }
|
||
)
|
||
end
|
||
end)
|
||
|
||
exec_lua(function()
|
||
_G.diagnostic_ns = vim.api.nvim_create_namespace('diagnostic_spec')
|
||
_G.other_ns = vim.api.nvim_create_namespace('other_namespace')
|
||
_G.diagnostic_bufnr = vim.api.nvim_create_buf(true, false)
|
||
local lines = { '1st line of text', '2nd line of text', 'wow', 'cool', 'more', 'lines' }
|
||
vim.fn.bufload(_G.diagnostic_bufnr)
|
||
vim.api.nvim_buf_set_lines(_G.diagnostic_bufnr, 0, 1, false, lines)
|
||
end)
|
||
end)
|
||
|
||
it('creates highlight groups', function()
|
||
command('runtime plugin/diagnostic.vim')
|
||
eq({
|
||
'DiagnosticDeprecated',
|
||
'DiagnosticError',
|
||
'DiagnosticFloatingError',
|
||
'DiagnosticFloatingHint',
|
||
'DiagnosticFloatingInfo',
|
||
'DiagnosticFloatingOk',
|
||
'DiagnosticFloatingWarn',
|
||
'DiagnosticHint',
|
||
'DiagnosticInfo',
|
||
'DiagnosticOk',
|
||
'DiagnosticSignError',
|
||
'DiagnosticSignHint',
|
||
'DiagnosticSignInfo',
|
||
'DiagnosticSignOk',
|
||
'DiagnosticSignWarn',
|
||
'DiagnosticUnderlineError',
|
||
'DiagnosticUnderlineHint',
|
||
'DiagnosticUnderlineInfo',
|
||
'DiagnosticUnderlineOk',
|
||
'DiagnosticUnderlineWarn',
|
||
'DiagnosticUnnecessary',
|
||
'DiagnosticVirtualLinesError',
|
||
'DiagnosticVirtualLinesHint',
|
||
'DiagnosticVirtualLinesInfo',
|
||
'DiagnosticVirtualLinesOk',
|
||
'DiagnosticVirtualLinesWarn',
|
||
'DiagnosticVirtualTextError',
|
||
'DiagnosticVirtualTextHint',
|
||
'DiagnosticVirtualTextInfo',
|
||
'DiagnosticVirtualTextOk',
|
||
'DiagnosticVirtualTextWarn',
|
||
'DiagnosticWarn',
|
||
}, fn.getcompletion('Diagnostic', 'highlight'))
|
||
end)
|
||
|
||
it('retrieves diagnostics from all buffers and namespaces', function()
|
||
local result = exec_lua(function()
|
||
local other_bufnr = vim.api.nvim_create_buf(true, false)
|
||
local lines = vim.api.nvim_buf_get_lines(_G.diagnostic_bufnr, 0, -1, true)
|
||
vim.api.nvim_buf_set_lines(other_bufnr, 0, 1, false, lines)
|
||
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_error('Diagnostic #1', 1, 1, 1, 1),
|
||
_G.make_error('Diagnostic #2', 2, 1, 2, 1),
|
||
})
|
||
vim.diagnostic.set(_G.other_ns, other_bufnr, {
|
||
_G.make_error('Diagnostic #3', 3, 1, 3, 1),
|
||
})
|
||
return vim.diagnostic.get()
|
||
end)
|
||
eq(3, #result)
|
||
eq(
|
||
2,
|
||
exec_lua(function()
|
||
return #vim.tbl_filter(function(d)
|
||
return d.bufnr == _G.diagnostic_bufnr
|
||
end, result)
|
||
end)
|
||
)
|
||
eq('Diagnostic #1', result[1].message)
|
||
end)
|
||
|
||
it('removes diagnostics from the cache when a buffer is removed', function()
|
||
eq(
|
||
2,
|
||
exec_lua(function()
|
||
vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
|
||
local other_bufnr = vim.fn.bufadd('test | test')
|
||
local lines = vim.api.nvim_buf_get_lines(_G.diagnostic_bufnr, 0, -1, true)
|
||
vim.api.nvim_buf_set_lines(other_bufnr, 0, 1, false, lines)
|
||
vim.cmd('bunload! ' .. other_bufnr)
|
||
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_error('Diagnostic #1', 1, 1, 1, 1),
|
||
_G.make_error('Diagnostic #2', 2, 1, 2, 1),
|
||
})
|
||
vim.diagnostic.set(_G.diagnostic_ns, other_bufnr, {
|
||
_G.make_error('Diagnostic #3', 3, 1, 3, 1),
|
||
})
|
||
vim.api.nvim_set_current_buf(other_bufnr)
|
||
vim.opt_local.buflisted = true
|
||
vim.cmd('bwipeout!')
|
||
return #vim.diagnostic.get()
|
||
end)
|
||
)
|
||
eq(
|
||
2,
|
||
exec_lua(function()
|
||
vim.api.nvim_set_current_buf(_G.diagnostic_bufnr)
|
||
vim.opt_local.buflisted = false
|
||
return #vim.diagnostic.get()
|
||
end)
|
||
)
|
||
eq(
|
||
0,
|
||
exec_lua(function()
|
||
vim.cmd('bwipeout!')
|
||
return #vim.diagnostic.get()
|
||
end)
|
||
)
|
||
end)
|
||
|
||
it('removes diagnostic from stale cache on reset', function()
|
||
local diagnostics = exec_lua(function()
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_error('Diagnostic #1', 1, 1, 1, 1),
|
||
_G.make_error('Diagnostic #2', 2, 1, 2, 1),
|
||
})
|
||
vim.fn.bufadd('test | test')
|
||
vim.cmd('noautocmd bwipeout! ' .. _G.diagnostic_bufnr)
|
||
return vim.diagnostic.get(_G.diagnostic_bufnr)
|
||
end)
|
||
eq(2, #diagnostics)
|
||
diagnostics = exec_lua(function()
|
||
vim.diagnostic.reset()
|
||
return vim.diagnostic.get()
|
||
end)
|
||
eq(0, #diagnostics)
|
||
end)
|
||
|
||
it('always returns a copy of diagnostic tables', function()
|
||
local result = exec_lua(function()
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_error('Diagnostic #1', 1, 1, 1, 1),
|
||
})
|
||
local diag = vim.diagnostic.get()
|
||
diag[1].col = 10000
|
||
return vim.diagnostic.get()[1].col == 10000
|
||
end)
|
||
eq(false, result)
|
||
end)
|
||
|
||
it('resolves buffer number 0 to the current buffer', function()
|
||
eq(
|
||
2,
|
||
exec_lua(function()
|
||
vim.api.nvim_set_current_buf(_G.diagnostic_bufnr)
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_error('Diagnostic #1', 1, 1, 1, 1),
|
||
_G.make_error('Diagnostic #2', 2, 1, 2, 1),
|
||
})
|
||
return #vim.diagnostic.get(0)
|
||
end)
|
||
)
|
||
end)
|
||
|
||
it('saves and count a single error', function()
|
||
eq(
|
||
1,
|
||
exec_lua(function()
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_error('Diagnostic #1', 1, 1, 1, 1),
|
||
})
|
||
return _G.count_diagnostics(
|
||
_G.diagnostic_bufnr,
|
||
vim.diagnostic.severity.ERROR,
|
||
_G.diagnostic_ns
|
||
)
|
||
end)
|
||
)
|
||
end)
|
||
|
||
it('saves and count multiple errors', function()
|
||
eq(
|
||
2,
|
||
exec_lua(function()
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_error('Diagnostic #1', 1, 1, 1, 1),
|
||
_G.make_error('Diagnostic #2', 2, 1, 2, 1),
|
||
})
|
||
return _G.count_diagnostics(
|
||
_G.diagnostic_bufnr,
|
||
vim.diagnostic.severity.ERROR,
|
||
_G.diagnostic_ns
|
||
)
|
||
end)
|
||
)
|
||
end)
|
||
|
||
it('saves and count from multiple namespaces', function()
|
||
eq(
|
||
{ 1, 1, 2 },
|
||
exec_lua(function()
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_error('Diagnostic From Server 1', 1, 1, 1, 1),
|
||
})
|
||
vim.diagnostic.set(_G.other_ns, _G.diagnostic_bufnr, {
|
||
_G.make_error('Diagnostic From Server 2', 1, 1, 1, 1),
|
||
})
|
||
return {
|
||
-- First namespace
|
||
_G.count_diagnostics(
|
||
_G.diagnostic_bufnr,
|
||
vim.diagnostic.severity.ERROR,
|
||
_G.diagnostic_ns
|
||
),
|
||
-- Second namespace
|
||
_G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.ERROR, _G.other_ns),
|
||
-- All namespaces
|
||
_G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.ERROR),
|
||
}
|
||
end)
|
||
)
|
||
end)
|
||
|
||
it('saves and count from multiple namespaces with respect to severity', function()
|
||
eq(
|
||
{ 3, 0, 3 },
|
||
exec_lua(function()
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_error('Diagnostic From Server 1:1', 1, 1, 1, 1),
|
||
_G.make_error('Diagnostic From Server 1:2', 2, 2, 2, 2),
|
||
_G.make_error('Diagnostic From Server 1:3', 2, 3, 3, 2),
|
||
})
|
||
vim.diagnostic.set(_G.other_ns, _G.diagnostic_bufnr, {
|
||
_G.make_warning('Warning From Server 2', 3, 3, 3, 3),
|
||
})
|
||
return {
|
||
-- Namespace 1
|
||
_G.count_diagnostics(
|
||
_G.diagnostic_bufnr,
|
||
vim.diagnostic.severity.ERROR,
|
||
_G.diagnostic_ns
|
||
),
|
||
-- Namespace 2
|
||
_G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.ERROR, _G.other_ns),
|
||
-- All namespaces
|
||
_G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.ERROR),
|
||
}
|
||
end)
|
||
)
|
||
end)
|
||
|
||
it('handles one namespace clearing highlights while the other still has highlights', function()
|
||
exec_lua(function()
|
||
vim.diagnostic.config({ virtual_text = true })
|
||
end)
|
||
-- 1 Error (1)
|
||
-- 1 Warning (2)
|
||
-- 1 Warning (2) + 1 Warning (1)
|
||
-- 2 highlights and 2 underlines (since error)
|
||
-- 1 highlight + 1 underline
|
||
local all_highlights = { 1, 1, 2, 4, 2 }
|
||
eq(
|
||
all_highlights,
|
||
exec_lua(function()
|
||
local ns_1_diags = {
|
||
_G.make_error('Error 1', 1, 1, 1, 5),
|
||
_G.make_warning('Warning on Server 1', 2, 1, 2, 3),
|
||
}
|
||
local ns_2_diags = {
|
||
_G.make_warning('Warning 1', 2, 1, 2, 3),
|
||
}
|
||
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, ns_1_diags)
|
||
vim.diagnostic.set(_G.other_ns, _G.diagnostic_bufnr, ns_2_diags)
|
||
|
||
return {
|
||
_G.count_diagnostics(
|
||
_G.diagnostic_bufnr,
|
||
vim.diagnostic.severity.ERROR,
|
||
_G.diagnostic_ns
|
||
),
|
||
_G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.WARN, _G.other_ns),
|
||
_G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.WARN),
|
||
_G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns),
|
||
_G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns),
|
||
}
|
||
end)
|
||
)
|
||
|
||
-- Clear diagnostics from namespace 1, and make sure we have the right amount of stuff for namespace 2
|
||
eq(
|
||
{ 1, 1, 2, 0, 2 },
|
||
exec_lua(function()
|
||
vim.diagnostic.enable(false, { bufnr = _G.diagnostic_bufnr, ns_id = _G.diagnostic_ns })
|
||
return {
|
||
_G.count_diagnostics(
|
||
_G.diagnostic_bufnr,
|
||
vim.diagnostic.severity.ERROR,
|
||
_G.diagnostic_ns
|
||
),
|
||
_G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.WARN, _G.other_ns),
|
||
_G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.WARN),
|
||
_G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns),
|
||
_G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns),
|
||
}
|
||
end)
|
||
)
|
||
|
||
-- Show diagnostics from namespace 1 again
|
||
eq(
|
||
all_highlights,
|
||
exec_lua(function()
|
||
vim.diagnostic.enable(true, { bufnr = _G.diagnostic_bufnr, ns_id = _G.diagnostic_ns })
|
||
return {
|
||
_G.count_diagnostics(
|
||
_G.diagnostic_bufnr,
|
||
vim.diagnostic.severity.ERROR,
|
||
_G.diagnostic_ns
|
||
),
|
||
_G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.WARN, _G.other_ns),
|
||
_G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.WARN),
|
||
_G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns),
|
||
_G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns),
|
||
}
|
||
end)
|
||
)
|
||
end)
|
||
|
||
it('does not display diagnostics when disabled', function()
|
||
exec_lua(function()
|
||
vim.diagnostic.config({ virtual_text = true })
|
||
end)
|
||
|
||
eq(
|
||
{ 0, 2 },
|
||
exec_lua(function()
|
||
local ns_1_diags = {
|
||
_G.make_error('Error 1', 1, 1, 1, 5),
|
||
_G.make_warning('Warning on Server 1', 2, 1, 2, 3),
|
||
}
|
||
local ns_2_diags = {
|
||
_G.make_warning('Warning 1', 2, 1, 2, 3),
|
||
}
|
||
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, ns_1_diags)
|
||
vim.diagnostic.set(_G.other_ns, _G.diagnostic_bufnr, ns_2_diags)
|
||
|
||
vim.diagnostic.enable(false, { bufnr = _G.diagnostic_bufnr, ns_id = _G.diagnostic_ns })
|
||
|
||
return {
|
||
_G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns),
|
||
_G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns),
|
||
}
|
||
end)
|
||
)
|
||
|
||
eq(
|
||
{ 4, 0 },
|
||
exec_lua(function()
|
||
vim.diagnostic.enable(true, { bufnr = _G.diagnostic_bufnr, ns_id = _G.diagnostic_ns })
|
||
vim.diagnostic.enable(false, { bufnr = _G.diagnostic_bufnr, ns_id = _G.other_ns })
|
||
|
||
return {
|
||
_G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns),
|
||
_G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns),
|
||
}
|
||
end)
|
||
)
|
||
end)
|
||
|
||
describe('show() and hide()', function()
|
||
it('works', function()
|
||
local result = exec_lua(function()
|
||
local other_bufnr = vim.api.nvim_create_buf(true, false)
|
||
|
||
vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
|
||
|
||
local result = {}
|
||
|
||
vim.diagnostic.config({ underline = false, virtual_text = true })
|
||
|
||
local ns_1_diags = {
|
||
_G.make_error('Error 1', 1, 1, 1, 5),
|
||
_G.make_warning('Warning on Server 1', 2, 1, 2, 5),
|
||
}
|
||
local ns_2_diags = {
|
||
_G.make_warning('Warning 1', 2, 1, 2, 5),
|
||
}
|
||
local other_buffer_diags = {
|
||
_G.make_info('This is interesting', 0, 0, 0, 0),
|
||
}
|
||
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, ns_1_diags)
|
||
vim.diagnostic.set(_G.other_ns, _G.diagnostic_bufnr, ns_2_diags)
|
||
vim.diagnostic.set(_G.diagnostic_ns, other_bufnr, other_buffer_diags)
|
||
|
||
-- All buffers and namespaces
|
||
table.insert(
|
||
result,
|
||
_G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns)
|
||
+ _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns)
|
||
+ _G.count_extmarks(other_bufnr, _G.diagnostic_ns)
|
||
)
|
||
|
||
-- Hide one namespace
|
||
vim.diagnostic.hide(_G.diagnostic_ns)
|
||
table.insert(
|
||
result,
|
||
_G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns)
|
||
+ _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns)
|
||
+ _G.count_extmarks(other_bufnr, _G.diagnostic_ns)
|
||
)
|
||
|
||
-- Show one namespace
|
||
vim.diagnostic.show(_G.diagnostic_ns)
|
||
table.insert(
|
||
result,
|
||
_G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns)
|
||
+ _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns)
|
||
+ _G.count_extmarks(other_bufnr, _G.diagnostic_ns)
|
||
)
|
||
|
||
-- Hide one buffer
|
||
vim.diagnostic.hide(nil, other_bufnr)
|
||
table.insert(
|
||
result,
|
||
_G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns)
|
||
+ _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns)
|
||
+ _G.count_extmarks(other_bufnr, _G.diagnostic_ns)
|
||
)
|
||
|
||
-- Hide everything
|
||
vim.diagnostic.hide()
|
||
table.insert(
|
||
result,
|
||
_G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns)
|
||
+ _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns)
|
||
+ _G.count_extmarks(other_bufnr, _G.diagnostic_ns)
|
||
)
|
||
|
||
-- Show one buffer
|
||
vim.diagnostic.show(nil, _G.diagnostic_bufnr)
|
||
table.insert(
|
||
result,
|
||
_G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns)
|
||
+ _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns)
|
||
+ _G.count_extmarks(other_bufnr, _G.diagnostic_ns)
|
||
)
|
||
|
||
return result
|
||
end)
|
||
|
||
eq(4, result[1])
|
||
eq(1, result[2])
|
||
eq(4, result[3])
|
||
eq(3, result[4])
|
||
eq(0, result[5])
|
||
eq(3, result[6])
|
||
end)
|
||
|
||
it("doesn't error after bwipeout on buffer", function()
|
||
exec_lua(function()
|
||
vim.diagnostic.set(
|
||
_G.diagnostic_ns,
|
||
_G.diagnostic_bufnr,
|
||
{ { message = '', lnum = 0, end_lnum = 0, col = 0, end_col = 0 } }
|
||
)
|
||
vim.cmd('bwipeout! ' .. _G.diagnostic_bufnr)
|
||
|
||
vim.diagnostic.show(_G.diagnostic_ns)
|
||
vim.diagnostic.hide(_G.diagnostic_ns)
|
||
end)
|
||
end)
|
||
|
||
it('handles diagnostics without extmark_id', function()
|
||
exec_lua(function()
|
||
vim.diagnostic.config({ virtual_text = true })
|
||
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_error('Error message', 0, 0, 0, 5),
|
||
})
|
||
|
||
local diags = vim.diagnostic.get(_G.diagnostic_bufnr, { namespace = _G.diagnostic_ns })
|
||
diags[1]._extmark_id = nil
|
||
|
||
vim.diagnostic.show(_G.diagnostic_ns, _G.diagnostic_bufnr, diags)
|
||
end)
|
||
end)
|
||
end)
|
||
|
||
describe('enable() and disable()', function()
|
||
it('validation', function()
|
||
matches('expected boolean, got table', pcall_err(exec_lua, [[vim.diagnostic.enable({})]]))
|
||
matches(
|
||
'filter: expected table, got string',
|
||
pcall_err(exec_lua, [[vim.diagnostic.enable(false, '')]])
|
||
)
|
||
matches(
|
||
'Invalid buffer id: 42',
|
||
pcall_err(exec_lua, [[vim.diagnostic.enable(true, { bufnr = 42 })]])
|
||
)
|
||
matches(
|
||
'expected boolean, got number',
|
||
pcall_err(exec_lua, [[vim.diagnostic.enable(42, {})]])
|
||
)
|
||
matches('expected boolean, got table', pcall_err(exec_lua, [[vim.diagnostic.enable({}, 42)]]))
|
||
end)
|
||
|
||
it('without arguments', function()
|
||
local result = exec_lua(function()
|
||
vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
|
||
|
||
local result = {}
|
||
|
||
vim.diagnostic.config({ underline = false, virtual_text = true })
|
||
|
||
local ns_1_diags = {
|
||
_G.make_error('Error 1', 1, 1, 1, 5),
|
||
_G.make_warning('Warning on Server 1', 2, 1, 2, 5),
|
||
}
|
||
local ns_2_diags = {
|
||
_G.make_warning('Warning 1', 2, 1, 2, 5),
|
||
}
|
||
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, ns_1_diags)
|
||
vim.diagnostic.set(_G.other_ns, _G.diagnostic_bufnr, ns_2_diags)
|
||
|
||
table.insert(
|
||
result,
|
||
_G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns)
|
||
+ _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns)
|
||
)
|
||
|
||
vim.diagnostic.enable(false)
|
||
|
||
table.insert(
|
||
result,
|
||
_G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns)
|
||
+ _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns)
|
||
)
|
||
|
||
-- Create a new buffer
|
||
local other_bufnr = vim.api.nvim_create_buf(true, false)
|
||
local other_buffer_diags = {
|
||
_G.make_info('This is interesting', 0, 0, 0, 0),
|
||
}
|
||
|
||
vim.diagnostic.set(_G.diagnostic_ns, other_bufnr, other_buffer_diags)
|
||
|
||
table.insert(
|
||
result,
|
||
_G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns)
|
||
+ _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns)
|
||
+ _G.count_extmarks(other_bufnr, _G.diagnostic_ns)
|
||
)
|
||
|
||
vim.diagnostic.enable()
|
||
|
||
table.insert(
|
||
result,
|
||
_G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns)
|
||
+ _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns)
|
||
+ _G.count_extmarks(other_bufnr, _G.diagnostic_ns)
|
||
)
|
||
|
||
return result
|
||
end)
|
||
|
||
eq(3, result[1])
|
||
eq(0, result[2])
|
||
eq(0, result[3])
|
||
eq(4, result[4])
|
||
end)
|
||
|
||
it('with buffer argument', function()
|
||
local result = exec_lua(function()
|
||
local other_bufnr = vim.api.nvim_create_buf(true, false)
|
||
|
||
vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
|
||
|
||
local result = {}
|
||
|
||
vim.diagnostic.config({ underline = false, virtual_text = true })
|
||
|
||
local ns_1_diags = {
|
||
_G.make_error('Error 1', 1, 1, 1, 5),
|
||
_G.make_warning('Warning on Server 1', 2, 1, 2, 5),
|
||
}
|
||
local ns_2_diags = {
|
||
_G.make_warning('Warning 1', 2, 1, 2, 5),
|
||
}
|
||
local other_buffer_diags = {
|
||
_G.make_info('This is interesting', 0, 0, 0, 0),
|
||
}
|
||
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, ns_1_diags)
|
||
vim.diagnostic.set(_G.other_ns, _G.diagnostic_bufnr, ns_2_diags)
|
||
vim.diagnostic.set(_G.diagnostic_ns, other_bufnr, other_buffer_diags)
|
||
|
||
table.insert(
|
||
result,
|
||
_G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns)
|
||
+ _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns)
|
||
+ _G.count_extmarks(other_bufnr, _G.diagnostic_ns)
|
||
)
|
||
|
||
vim.diagnostic.enable(false, { bufnr = _G.diagnostic_bufnr })
|
||
|
||
table.insert(
|
||
result,
|
||
_G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns)
|
||
+ _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns)
|
||
+ _G.count_extmarks(other_bufnr, _G.diagnostic_ns)
|
||
)
|
||
|
||
vim.diagnostic.enable(true, { bufnr = _G.diagnostic_bufnr })
|
||
|
||
table.insert(
|
||
result,
|
||
_G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns)
|
||
+ _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns)
|
||
+ _G.count_extmarks(other_bufnr, _G.diagnostic_ns)
|
||
)
|
||
|
||
vim.diagnostic.enable(false, { bufnr = other_bufnr })
|
||
|
||
table.insert(
|
||
result,
|
||
_G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns)
|
||
+ _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns)
|
||
+ _G.count_extmarks(other_bufnr, _G.diagnostic_ns)
|
||
)
|
||
|
||
return result
|
||
end)
|
||
|
||
eq(4, result[1])
|
||
eq(1, result[2])
|
||
eq(4, result[3])
|
||
eq(3, result[4])
|
||
end)
|
||
|
||
it('with a namespace argument', function()
|
||
local result = exec_lua(function()
|
||
vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
|
||
|
||
local result = {}
|
||
|
||
vim.diagnostic.config({ underline = false, virtual_text = true })
|
||
|
||
local ns_1_diags = {
|
||
_G.make_error('Error 1', 1, 1, 1, 5),
|
||
_G.make_warning('Warning on Server 1', 2, 1, 2, 5),
|
||
}
|
||
local ns_2_diags = {
|
||
_G.make_warning('Warning 1', 2, 1, 2, 5),
|
||
}
|
||
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, ns_1_diags)
|
||
vim.diagnostic.set(_G.other_ns, _G.diagnostic_bufnr, ns_2_diags)
|
||
|
||
table.insert(
|
||
result,
|
||
_G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns)
|
||
+ _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns)
|
||
)
|
||
|
||
vim.diagnostic.enable(false, { ns_id = _G.diagnostic_ns })
|
||
|
||
table.insert(
|
||
result,
|
||
_G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns)
|
||
+ _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns)
|
||
)
|
||
|
||
vim.diagnostic.enable(true, { ns_id = _G.diagnostic_ns })
|
||
|
||
table.insert(
|
||
result,
|
||
_G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns)
|
||
+ _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns)
|
||
)
|
||
|
||
vim.diagnostic.enable(false, { ns_id = _G.other_ns })
|
||
|
||
table.insert(
|
||
result,
|
||
_G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns)
|
||
+ _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns)
|
||
)
|
||
|
||
return result
|
||
end)
|
||
|
||
eq(3, result[1])
|
||
eq(1, result[2])
|
||
eq(3, result[3])
|
||
eq(2, result[4])
|
||
end)
|
||
|
||
--- @return table
|
||
local function test_enable()
|
||
return exec_lua(function()
|
||
local other_bufnr = vim.api.nvim_create_buf(true, false)
|
||
|
||
vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
|
||
|
||
local result = {}
|
||
|
||
vim.diagnostic.config({ underline = false, virtual_text = true })
|
||
|
||
local ns_1_diags = {
|
||
_G.make_error('Error 1', 1, 1, 1, 5),
|
||
_G.make_warning('Warning on Server 1', 2, 1, 2, 5),
|
||
}
|
||
local ns_2_diags = {
|
||
_G.make_warning('Warning 1', 2, 1, 2, 5),
|
||
}
|
||
local other_buffer_diags = {
|
||
_G.make_info('This is interesting', 0, 0, 0, 0),
|
||
}
|
||
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, ns_1_diags)
|
||
vim.diagnostic.set(_G.other_ns, _G.diagnostic_bufnr, ns_2_diags)
|
||
vim.diagnostic.set(_G.diagnostic_ns, other_bufnr, other_buffer_diags)
|
||
|
||
table.insert(
|
||
result,
|
||
_G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns)
|
||
+ _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns)
|
||
+ _G.count_extmarks(other_bufnr, _G.diagnostic_ns)
|
||
)
|
||
|
||
vim.diagnostic.enable(false, { bufnr = _G.diagnostic_bufnr, ns_id = _G.diagnostic_ns })
|
||
|
||
table.insert(
|
||
result,
|
||
_G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns)
|
||
+ _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns)
|
||
+ _G.count_extmarks(other_bufnr, _G.diagnostic_ns)
|
||
)
|
||
|
||
vim.diagnostic.enable(false, { bufnr = _G.diagnostic_bufnr, ns_id = _G.other_ns })
|
||
|
||
table.insert(
|
||
result,
|
||
_G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns)
|
||
+ _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns)
|
||
+ _G.count_extmarks(other_bufnr, _G.diagnostic_ns)
|
||
)
|
||
|
||
vim.diagnostic.enable(true, { bufnr = _G.diagnostic_bufnr, ns_id = _G.diagnostic_ns })
|
||
|
||
table.insert(
|
||
result,
|
||
_G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns)
|
||
+ _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns)
|
||
+ _G.count_extmarks(other_bufnr, _G.diagnostic_ns)
|
||
)
|
||
|
||
-- Should have no effect
|
||
vim.diagnostic.enable(false, { bufnr = other_bufnr, ns_id = _G.other_ns })
|
||
|
||
table.insert(
|
||
result,
|
||
_G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns)
|
||
+ _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns)
|
||
+ _G.count_extmarks(other_bufnr, _G.diagnostic_ns)
|
||
)
|
||
|
||
return result
|
||
end)
|
||
end
|
||
|
||
it('with both buffer and namespace arguments', function()
|
||
local result = test_enable()
|
||
eq(4, result[1])
|
||
eq(2, result[2])
|
||
eq(1, result[3])
|
||
eq(3, result[4])
|
||
eq(3, result[5])
|
||
end)
|
||
end)
|
||
|
||
describe('reset()', function()
|
||
it('diagnostic count is 0 and displayed diagnostics are 0 after call', function()
|
||
exec_lua(function()
|
||
vim.diagnostic.config({ virtual_text = true })
|
||
end)
|
||
|
||
-- 1 Error (1)
|
||
-- 1 Warning (2)
|
||
-- 1 Warning (2) + 1 Warning (1)
|
||
-- 2 highlights and 2 underlines (since error)
|
||
-- 1 highlight + 1 underline
|
||
local all_highlights = { 1, 1, 2, 4, 2 }
|
||
eq(
|
||
all_highlights,
|
||
exec_lua(function()
|
||
local ns_1_diags = {
|
||
_G.make_error('Error 1', 1, 1, 1, 5),
|
||
_G.make_warning('Warning on Server 1', 2, 1, 2, 3),
|
||
}
|
||
local ns_2_diags = {
|
||
_G.make_warning('Warning 1', 2, 1, 2, 3),
|
||
}
|
||
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, ns_1_diags)
|
||
vim.diagnostic.set(_G.other_ns, _G.diagnostic_bufnr, ns_2_diags)
|
||
|
||
return {
|
||
_G.count_diagnostics(
|
||
_G.diagnostic_bufnr,
|
||
vim.diagnostic.severity.ERROR,
|
||
_G.diagnostic_ns
|
||
),
|
||
_G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.WARN, _G.other_ns),
|
||
_G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.WARN),
|
||
_G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns),
|
||
_G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns),
|
||
}
|
||
end)
|
||
)
|
||
|
||
-- Reset diagnostics from namespace 1
|
||
exec_lua([[ vim.diagnostic.reset( _G.diagnostic_ns) ]])
|
||
|
||
-- Make sure we have the right diagnostic count
|
||
eq(
|
||
{ 0, 1, 1, 0, 2 },
|
||
exec_lua(function()
|
||
local diagnostic_count = {}
|
||
vim.wait(100, function()
|
||
diagnostic_count = {
|
||
_G.count_diagnostics(
|
||
_G.diagnostic_bufnr,
|
||
vim.diagnostic.severity.ERROR,
|
||
_G.diagnostic_ns
|
||
),
|
||
_G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.WARN, _G.other_ns),
|
||
_G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.WARN),
|
||
_G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns),
|
||
_G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns),
|
||
}
|
||
end)
|
||
return diagnostic_count
|
||
end)
|
||
)
|
||
|
||
-- Reset diagnostics from namespace 2
|
||
exec_lua([[ vim.diagnostic.reset(_G.other_ns) ]])
|
||
|
||
-- Make sure we have the right diagnostic count
|
||
eq(
|
||
{ 0, 0, 0, 0, 0 },
|
||
exec_lua(function()
|
||
local diagnostic_count = {}
|
||
vim.wait(100, function()
|
||
diagnostic_count = {
|
||
_G.count_diagnostics(
|
||
_G.diagnostic_bufnr,
|
||
vim.diagnostic.severity.ERROR,
|
||
_G.diagnostic_ns
|
||
),
|
||
_G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.WARN, _G.other_ns),
|
||
_G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.WARN),
|
||
_G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns),
|
||
_G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns),
|
||
}
|
||
end)
|
||
return diagnostic_count
|
||
end)
|
||
)
|
||
end)
|
||
|
||
it("doesn't error after bwipeout called on buffer", function()
|
||
exec_lua(function()
|
||
vim.diagnostic.set(
|
||
_G.diagnostic_ns,
|
||
_G.diagnostic_bufnr,
|
||
{ { message = '', lnum = 0, end_lnum = 0, col = 0, end_col = 0 } }
|
||
)
|
||
vim.cmd('bwipeout! ' .. _G.diagnostic_bufnr)
|
||
|
||
vim.diagnostic.reset(_G.diagnostic_ns)
|
||
end)
|
||
end)
|
||
end)
|
||
|
||
describe('get_next()', function()
|
||
it('can find the next pos with only one namespace', function()
|
||
eq(
|
||
{ 1, 1 },
|
||
exec_lua(function()
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_error('Diagnostic #1', 1, 1, 1, 1),
|
||
})
|
||
vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
|
||
local next = vim.diagnostic.get_next()
|
||
return { next.lnum, next.col }
|
||
end)
|
||
)
|
||
end)
|
||
|
||
it('can find next pos with two errors', function()
|
||
eq(
|
||
{ 4, 4 },
|
||
exec_lua(function()
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_error('Diagnostic #1', 1, 1, 1, 1),
|
||
_G.make_error('Diagnostic #2', 4, 4, 4, 4),
|
||
})
|
||
vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
|
||
vim.api.nvim_win_set_cursor(0, { 3, 1 })
|
||
local next = vim.diagnostic.get_next({ namespace = _G.diagnostic_ns })
|
||
return { next.lnum, next.col }
|
||
end)
|
||
)
|
||
end)
|
||
|
||
it('can cycle when position is past error', function()
|
||
eq(
|
||
{ 1, 1 },
|
||
exec_lua(function()
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_error('Diagnostic #1', 1, 1, 1, 1),
|
||
})
|
||
vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
|
||
vim.api.nvim_win_set_cursor(0, { 3, 1 })
|
||
local next = vim.diagnostic.get_next({ namespace = _G.diagnostic_ns })
|
||
return { next.lnum, next.col }
|
||
end)
|
||
)
|
||
end)
|
||
|
||
it('will not cycle when wrap is off', function()
|
||
eq(
|
||
nil,
|
||
exec_lua(function()
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_error('Diagnostic #1', 1, 1, 1, 1),
|
||
})
|
||
vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
|
||
vim.api.nvim_win_set_cursor(0, { 3, 1 })
|
||
local next = vim.diagnostic.get_next({ namespace = _G.diagnostic_ns, wrap = false })
|
||
return next
|
||
end)
|
||
)
|
||
end)
|
||
|
||
it('can cycle even from the last line', function()
|
||
eq(
|
||
{ 4, 4 },
|
||
exec_lua(function()
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_error('Diagnostic #2', 4, 4, 4, 4),
|
||
})
|
||
vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
|
||
vim.api.nvim_win_set_cursor(0, { vim.api.nvim_buf_line_count(0), 1 })
|
||
local prev = vim.diagnostic.get_prev({ namespace = _G.diagnostic_ns })
|
||
return { prev.lnum, prev.col }
|
||
end)
|
||
)
|
||
end)
|
||
|
||
it('works with diagnostics past the end of the line #16349', function()
|
||
eq(
|
||
{ 4, 0 },
|
||
exec_lua(function()
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_error('Diagnostic #1', 3, 9001, 3, 9001),
|
||
_G.make_error('Diagnostic #2', 4, 0, 4, 0),
|
||
})
|
||
vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
|
||
vim.api.nvim_win_set_cursor(0, { 1, 1 })
|
||
vim.diagnostic.jump({ count = 1 })
|
||
local next = vim.diagnostic.get_next({ namespace = _G.diagnostic_ns })
|
||
return { next.lnum, next.col }
|
||
end)
|
||
)
|
||
end)
|
||
|
||
it('works with diagnostics before the start of the line', function()
|
||
eq(
|
||
{ 4, 0 },
|
||
exec_lua(function()
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_error('Diagnostic #1', 3, 9001, 3, 9001),
|
||
_G.make_error('Diagnostic #2', 4, -1, 4, -1),
|
||
})
|
||
vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
|
||
vim.api.nvim_win_set_cursor(0, { 1, 1 })
|
||
vim.diagnostic.jump({ count = 1 })
|
||
local next = vim.diagnostic.get_next({ namespace = _G.diagnostic_ns })
|
||
return { next.lnum, next.col }
|
||
end)
|
||
)
|
||
end)
|
||
|
||
it('jumps to diagnostic with highest severity', function()
|
||
exec_lua(function()
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_info('Info', 1, 0, 1, 1),
|
||
_G.make_error('Error', 2, 0, 2, 1),
|
||
_G.make_warning('Warning', 3, 0, 3, 1),
|
||
_G.make_error('Error', 4, 0, 4, 1),
|
||
})
|
||
|
||
vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
|
||
vim.api.nvim_win_set_cursor(0, { 1, 0 })
|
||
end)
|
||
|
||
eq(
|
||
{ 3, 0 },
|
||
exec_lua(function()
|
||
vim.diagnostic.jump({ count = 1, _highest = true })
|
||
return vim.api.nvim_win_get_cursor(0)
|
||
end)
|
||
)
|
||
|
||
eq(
|
||
{ 5, 0 },
|
||
exec_lua(function()
|
||
vim.diagnostic.jump({ count = 1, _highest = true })
|
||
return vim.api.nvim_win_get_cursor(0)
|
||
end)
|
||
)
|
||
|
||
exec_lua(function()
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_info('Info', 1, 0, 1, 1),
|
||
_G.make_hint('Hint', 2, 0, 2, 1),
|
||
_G.make_warning('Warning', 3, 0, 3, 1),
|
||
_G.make_hint('Hint', 4, 0, 4, 1),
|
||
_G.make_warning('Warning', 5, 0, 5, 1),
|
||
})
|
||
|
||
vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
|
||
vim.api.nvim_win_set_cursor(0, { 1, 0 })
|
||
end)
|
||
|
||
eq(
|
||
{ 4, 0 },
|
||
exec_lua(function()
|
||
vim.diagnostic.jump({ count = 1, _highest = true })
|
||
return vim.api.nvim_win_get_cursor(0)
|
||
end)
|
||
)
|
||
|
||
eq(
|
||
{ 6, 0 },
|
||
exec_lua(function()
|
||
vim.diagnostic.jump({ count = 1, _highest = true })
|
||
return vim.api.nvim_win_get_cursor(0)
|
||
end)
|
||
)
|
||
end)
|
||
|
||
it('jumps to next diagnostic if severity is non-nil', function()
|
||
exec_lua(function()
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_info('Info', 1, 0, 1, 1),
|
||
_G.make_error('Error', 2, 0, 2, 1),
|
||
_G.make_warning('Warning', 3, 0, 3, 1),
|
||
_G.make_error('Error', 4, 0, 4, 1),
|
||
})
|
||
|
||
vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
|
||
vim.api.nvim_win_set_cursor(0, { 1, 0 })
|
||
end)
|
||
|
||
eq(
|
||
{ 2, 0 },
|
||
exec_lua(function()
|
||
vim.diagnostic.jump({ count = 1 })
|
||
return vim.api.nvim_win_get_cursor(0)
|
||
end)
|
||
)
|
||
|
||
eq(
|
||
{ 3, 0 },
|
||
exec_lua(function()
|
||
vim.diagnostic.jump({ count = 1 })
|
||
return vim.api.nvim_win_get_cursor(0)
|
||
end)
|
||
)
|
||
|
||
eq(
|
||
{ 4, 0 },
|
||
exec_lua(function()
|
||
vim.diagnostic.jump({ count = 1 })
|
||
return vim.api.nvim_win_get_cursor(0)
|
||
end)
|
||
)
|
||
end)
|
||
end)
|
||
|
||
describe('get_prev()', function()
|
||
it('can find the previous diagnostic with only one namespace', function()
|
||
eq(
|
||
{ 1, 1 },
|
||
exec_lua(function()
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_error('Diagnostic #1', 1, 1, 1, 1),
|
||
})
|
||
vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
|
||
vim.api.nvim_win_set_cursor(0, { 3, 1 })
|
||
local prev = vim.diagnostic.get_prev()
|
||
return { prev.lnum, prev.col }
|
||
end)
|
||
)
|
||
end)
|
||
|
||
it('can find the previous diagnostic with two errors', function()
|
||
eq(
|
||
{ 1, 1 },
|
||
exec_lua(function()
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_error('Diagnostic #1', 1, 1, 1, 1),
|
||
_G.make_error('Diagnostic #2', 4, 4, 4, 4),
|
||
})
|
||
vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
|
||
vim.api.nvim_win_set_cursor(0, { 3, 1 })
|
||
local prev = vim.diagnostic.get_prev({ namespace = _G.diagnostic_ns })
|
||
return { prev.lnum, prev.col }
|
||
end)
|
||
)
|
||
end)
|
||
|
||
it('can cycle when position is past error', function()
|
||
eq(
|
||
{ 4, 4 },
|
||
exec_lua(function()
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_error('Diagnostic #2', 4, 4, 4, 4),
|
||
})
|
||
vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
|
||
vim.api.nvim_win_set_cursor(0, { 3, 1 })
|
||
local prev = vim.diagnostic.get_prev({ namespace = _G.diagnostic_ns })
|
||
return { prev.lnum, prev.col }
|
||
end)
|
||
)
|
||
end)
|
||
|
||
it('respects wrap parameter', function()
|
||
eq(
|
||
nil,
|
||
exec_lua(function()
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_error('Diagnostic #2', 4, 4, 4, 4),
|
||
})
|
||
vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
|
||
vim.api.nvim_win_set_cursor(0, { 3, 1 })
|
||
local prev = vim.diagnostic.get_prev({ namespace = _G.diagnostic_ns, wrap = false })
|
||
return prev
|
||
end)
|
||
)
|
||
end)
|
||
|
||
it('works on blank line #28397', function()
|
||
eq(
|
||
{ 0, 2 },
|
||
exec_lua(function()
|
||
local test_bufnr = vim.api.nvim_create_buf(true, false)
|
||
vim.api.nvim_buf_set_lines(test_bufnr, 0, -1, false, {
|
||
'first line',
|
||
'',
|
||
'',
|
||
'end line',
|
||
})
|
||
vim.diagnostic.set(_G.diagnostic_ns, test_bufnr, {
|
||
_G.make_info('Diagnostic #1', 0, 2, 0, 2),
|
||
_G.make_info('Diagnostic #2', 2, 0, 2, 0),
|
||
_G.make_info('Diagnostic #3', 2, 0, 2, 0),
|
||
})
|
||
vim.api.nvim_win_set_buf(0, test_bufnr)
|
||
vim.api.nvim_win_set_cursor(0, { 3, 0 })
|
||
return vim.diagnostic.get_prev_pos { namespace = _G.diagnostic_ns }
|
||
end)
|
||
)
|
||
end)
|
||
end)
|
||
|
||
describe('jump()', function()
|
||
before_each(function()
|
||
exec_lua(function()
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_error('Diagnostic #1', 0, 0, 0, 2),
|
||
_G.make_error('Diagnostic #2', 1, 1, 1, 4),
|
||
_G.make_warning('Diagnostic #3', 2, -1, 2, -1),
|
||
_G.make_info('Diagnostic #4', 3, 0, 3, 3),
|
||
})
|
||
vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
|
||
end)
|
||
end)
|
||
|
||
it('can move forward', function()
|
||
eq(
|
||
{ 2, 1 },
|
||
exec_lua(function()
|
||
vim.api.nvim_win_set_cursor(0, { 1, 0 })
|
||
vim.diagnostic.jump({ count = 1 })
|
||
return vim.api.nvim_win_get_cursor(0)
|
||
end)
|
||
)
|
||
|
||
eq(
|
||
{ 4, 0 },
|
||
exec_lua(function()
|
||
vim.api.nvim_win_set_cursor(0, { 1, 0 })
|
||
vim.diagnostic.jump({ count = 3 })
|
||
return vim.api.nvim_win_get_cursor(0)
|
||
end)
|
||
)
|
||
|
||
eq(
|
||
{ 4, 0 },
|
||
exec_lua(function()
|
||
vim.api.nvim_win_set_cursor(0, { 1, 0 })
|
||
vim.diagnostic.jump({ count = math.huge, wrap = false })
|
||
return vim.api.nvim_win_get_cursor(0)
|
||
end)
|
||
)
|
||
end)
|
||
|
||
it('can move backward', function()
|
||
eq(
|
||
{ 3, 0 },
|
||
exec_lua(function()
|
||
vim.api.nvim_win_set_cursor(0, { 4, 0 })
|
||
vim.diagnostic.jump({ count = -1 })
|
||
return vim.api.nvim_win_get_cursor(0)
|
||
end)
|
||
)
|
||
|
||
eq(
|
||
{ 1, 0 },
|
||
exec_lua(function()
|
||
vim.api.nvim_win_set_cursor(0, { 4, 0 })
|
||
vim.diagnostic.jump({ count = -3 })
|
||
return vim.api.nvim_win_get_cursor(0)
|
||
end)
|
||
)
|
||
|
||
eq(
|
||
{ 1, 0 },
|
||
exec_lua(function()
|
||
vim.api.nvim_win_set_cursor(0, { 4, 0 })
|
||
vim.diagnostic.jump({ count = -math.huge, wrap = false })
|
||
return vim.api.nvim_win_get_cursor(0)
|
||
end)
|
||
)
|
||
end)
|
||
|
||
it('can filter by severity', function()
|
||
eq(
|
||
{ 3, 0 },
|
||
exec_lua(function()
|
||
vim.api.nvim_win_set_cursor(0, { 1, 0 })
|
||
vim.diagnostic.jump({ count = 1, severity = vim.diagnostic.severity.WARN })
|
||
return vim.api.nvim_win_get_cursor(0)
|
||
end)
|
||
)
|
||
|
||
eq(
|
||
{ 3, 0 },
|
||
exec_lua(function()
|
||
vim.api.nvim_win_set_cursor(0, { 1, 0 })
|
||
vim.diagnostic.jump({ count = 9999, severity = vim.diagnostic.severity.WARN })
|
||
return vim.api.nvim_win_get_cursor(0)
|
||
end)
|
||
)
|
||
end)
|
||
|
||
it('can wrap', function()
|
||
eq(
|
||
{ 1, 0 },
|
||
exec_lua(function()
|
||
vim.api.nvim_win_set_cursor(0, { 4, 0 })
|
||
vim.diagnostic.jump({ count = 1, wrap = true })
|
||
return vim.api.nvim_win_get_cursor(0)
|
||
end)
|
||
)
|
||
|
||
eq(
|
||
{ 4, 0 },
|
||
exec_lua(function()
|
||
vim.api.nvim_win_set_cursor(0, { 1, 0 })
|
||
vim.diagnostic.jump({ count = -1, wrap = true })
|
||
return vim.api.nvim_win_get_cursor(0)
|
||
end)
|
||
)
|
||
end)
|
||
|
||
it('supports on_jump() handler', function()
|
||
exec_lua(function()
|
||
_G.jumped = false
|
||
|
||
vim.diagnostic.jump({
|
||
count = 1,
|
||
on_jump = function()
|
||
_G.jumped = true
|
||
end,
|
||
})
|
||
end)
|
||
|
||
retry(nil, nil, function()
|
||
eq(true, exec_lua('return _G.jumped'))
|
||
end)
|
||
end)
|
||
|
||
describe('after inserting text before diagnostic position', function()
|
||
before_each(function()
|
||
api.nvim_buf_set_text(0, 3, 0, 3, 0, { 'new line', 'new ' })
|
||
end)
|
||
|
||
it('finds next diagnostic at a logical location', function()
|
||
eq(
|
||
{ 5, 4 },
|
||
exec_lua(function()
|
||
vim.api.nvim_win_set_cursor(0, { 3, 1 })
|
||
vim.diagnostic.jump({ count = 1 })
|
||
return vim.api.nvim_win_get_cursor(0)
|
||
end)
|
||
)
|
||
end)
|
||
|
||
it('finds previous diagnostic at a logical location', function()
|
||
eq(
|
||
{ 5, 4 },
|
||
exec_lua(function()
|
||
vim.api.nvim_win_set_cursor(0, { 6, 4 })
|
||
vim.diagnostic.jump({ count = -1 })
|
||
return vim.api.nvim_win_get_cursor(0)
|
||
end)
|
||
)
|
||
end)
|
||
end)
|
||
|
||
describe('if diagnostic is set after last character in line', function()
|
||
before_each(function()
|
||
exec_lua(function()
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_error('Diagnostic #1', 2, 3, 3, 4),
|
||
})
|
||
end)
|
||
end)
|
||
|
||
it('finds next diagnostic at the end of the line', function()
|
||
eq(
|
||
{ 3, 2 },
|
||
exec_lua(function()
|
||
vim.api.nvim_win_set_cursor(0, { 3, 0 })
|
||
vim.diagnostic.jump({ count = 1 })
|
||
return vim.api.nvim_win_get_cursor(0)
|
||
end)
|
||
)
|
||
end)
|
||
|
||
it('finds previous diagnostic at the end of the line', function()
|
||
eq(
|
||
{ 3, 2 },
|
||
exec_lua(function()
|
||
vim.api.nvim_win_set_cursor(0, { 4, 2 })
|
||
vim.diagnostic.jump({ count = -1 })
|
||
return vim.api.nvim_win_get_cursor(0)
|
||
end)
|
||
)
|
||
end)
|
||
end)
|
||
|
||
describe('after entire text range with a diagnostic was deleted', function()
|
||
before_each(function()
|
||
api.nvim_buf_set_text(0, 1, 1, 1, 4, {})
|
||
end)
|
||
|
||
it('does not find next diagnostic inside the deleted range', function()
|
||
eq(
|
||
{ 3, 0 },
|
||
exec_lua(function()
|
||
vim.api.nvim_win_set_cursor(0, { 1, 0 })
|
||
vim.diagnostic.jump({ count = 1 })
|
||
return vim.api.nvim_win_get_cursor(0)
|
||
end)
|
||
)
|
||
end)
|
||
|
||
it('does not find previous diagnostic inside the deleted range', function()
|
||
eq(
|
||
{ 1, 0 },
|
||
exec_lua(function()
|
||
vim.api.nvim_win_set_cursor(0, { 3, 0 })
|
||
vim.diagnostic.jump({ count = -1 })
|
||
return vim.api.nvim_win_get_cursor(0)
|
||
end)
|
||
)
|
||
end)
|
||
end)
|
||
end)
|
||
|
||
describe('get()', function()
|
||
it('returns an empty table when no diagnostics are present', function()
|
||
eq(
|
||
{},
|
||
exec_lua [[return vim.diagnostic.get( _G.diagnostic_bufnr, {namespace=diagnostic_ns})]]
|
||
)
|
||
end)
|
||
|
||
it('returns all diagnostics when no severity is supplied', function()
|
||
eq(
|
||
2,
|
||
exec_lua(function()
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_error('Error 1', 1, 1, 1, 5),
|
||
_G.make_warning('Warning on Server 1', 1, 1, 2, 3),
|
||
})
|
||
|
||
return #vim.diagnostic.get(_G.diagnostic_bufnr)
|
||
end)
|
||
)
|
||
end)
|
||
|
||
it('returns only requested diagnostics when severity range is supplied', function()
|
||
eq(
|
||
{ 2, 3, 2 },
|
||
exec_lua(function()
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_error('Error 1', 1, 1, 1, 5),
|
||
_G.make_warning('Warning on Server 1', 1, 1, 2, 3),
|
||
_G.make_info('Ignored information', 1, 1, 2, 3),
|
||
_G.make_hint("Here's a hint", 1, 1, 2, 3),
|
||
})
|
||
|
||
return {
|
||
#vim.diagnostic.get(
|
||
_G.diagnostic_bufnr,
|
||
{ severity = { min = vim.diagnostic.severity.WARN } }
|
||
),
|
||
#vim.diagnostic.get(
|
||
_G.diagnostic_bufnr,
|
||
{ severity = { max = vim.diagnostic.severity.WARN } }
|
||
),
|
||
#vim.diagnostic.get(_G.diagnostic_bufnr, {
|
||
severity = {
|
||
min = vim.diagnostic.severity.INFO,
|
||
max = vim.diagnostic.severity.WARN,
|
||
},
|
||
}),
|
||
}
|
||
end)
|
||
)
|
||
end)
|
||
|
||
it('returns only requested diagnostics when severities are supplied', function()
|
||
eq(
|
||
{ 1, 1, 2 },
|
||
exec_lua(function()
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_error('Error 1', 1, 1, 1, 5),
|
||
_G.make_warning('Warning on Server 1', 1, 1, 2, 3),
|
||
_G.make_info('Ignored information', 1, 1, 2, 3),
|
||
_G.make_hint("Here's a hint", 1, 1, 2, 3),
|
||
})
|
||
|
||
return {
|
||
#vim.diagnostic.get(
|
||
_G.diagnostic_bufnr,
|
||
{ severity = { vim.diagnostic.severity.WARN } }
|
||
),
|
||
#vim.diagnostic.get(
|
||
_G.diagnostic_bufnr,
|
||
{ severity = { vim.diagnostic.severity.ERROR } }
|
||
),
|
||
#vim.diagnostic.get(_G.diagnostic_bufnr, {
|
||
severity = {
|
||
vim.diagnostic.severity.INFO,
|
||
vim.diagnostic.severity.WARN,
|
||
},
|
||
}),
|
||
}
|
||
end)
|
||
)
|
||
end)
|
||
|
||
it('allows filtering by line', function()
|
||
eq(
|
||
2,
|
||
exec_lua(function()
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_error('Error 1', 1, 1, 1, 5),
|
||
_G.make_warning('Warning on Server 1', 1, 1, 2, 3),
|
||
_G.make_info('Ignored information', 1, 1, 2, 3),
|
||
_G.make_error('Error On Other Line', 3, 1, 3, 5),
|
||
})
|
||
|
||
return #vim.diagnostic.get(_G.diagnostic_bufnr, { lnum = 2 })
|
||
end)
|
||
)
|
||
end)
|
||
|
||
it('allows filtering by enablement', function()
|
||
eq(
|
||
{ 3, 1, 2 },
|
||
exec_lua(function()
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_error('Error 1', 1, 1, 1, 5),
|
||
})
|
||
vim.diagnostic.set(_G.other_ns, _G.diagnostic_bufnr, {
|
||
_G.make_error('Error 2', 1, 1, 1, 5),
|
||
_G.make_error('Error 3', 3, 1, 3, 5),
|
||
})
|
||
|
||
vim.diagnostic.enable(false, { ns_id = _G.other_ns })
|
||
|
||
return {
|
||
#vim.diagnostic.get(_G.diagnostic_bufnr),
|
||
#vim.diagnostic.get(_G.diagnostic_bufnr, { enabled = true }),
|
||
#vim.diagnostic.get(_G.diagnostic_bufnr, { enabled = false }),
|
||
}
|
||
end)
|
||
)
|
||
end)
|
||
end)
|
||
|
||
describe('count', function()
|
||
it('returns actually present severity counts', function()
|
||
eq(
|
||
exec_lua(function()
|
||
return {
|
||
[vim.diagnostic.severity.ERROR] = 4,
|
||
[vim.diagnostic.severity.WARN] = 3,
|
||
[vim.diagnostic.severity.INFO] = 2,
|
||
[vim.diagnostic.severity.HINT] = 1,
|
||
}
|
||
end),
|
||
exec_lua(function()
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_error('Error 1', 1, 1, 1, 2),
|
||
_G.make_error('Error 2', 1, 3, 1, 4),
|
||
_G.make_error('Error 3', 1, 5, 1, 6),
|
||
_G.make_error('Error 4', 1, 7, 1, 8),
|
||
_G.make_warning('Warning 1', 2, 1, 2, 2),
|
||
_G.make_warning('Warning 2', 2, 3, 2, 4),
|
||
_G.make_warning('Warning 3', 2, 5, 2, 6),
|
||
_G.make_info('Info 1', 3, 1, 3, 2),
|
||
_G.make_info('Info 2', 3, 3, 3, 4),
|
||
_G.make_hint('Hint 1', 4, 1, 4, 2),
|
||
})
|
||
return vim.diagnostic.count(_G.diagnostic_bufnr)
|
||
end)
|
||
)
|
||
eq(
|
||
exec_lua(function()
|
||
return {
|
||
[vim.diagnostic.severity.ERROR] = 2,
|
||
[vim.diagnostic.severity.INFO] = 1,
|
||
}
|
||
end),
|
||
exec_lua(function()
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_error('Error 1', 1, 1, 1, 2),
|
||
_G.make_error('Error 2', 1, 3, 1, 4),
|
||
_G.make_info('Info 1', 3, 1, 3, 2),
|
||
})
|
||
return vim.diagnostic.count(_G.diagnostic_bufnr)
|
||
end)
|
||
)
|
||
end)
|
||
|
||
it('returns only requested diagnostics count when severity range is supplied', function()
|
||
eq(
|
||
exec_lua(function()
|
||
return {
|
||
{ [vim.diagnostic.severity.ERROR] = 1, [vim.diagnostic.severity.WARN] = 1 },
|
||
{
|
||
[vim.diagnostic.severity.WARN] = 1,
|
||
[vim.diagnostic.severity.INFO] = 1,
|
||
[vim.diagnostic.severity.HINT] = 1,
|
||
},
|
||
{ [vim.diagnostic.severity.WARN] = 1, [vim.diagnostic.severity.INFO] = 1 },
|
||
}
|
||
end),
|
||
exec_lua(function()
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_error('Error 1', 1, 1, 1, 5),
|
||
_G.make_warning('Warning on Server 1', 1, 1, 2, 3),
|
||
_G.make_info('Ignored information', 1, 1, 2, 3),
|
||
_G.make_hint("Here's a hint", 1, 1, 2, 3),
|
||
})
|
||
|
||
return {
|
||
vim.diagnostic.count(
|
||
_G.diagnostic_bufnr,
|
||
{ severity = { min = vim.diagnostic.severity.WARN } }
|
||
),
|
||
vim.diagnostic.count(
|
||
_G.diagnostic_bufnr,
|
||
{ severity = { max = vim.diagnostic.severity.WARN } }
|
||
),
|
||
vim.diagnostic.count(_G.diagnostic_bufnr, {
|
||
severity = {
|
||
min = vim.diagnostic.severity.INFO,
|
||
max = vim.diagnostic.severity.WARN,
|
||
},
|
||
}),
|
||
}
|
||
end)
|
||
)
|
||
end)
|
||
|
||
it('returns only requested diagnostics when severities are supplied', function()
|
||
eq(
|
||
exec_lua(function()
|
||
return {
|
||
{ [vim.diagnostic.severity.WARN] = 1 },
|
||
{ [vim.diagnostic.severity.ERROR] = 1 },
|
||
{ [vim.diagnostic.severity.WARN] = 1, [vim.diagnostic.severity.INFO] = 1 },
|
||
}
|
||
end),
|
||
exec_lua(function()
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_error('Error 1', 1, 1, 1, 5),
|
||
_G.make_warning('Warning on Server 1', 1, 1, 2, 3),
|
||
_G.make_info('Ignored information', 1, 1, 2, 3),
|
||
_G.make_hint("Here's a hint", 1, 1, 2, 3),
|
||
})
|
||
|
||
return {
|
||
vim.diagnostic.count(
|
||
_G.diagnostic_bufnr,
|
||
{ severity = { vim.diagnostic.severity.WARN } }
|
||
),
|
||
vim.diagnostic.count(
|
||
_G.diagnostic_bufnr,
|
||
{ severity = { vim.diagnostic.severity.ERROR } }
|
||
),
|
||
vim.diagnostic.count(_G.diagnostic_bufnr, {
|
||
severity = {
|
||
vim.diagnostic.severity.INFO,
|
||
vim.diagnostic.severity.WARN,
|
||
},
|
||
}),
|
||
}
|
||
end)
|
||
)
|
||
end)
|
||
|
||
it('allows filtering by line', function()
|
||
eq(
|
||
exec_lua(function()
|
||
return {
|
||
[vim.diagnostic.severity.WARN] = 1,
|
||
[vim.diagnostic.severity.INFO] = 1,
|
||
}
|
||
end),
|
||
exec_lua(function()
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_error('Error 1', 1, 1, 1, 5),
|
||
_G.make_warning('Warning on Server 1', 1, 1, 2, 3),
|
||
_G.make_info('Ignored information', 1, 1, 2, 3),
|
||
_G.make_error('Error On Other Line', 3, 1, 3, 5),
|
||
})
|
||
|
||
return vim.diagnostic.count(_G.diagnostic_bufnr, { lnum = 2 })
|
||
end)
|
||
)
|
||
end)
|
||
end)
|
||
|
||
describe('config()', function()
|
||
it('works with global, namespace, and ephemeral options', function()
|
||
eq(
|
||
1,
|
||
exec_lua(function()
|
||
vim.diagnostic.config({
|
||
virtual_text = false,
|
||
})
|
||
|
||
vim.diagnostic.config({
|
||
virtual_text = true,
|
||
underline = false,
|
||
}, _G.diagnostic_ns)
|
||
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_error('Some Error', 4, 4, 4, 4),
|
||
})
|
||
|
||
return _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns)
|
||
end)
|
||
)
|
||
|
||
eq(
|
||
1,
|
||
exec_lua(function()
|
||
vim.diagnostic.config({
|
||
virtual_text = false,
|
||
})
|
||
|
||
vim.diagnostic.config({
|
||
virtual_text = false,
|
||
underline = false,
|
||
}, _G.diagnostic_ns)
|
||
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_error('Some Error', 4, 4, 4, 4),
|
||
}, { virtual_text = true })
|
||
|
||
return _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns)
|
||
end)
|
||
)
|
||
|
||
eq(
|
||
0,
|
||
exec_lua(function()
|
||
vim.diagnostic.config({
|
||
virtual_text = false,
|
||
})
|
||
|
||
vim.diagnostic.config({
|
||
virtual_text = { severity = vim.diagnostic.severity.ERROR },
|
||
underline = false,
|
||
}, _G.diagnostic_ns)
|
||
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_warning('Some Warning', 4, 4, 4, 4),
|
||
}, { virtual_text = true })
|
||
|
||
return _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns)
|
||
end)
|
||
)
|
||
|
||
eq(
|
||
1,
|
||
exec_lua(function()
|
||
vim.diagnostic.config({
|
||
virtual_text = false,
|
||
})
|
||
|
||
vim.diagnostic.config({
|
||
virtual_text = { severity = vim.diagnostic.severity.ERROR },
|
||
underline = false,
|
||
}, _G.diagnostic_ns)
|
||
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_warning('Some Warning', 4, 4, 4, 4),
|
||
}, {
|
||
virtual_text = {}, -- An empty table uses default values
|
||
})
|
||
|
||
return _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns)
|
||
end)
|
||
)
|
||
end)
|
||
|
||
it('can use functions for config values', function()
|
||
exec_lua(function()
|
||
vim.diagnostic.config({
|
||
virtual_text = function()
|
||
return true
|
||
end,
|
||
}, _G.diagnostic_ns)
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_error('Delayed Diagnostic', 4, 4, 4, 4),
|
||
})
|
||
end)
|
||
|
||
eq(
|
||
1,
|
||
exec_lua [[return _G.count_diagnostics( _G.diagnostic_bufnr, vim.diagnostic.severity.ERROR, _G.diagnostic_ns)]]
|
||
)
|
||
eq(2, exec_lua [[return _G.count_extmarks( _G.diagnostic_bufnr, _G.diagnostic_ns)]])
|
||
|
||
-- Now, don't enable virtual text.
|
||
-- We should have one less extmark displayed.
|
||
exec_lua(function()
|
||
vim.diagnostic.config({
|
||
virtual_text = function()
|
||
return false
|
||
end,
|
||
}, _G.diagnostic_ns)
|
||
end)
|
||
|
||
eq(
|
||
1,
|
||
exec_lua [[return _G.count_diagnostics( _G.diagnostic_bufnr, vim.diagnostic.severity.ERROR, _G.diagnostic_ns)]]
|
||
)
|
||
eq(1, exec_lua [[return _G.count_extmarks( _G.diagnostic_bufnr, _G.diagnostic_ns)]])
|
||
end)
|
||
|
||
it('allows filtering by severity', function()
|
||
local get_extmark_count_with_severity = function(min_severity)
|
||
return exec_lua(function()
|
||
vim.diagnostic.config({
|
||
underline = false,
|
||
virtual_text = {
|
||
severity = { min = min_severity },
|
||
},
|
||
})
|
||
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_warning('Delayed Diagnostic', 4, 4, 4, 4),
|
||
})
|
||
|
||
return _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns)
|
||
end)
|
||
end
|
||
|
||
-- No messages with Error or higher
|
||
eq(0, get_extmark_count_with_severity('ERROR'))
|
||
|
||
-- But now we don't filter it
|
||
eq(1, get_extmark_count_with_severity('WARN'))
|
||
eq(1, get_extmark_count_with_severity('HINT'))
|
||
end)
|
||
|
||
it('allows sorting by severity', function()
|
||
exec_lua(function()
|
||
vim.diagnostic.config({
|
||
underline = false,
|
||
signs = true,
|
||
virtual_text = true,
|
||
})
|
||
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_warning('Warning', 4, 4, 4, 4),
|
||
_G.make_error('Error', 4, 4, 4, 4),
|
||
_G.make_info('Info', 4, 4, 4, 4),
|
||
})
|
||
|
||
function _G.get_highest_underline_hl(severity_sort)
|
||
vim.diagnostic.config({
|
||
underline = true,
|
||
severity_sort = severity_sort,
|
||
})
|
||
|
||
local extmarks = _G.get_underline_extmarks(_G.diagnostic_ns)
|
||
|
||
table.sort(extmarks, function(a, b)
|
||
return a[4].priority > b[4].priority
|
||
end)
|
||
|
||
return extmarks[1][4].hl_group
|
||
end
|
||
|
||
function _G.get_virt_text_and_signs(severity_sort)
|
||
vim.diagnostic.config({
|
||
severity_sort = severity_sort,
|
||
})
|
||
|
||
local virt_text = _G.get_virt_text_extmarks(_G.diagnostic_ns)[1][4].virt_text
|
||
|
||
local virt_texts = {}
|
||
for i = 2, #virt_text - 1 do
|
||
table.insert(virt_texts, (string.gsub(virt_text[i][2], 'DiagnosticVirtualText', '')))
|
||
end
|
||
|
||
local ns = vim.diagnostic.get_namespace(_G.diagnostic_ns)
|
||
local sign_ns = ns.user_data.sign_ns
|
||
local signs = {}
|
||
local all_signs = vim.api.nvim_buf_get_extmarks(
|
||
_G.diagnostic_bufnr,
|
||
sign_ns,
|
||
0,
|
||
-1,
|
||
{ type = 'sign', details = true }
|
||
)
|
||
table.sort(all_signs, function(a, b)
|
||
return a[1] > b[1]
|
||
end)
|
||
|
||
for _, v in ipairs(all_signs) do
|
||
local s = v[4].sign_hl_group:gsub('DiagnosticSign', '')
|
||
if not vim.tbl_contains(signs, s) then
|
||
signs[#signs + 1] = s
|
||
end
|
||
end
|
||
|
||
return { virt_texts, signs }
|
||
end
|
||
end)
|
||
|
||
local result = exec_lua [[return _G.get_virt_text_and_signs(false)]]
|
||
|
||
-- Virt texts are defined lowest priority to highest, signs from
|
||
-- highest to lowest
|
||
eq({ 'Warn', 'Error', 'Info' }, result[1])
|
||
eq({ 'Info', 'Error', 'Warn' }, result[2])
|
||
|
||
result = exec_lua [[return _G.get_virt_text_and_signs(true)]]
|
||
eq({ 'Info', 'Warn', 'Error' }, result[1])
|
||
eq({ 'Error', 'Warn', 'Info' }, result[2])
|
||
|
||
result = exec_lua [[return _G.get_virt_text_and_signs({ reverse = true })]]
|
||
eq({ 'Error', 'Warn', 'Info' }, result[1])
|
||
eq({ 'Info', 'Warn', 'Error' }, result[2])
|
||
|
||
local underline_hl = exec_lua [[return _G.get_highest_underline_hl(true)]]
|
||
eq('DiagnosticUnderlineError', underline_hl)
|
||
|
||
underline_hl = exec_lua [[return _G.get_highest_underline_hl({ reverse = true })]]
|
||
eq('DiagnosticUnderlineInfo', underline_hl)
|
||
end)
|
||
|
||
it(
|
||
'shows deprecated and unnecessary highlights in addition to severity-based highlights',
|
||
function()
|
||
local screen = Screen.new(50, 3)
|
||
screen:set_default_attr_ids({
|
||
--- DiagnosticUnderlineError + DiagnosticUnnecessary + DiagnosticDeprecated combined
|
||
[1] = {
|
||
background = Screen.colors.Red1,
|
||
strikethrough = true,
|
||
underline = true,
|
||
special = Screen.colors.Red1,
|
||
bold = true,
|
||
},
|
||
})
|
||
|
||
command('hi DiagnosticUnderlineError guibg=Red gui=underline guisp=Red')
|
||
command('hi DiagnosticUnnecessary gui=bold')
|
||
command('hi DiagnosticDeprecated gui=strikethrough')
|
||
|
||
exec_lua(function()
|
||
vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
|
||
vim.diagnostic.config({
|
||
signs = false,
|
||
})
|
||
|
||
local diagnostic = _G.make_error('Some error', 0, 0, 0, 3, 'source x')
|
||
diagnostic._tags = {
|
||
deprecated = true,
|
||
unnecessary = true,
|
||
}
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { diagnostic })
|
||
end)
|
||
|
||
screen:expect([[
|
||
{1:^1st} line of text |
|
||
2nd line of text |
|
||
|
|
||
]])
|
||
end
|
||
)
|
||
|
||
it('can show diagnostic sources in virtual text', function()
|
||
local result = exec_lua(function()
|
||
local diagnostics = {
|
||
_G.make_error('Some error', 0, 0, 0, 0, 'source x'),
|
||
}
|
||
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics, {
|
||
underline = false,
|
||
virtual_text = {
|
||
prefix = '',
|
||
source = 'always',
|
||
},
|
||
})
|
||
|
||
local extmarks = _G.get_virt_text_extmarks(_G.diagnostic_ns)
|
||
local virt_text = extmarks[1][4].virt_text[3][1]
|
||
return virt_text
|
||
end)
|
||
eq(' source x: Some error', result)
|
||
|
||
result = exec_lua(function()
|
||
vim.diagnostic.config({
|
||
underline = false,
|
||
virtual_text = {
|
||
prefix = '',
|
||
source = 'if_many',
|
||
},
|
||
}, _G.diagnostic_ns)
|
||
|
||
local extmarks = _G.get_virt_text_extmarks(_G.diagnostic_ns)
|
||
local virt_text = extmarks[1][4].virt_text[3][1]
|
||
return virt_text
|
||
end)
|
||
eq(' Some error', result)
|
||
|
||
result = exec_lua(function()
|
||
local diagnostics = {
|
||
_G.make_error('Some error', 0, 0, 0, 0, 'source x'),
|
||
_G.make_error('Another error', 1, 1, 1, 1, 'source y'),
|
||
}
|
||
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics, {
|
||
underline = false,
|
||
virtual_text = {
|
||
prefix = '',
|
||
source = 'if_many',
|
||
},
|
||
})
|
||
|
||
local extmarks = _G.get_virt_text_extmarks(_G.diagnostic_ns)
|
||
local virt_text = { extmarks[1][4].virt_text[3][1], extmarks[2][4].virt_text[3][1] }
|
||
return virt_text
|
||
end)
|
||
eq(' source x: Some error', result[1])
|
||
eq(' source y: Another error', result[2])
|
||
end)
|
||
|
||
it('supports a format function for diagnostic messages', function()
|
||
local result = exec_lua(function()
|
||
vim.diagnostic.config({
|
||
underline = false,
|
||
virtual_text = {
|
||
prefix = '',
|
||
format = function(diagnostic)
|
||
if diagnostic.severity == vim.diagnostic.severity.ERROR then
|
||
return string.format('🔥 %s', diagnostic.message)
|
||
end
|
||
return string.format('👀 %s', diagnostic.message)
|
||
end,
|
||
},
|
||
})
|
||
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_warning('Warning', 0, 0, 0, 0),
|
||
_G.make_error('Error', 1, 0, 1, 0),
|
||
})
|
||
|
||
local extmarks = _G.get_virt_text_extmarks(_G.diagnostic_ns)
|
||
return { extmarks[1][4].virt_text, extmarks[2][4].virt_text }
|
||
end)
|
||
eq(' 👀 Warning', result[1][3][1])
|
||
eq(' 🔥 Error', result[2][3][1])
|
||
end)
|
||
|
||
it('includes source for formatted diagnostics', function()
|
||
local result = exec_lua(function()
|
||
vim.diagnostic.config({
|
||
underline = false,
|
||
virtual_text = {
|
||
prefix = '',
|
||
source = 'always',
|
||
format = function(diagnostic)
|
||
if diagnostic.severity == vim.diagnostic.severity.ERROR then
|
||
return string.format('🔥 %s', diagnostic.message)
|
||
end
|
||
return string.format('👀 %s', diagnostic.message)
|
||
end,
|
||
},
|
||
})
|
||
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_warning('Warning', 0, 0, 0, 0, 'some_linter'),
|
||
_G.make_error('Error', 1, 0, 1, 0, 'another_linter'),
|
||
})
|
||
|
||
local extmarks = _G.get_virt_text_extmarks(_G.diagnostic_ns)
|
||
return { extmarks[1][4].virt_text, extmarks[2][4].virt_text }
|
||
end)
|
||
eq(' some_linter: 👀 Warning', result[1][3][1])
|
||
eq(' another_linter: 🔥 Error', result[2][3][1])
|
||
end)
|
||
|
||
it('can add a prefix to virtual text', function()
|
||
eq(
|
||
'E Some error',
|
||
exec_lua(function()
|
||
local diagnostics = {
|
||
_G.make_error('Some error', 0, 0, 0, 0),
|
||
}
|
||
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics, {
|
||
underline = false,
|
||
virtual_text = {
|
||
prefix = 'E',
|
||
suffix = '',
|
||
},
|
||
})
|
||
|
||
local extmarks = _G.get_virt_text_extmarks(_G.diagnostic_ns)
|
||
local prefix = extmarks[1][4].virt_text[2][1]
|
||
local message = extmarks[1][4].virt_text[3][1]
|
||
return prefix .. message
|
||
end)
|
||
)
|
||
|
||
eq(
|
||
'[(1/1) err-code] Some error',
|
||
exec_lua(function()
|
||
local diagnostics = {
|
||
_G.make_error('Some error', 0, 0, 0, 0, nil, 'err-code'),
|
||
}
|
||
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics, {
|
||
underline = false,
|
||
virtual_text = {
|
||
prefix = function(diag, i, total)
|
||
return string.format('[(%d/%d) %s]', i, total, diag.code)
|
||
end,
|
||
suffix = '',
|
||
},
|
||
})
|
||
|
||
local extmarks = _G.get_virt_text_extmarks(_G.diagnostic_ns)
|
||
local prefix = extmarks[1][4].virt_text[2][1]
|
||
local message = extmarks[1][4].virt_text[3][1]
|
||
return prefix .. message
|
||
end)
|
||
)
|
||
end)
|
||
|
||
it('can add a suffix to virtual text', function()
|
||
eq(
|
||
' Some error ✘',
|
||
exec_lua(function()
|
||
local diagnostics = {
|
||
_G.make_error('Some error', 0, 0, 0, 0),
|
||
}
|
||
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics, {
|
||
underline = false,
|
||
virtual_text = {
|
||
prefix = '',
|
||
suffix = ' ✘',
|
||
},
|
||
})
|
||
|
||
local extmarks = _G.get_virt_text_extmarks(_G.diagnostic_ns)
|
||
local virt_text = extmarks[1][4].virt_text[3][1]
|
||
return virt_text
|
||
end)
|
||
)
|
||
|
||
eq(
|
||
' Some error [err-code]',
|
||
exec_lua(function()
|
||
local diagnostics = {
|
||
_G.make_error('Some error', 0, 0, 0, 0, nil, 'err-code'),
|
||
}
|
||
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics, {
|
||
underline = false,
|
||
virtual_text = {
|
||
prefix = '',
|
||
suffix = function(diag)
|
||
return string.format(' [%s]', diag.code)
|
||
end,
|
||
},
|
||
})
|
||
|
||
local extmarks = _G.get_virt_text_extmarks(_G.diagnostic_ns)
|
||
local virt_text = extmarks[1][4].virt_text[3][1]
|
||
return virt_text
|
||
end)
|
||
)
|
||
end)
|
||
|
||
it('can filter diagnostics by returning nil when formatting', function()
|
||
local result = exec_lua(function()
|
||
vim.diagnostic.config {
|
||
virtual_text = {
|
||
format = function(diagnostic)
|
||
if diagnostic.code == 'foo_err' then
|
||
return nil
|
||
end
|
||
return diagnostic.message
|
||
end,
|
||
},
|
||
}
|
||
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_error('An error here!', 0, 0, 0, 0, 'foo_server', 'foo_err'),
|
||
_G.make_error('An error there!', 1, 1, 1, 1, 'bar_server', 'bar_err'),
|
||
})
|
||
|
||
local extmarks = _G.get_virt_text_extmarks(_G.diagnostic_ns)
|
||
return extmarks
|
||
end)
|
||
|
||
eq(1, #result)
|
||
eq(' An error there!', result[1][4].virt_text[3][1])
|
||
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)
|
||
|
||
it('can hide 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 = false } })
|
||
|
||
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(' Another error there!', result[1][4].virt_text[3][1])
|
||
end)
|
||
|
||
it('only renders virtual_text diagnostics within buffer length', function()
|
||
local result = exec_lua(function()
|
||
vim.api.nvim_win_set_cursor(0, { 1, 0 })
|
||
|
||
vim.diagnostic.config({ virtual_text = { current_line = false } })
|
||
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_error('Hidden Error here!', 0, 0, 0, 0, 'foo_server'),
|
||
_G.make_error('First Error here!', 1, 0, 1, 0, 'foo_server'),
|
||
_G.make_error('Second Error here!', 2, 0, 2, 0, 'foo_server'),
|
||
_G.make_error('First Ignored Error here!', 3, 0, 3, 0, 'foo_server'),
|
||
_G.make_error('Second Ignored Error here!', 6, 0, 6, 0, 'foo_server'),
|
||
_G.make_error('Third Ignored Error here!', 8, 0, 8, 0, 'foo_server'),
|
||
})
|
||
|
||
vim.api.nvim_buf_set_lines(_G.diagnostic_bufnr, 2, 5, false, {})
|
||
vim.api.nvim_exec_autocmds('CursorHold', { buf = _G.diagnostic_bufnr })
|
||
return _G.get_virt_text_extmarks(_G.diagnostic_ns)
|
||
end)
|
||
|
||
eq(2, #result)
|
||
eq(' First Error here!', result[1][4].virt_text[3][1])
|
||
eq(' Second Error here!', result[2][4].virt_text[3][1])
|
||
end)
|
||
end)
|
||
|
||
describe('handlers.virtual_lines', function()
|
||
it('includes diagnostic code and message', function()
|
||
local result = exec_lua(function()
|
||
vim.diagnostic.config({ virtual_lines = true })
|
||
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_error('Missed symbol `,`', 0, 0, 0, 0, 'lua_ls', 'miss-symbol'),
|
||
})
|
||
|
||
local extmarks = _G.get_virt_lines_extmarks(_G.diagnostic_ns)
|
||
return extmarks
|
||
end)
|
||
|
||
eq(1, #result)
|
||
eq('auto', result[1][4].virt_lines_overflow)
|
||
eq('miss-symbol: Missed symbol `,`', result[1][4].virt_lines[1][3][1])
|
||
end)
|
||
|
||
it('adds space to the left of the diagnostic', function()
|
||
local error_offset = 5
|
||
local result = exec_lua(function()
|
||
vim.diagnostic.config({ virtual_lines = true })
|
||
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_error('Error here!', 0, error_offset, 0, error_offset, 'foo_server'),
|
||
})
|
||
|
||
local extmarks = _G.get_virt_lines_extmarks(_G.diagnostic_ns)
|
||
return extmarks[1][4].virt_lines
|
||
end)
|
||
|
||
eq(error_offset, result[1][1][1]:len())
|
||
end)
|
||
|
||
it('highlights diagnostics in multiple lines by default #38685', function()
|
||
local result = exec_lua(function()
|
||
vim.diagnostic.config({ virtual_lines = 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, 3, 0, 'foo_server'),
|
||
})
|
||
|
||
local extmarks = _G.get_virt_lines_extmarks(_G.diagnostic_ns)
|
||
return extmarks
|
||
end)
|
||
|
||
eq(2, #result)
|
||
eq('Error here!', result[1][4].virt_lines[1][3][1])
|
||
eq('Another error there!', result[2][4].virt_lines[1][3][1])
|
||
eq(0, result[1][2])
|
||
eq(3, result[2][2])
|
||
end)
|
||
|
||
it('highlights multiple diagnostics in a single line by default', function()
|
||
local result = exec_lua(function()
|
||
vim.api.nvim_buf_set_lines(
|
||
_G.diagnostic_bufnr,
|
||
0,
|
||
-1,
|
||
false,
|
||
{ 'def foo(x: int, /, y: str, *, z: float) -> None: ...' }
|
||
)
|
||
|
||
vim.diagnostic.config({ virtual_lines = true })
|
||
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_error('Error here!', 0, 8, 0, 9, 'foo_server'),
|
||
_G.make_error('Another error there!', 0, 19, 0, 20, 'foo_server'),
|
||
_G.make_error('And another one!', 0, 30, 0, 31, 'foo_server'),
|
||
})
|
||
|
||
local extmarks = _G.get_virt_lines_extmarks(_G.diagnostic_ns)
|
||
return extmarks
|
||
end)
|
||
|
||
--[[
|
||
|def foo(x: int, /, y: str, *, z: float) -> None: ...
|
||
| │ │ └──── And another one!
|
||
| │ └──── Another error there!
|
||
| └──── Error here!
|
||
| ^ col=8
|
||
| ^ col=19
|
||
| ^ col=30
|
||
|
||
11 cols between each diagnostic after the first one (10 spaces + |)
|
||
]]
|
||
|
||
eq(1, #result)
|
||
local virt_lines = result[1][4].virt_lines
|
||
eq(8, virt_lines[1][1][1]:len()) -- first space
|
||
eq(10, virt_lines[1][3][1]:len()) -- second space
|
||
eq(10, virt_lines[1][5][1]:len()) -- third space
|
||
eq('And another one!', virt_lines[1][7][1])
|
||
eq(8, virt_lines[2][1][1]:len()) -- first space
|
||
eq(10, virt_lines[2][3][1]:len()) -- second space
|
||
eq('Another error there!', virt_lines[2][5][1])
|
||
eq(8, virt_lines[3][1][1]:len()) -- first space
|
||
eq('Error here!', virt_lines[3][3][1])
|
||
end)
|
||
|
||
it('highlights overlapping diagnostics on a single line', function()
|
||
local result = exec_lua(function()
|
||
vim.diagnostic.config({ virtual_lines = true })
|
||
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_error('Error here!', 0, 10, 0, 11, 'foo_server'),
|
||
_G.make_error('Another error here!', 0, 10, 0, 11, 'foo_server'),
|
||
})
|
||
|
||
local extmarks = _G.get_virt_lines_extmarks(_G.diagnostic_ns)
|
||
return extmarks
|
||
end)
|
||
|
||
--[[
|
||
|1234567890x
|
||
| ├──── Another error here!
|
||
| └──── Error here!
|
||
]]
|
||
|
||
eq(1, #result)
|
||
local virt_lines = result[1][4].virt_lines
|
||
eq(10, virt_lines[1][1][1]:len()) -- first space
|
||
eq('├──── ', virt_lines[1][2][1])
|
||
eq('Another error here!', virt_lines[1][3][1])
|
||
eq(10, virt_lines[2][1][1]:len()) -- second space
|
||
eq('└──── ', virt_lines[2][2][1])
|
||
eq('Error here!', virt_lines[2][3][1])
|
||
end)
|
||
|
||
it('handles multi-line diagnostic message', function()
|
||
local result = exec_lua(function()
|
||
vim.diagnostic.config({ virtual_lines = true })
|
||
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_error('Error here!\ngot another line', 0, 10, 0, 11, 'foo_server'),
|
||
})
|
||
|
||
local extmarks = _G.get_virt_lines_extmarks(_G.diagnostic_ns)
|
||
return extmarks
|
||
end)
|
||
|
||
--[[
|
||
|1234567890x
|
||
| └──── Error here!
|
||
| got another line
|
||
]]
|
||
|
||
eq(1, #result)
|
||
local virt_lines = result[1][4].virt_lines
|
||
eq(10, virt_lines[1][1][1]:len()) -- first space
|
||
eq('└──── ', virt_lines[1][2][1])
|
||
eq('Error here!', virt_lines[1][3][1])
|
||
eq(10, virt_lines[2][1][1]:len()) -- second line space
|
||
eq(6, virt_lines[2][2][1]:len()) -- extra padding
|
||
eq('got another line', virt_lines[2][3][1])
|
||
end)
|
||
|
||
it('can highlight diagnostics only in the current line', function()
|
||
local result = exec_lua(function()
|
||
vim.api.nvim_win_set_cursor(0, { 1, 0 })
|
||
|
||
vim.diagnostic.config({ virtual_lines = { 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'),
|
||
})
|
||
|
||
vim.api.nvim_exec_autocmds('CursorHold', { buf = _G.diagnostic_bufnr })
|
||
local extmarks = _G.get_virt_lines_extmarks(_G.diagnostic_ns)
|
||
return extmarks
|
||
end)
|
||
|
||
eq(1, #result)
|
||
eq('Error here!', result[1][4].virt_lines[1][3][1])
|
||
end)
|
||
|
||
it('supports a format function for diagnostic messages', function()
|
||
local result = exec_lua(function()
|
||
vim.diagnostic.config({
|
||
virtual_lines = {
|
||
format = function()
|
||
return 'Error here!'
|
||
end,
|
||
},
|
||
})
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_error('Invalid syntax', 0, 0, 0, 0),
|
||
})
|
||
local extmarks = _G.get_virt_lines_extmarks(_G.diagnostic_ns)
|
||
return extmarks[1][4].virt_lines
|
||
end)
|
||
eq('Error here!', result[1][3][1])
|
||
end)
|
||
|
||
it('sorts by severity with stable tiebreaker #37137', function()
|
||
local result = exec_lua(function()
|
||
vim.diagnostic.config({ severity_sort = true, virtual_lines = { current_line = true } })
|
||
local m = 100
|
||
local diagnostics = {
|
||
{ end_col = m, lnum = 0, message = 'a', severity = 2 },
|
||
{ end_col = m, lnum = 0, message = 'b', severity = 2 },
|
||
{ end_col = m, lnum = 0, message = 'c', severity = 2 },
|
||
{ end_col = m, lnum = 2, message = 'd', severity = 2 },
|
||
{ end_col = m, lnum = 2, message = 'e', severity = 2 },
|
||
{ end_col = m, lnum = 2, message = 'f', severity = 2 },
|
||
}
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics, {})
|
||
vim.diagnostic.show(_G.diagnostic_ns, _G.diagnostic_bufnr)
|
||
vim.api.nvim_win_set_cursor(0, { 1, 0 })
|
||
vim.api.nvim_exec_autocmds('CursorHold', { buf = _G.diagnostic_bufnr })
|
||
local extmarks = _G.get_virt_lines_extmarks(_G.diagnostic_ns)
|
||
local result = {}
|
||
for _, d in ipairs(extmarks[1][4].virt_lines) do
|
||
table.insert(result, d[3][1])
|
||
end
|
||
return result
|
||
end)
|
||
eq({ 'c', 'b', 'a' }, result)
|
||
end)
|
||
end)
|
||
|
||
describe('set()', function()
|
||
it('validation', function()
|
||
matches(
|
||
'expected a list of diagnostics',
|
||
pcall_err(exec_lua, [[vim.diagnostic.set(1, 0, {lnum = 1, col = 2})]])
|
||
)
|
||
end)
|
||
|
||
it('does not accumulate BufRead autocmds for unloaded buffers', function()
|
||
local counts = exec_lua(function()
|
||
local bufnr = vim.fn.bufadd(vim.fn.tempname())
|
||
local function count_autocmds()
|
||
return #vim.api.nvim_get_autocmds({ event = 'BufRead', buffer = bufnr })
|
||
end
|
||
vim.diagnostic.set(_G.diagnostic_ns, bufnr, { _G.make_error('Error 1', 0, 0, 0, 0) })
|
||
local first = count_autocmds()
|
||
for i = 2, 5 do
|
||
vim.diagnostic.set(_G.diagnostic_ns, bufnr, { _G.make_error('Error ' .. i, 0, 0, 0, 0) })
|
||
end
|
||
return { first = first, last = count_autocmds() }
|
||
end)
|
||
eq(counts.first, counts.last)
|
||
end)
|
||
|
||
it('computes positions from the last set() when the buffer loads', function()
|
||
eq(
|
||
{ autocmds = 0, extmarks = { { 2, 1 } } },
|
||
exec_lua(function()
|
||
local path = vim.fn.tempname()
|
||
vim.fn.writefile({ 'one', 'two', 'three' }, path)
|
||
local bufnr = vim.fn.bufadd(path)
|
||
vim.diagnostic.set(_G.diagnostic_ns, bufnr, { _G.make_error('Old', 0, 0, 0, 0) })
|
||
vim.diagnostic.set(_G.diagnostic_ns, bufnr, { _G.make_error('New', 2, 1, 2, 2) })
|
||
vim.fn.bufload(bufnr)
|
||
local location_ns = vim.diagnostic.get_namespace(_G.diagnostic_ns).user_data.location_ns
|
||
local extmarks = {} --- @type [integer, integer][]
|
||
for _, m in ipairs(vim.api.nvim_buf_get_extmarks(bufnr, location_ns, 0, -1, {})) do
|
||
extmarks[#extmarks + 1] = { m[2], m[3] }
|
||
end
|
||
return {
|
||
autocmds = #vim.api.nvim_get_autocmds({ event = 'BufRead', buffer = bufnr }),
|
||
extmarks = extmarks,
|
||
}
|
||
end)
|
||
)
|
||
end)
|
||
|
||
it('can perform updates after insert_leave', function()
|
||
exec_lua(function()
|
||
vim.diagnostic.config({ virtual_text = true })
|
||
vim.api.nvim_set_current_buf(_G.diagnostic_bufnr)
|
||
end)
|
||
|
||
api.nvim_input('o')
|
||
eq({ mode = 'i', blocking = false }, api.nvim_get_mode())
|
||
|
||
-- Save the diagnostics
|
||
exec_lua(function()
|
||
vim.diagnostic.config({
|
||
update_in_insert = false,
|
||
})
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_error('Delayed Diagnostic', 4, 4, 4, 4),
|
||
})
|
||
end)
|
||
|
||
-- No diagnostics displayed yet.
|
||
eq({ mode = 'i', blocking = false }, api.nvim_get_mode())
|
||
eq(
|
||
1,
|
||
exec_lua [[return _G.count_diagnostics( _G.diagnostic_bufnr, vim.diagnostic.severity.ERROR, _G.diagnostic_ns)]]
|
||
)
|
||
eq(0, exec_lua [[return _G.count_extmarks( _G.diagnostic_bufnr, _G.diagnostic_ns)]])
|
||
|
||
api.nvim_input('<esc>')
|
||
eq({ mode = 'n', blocking = false }, api.nvim_get_mode())
|
||
|
||
eq(
|
||
1,
|
||
exec_lua [[return _G.count_diagnostics( _G.diagnostic_bufnr, vim.diagnostic.severity.ERROR, _G.diagnostic_ns)]]
|
||
)
|
||
eq(2, exec_lua [[return _G.count_extmarks( _G.diagnostic_bufnr, _G.diagnostic_ns)]])
|
||
end)
|
||
|
||
it('does not perform updates when not needed', function()
|
||
exec_lua [[vim.api.nvim_set_current_buf( _G.diagnostic_bufnr)]]
|
||
api.nvim_input('o')
|
||
eq({ mode = 'i', blocking = false }, api.nvim_get_mode())
|
||
|
||
-- Save the diagnostics
|
||
exec_lua(function()
|
||
vim.diagnostic.config({
|
||
update_in_insert = false,
|
||
virtual_text = true,
|
||
})
|
||
|
||
_G.DisplayCount = 0
|
||
local set_virtual_text = vim.diagnostic.handlers.virtual_text.show
|
||
vim.diagnostic.handlers.virtual_text.show = function(...)
|
||
_G.DisplayCount = _G.DisplayCount + 1
|
||
return set_virtual_text(...)
|
||
end
|
||
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_error('Delayed Diagnostic', 4, 4, 4, 4),
|
||
})
|
||
end)
|
||
|
||
-- No diagnostics displayed yet.
|
||
eq({ mode = 'i', blocking = false }, api.nvim_get_mode())
|
||
eq(
|
||
1,
|
||
exec_lua [[return _G.count_diagnostics( _G.diagnostic_bufnr, vim.diagnostic.severity.ERROR, _G.diagnostic_ns)]]
|
||
)
|
||
eq(0, exec_lua [[return _G.count_extmarks( _G.diagnostic_bufnr, _G.diagnostic_ns)]])
|
||
eq(0, exec_lua [[return _G.DisplayCount]])
|
||
|
||
api.nvim_input('<esc>')
|
||
eq({ mode = 'n', blocking = false }, api.nvim_get_mode())
|
||
|
||
eq(
|
||
1,
|
||
exec_lua [[return _G.count_diagnostics( _G.diagnostic_bufnr, vim.diagnostic.severity.ERROR, _G.diagnostic_ns)]]
|
||
)
|
||
eq(2, exec_lua [[return _G.count_extmarks( _G.diagnostic_bufnr, _G.diagnostic_ns)]])
|
||
eq(1, exec_lua [[return _G.DisplayCount]])
|
||
|
||
-- Go in and out of insert mode one more time.
|
||
api.nvim_input('o')
|
||
eq({ mode = 'i', blocking = false }, api.nvim_get_mode())
|
||
|
||
api.nvim_input('<esc>')
|
||
eq({ mode = 'n', blocking = false }, api.nvim_get_mode())
|
||
|
||
-- Should not have set the virtual text again.
|
||
eq(1, exec_lua [[return _G.DisplayCount]])
|
||
end)
|
||
|
||
it('never sets virtual text, in combination with insert leave', function()
|
||
exec_lua [[vim.api.nvim_set_current_buf( _G.diagnostic_bufnr)]]
|
||
api.nvim_input('o')
|
||
eq({ mode = 'i', blocking = false }, api.nvim_get_mode())
|
||
|
||
-- Save the diagnostics
|
||
exec_lua(function()
|
||
vim.diagnostic.config({
|
||
update_in_insert = false,
|
||
virtual_text = false,
|
||
})
|
||
|
||
_G.DisplayCount = 0
|
||
local set_virtual_text = vim.diagnostic.handlers.virtual_text.show
|
||
vim.diagnostic.handlers.virtual_text.show = function(...)
|
||
_G.DisplayCount = _G.DisplayCount + 1
|
||
return set_virtual_text(...)
|
||
end
|
||
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_error('Delayed Diagnostic', 4, 4, 4, 4),
|
||
})
|
||
end)
|
||
|
||
-- No diagnostics displayed yet.
|
||
eq({ mode = 'i', blocking = false }, api.nvim_get_mode())
|
||
eq(
|
||
1,
|
||
exec_lua [[return _G.count_diagnostics( _G.diagnostic_bufnr, vim.diagnostic.severity.ERROR, _G.diagnostic_ns)]]
|
||
)
|
||
eq(0, exec_lua [[return _G.count_extmarks( _G.diagnostic_bufnr, _G.diagnostic_ns)]])
|
||
eq(0, exec_lua [[return _G.DisplayCount]])
|
||
|
||
api.nvim_input('<esc>')
|
||
eq({ mode = 'n', blocking = false }, api.nvim_get_mode())
|
||
|
||
eq(
|
||
1,
|
||
exec_lua [[return _G.count_diagnostics( _G.diagnostic_bufnr, vim.diagnostic.severity.ERROR, _G.diagnostic_ns)]]
|
||
)
|
||
eq(1, exec_lua [[return _G.count_extmarks( _G.diagnostic_bufnr, _G.diagnostic_ns)]])
|
||
eq(0, exec_lua [[return _G.DisplayCount]])
|
||
|
||
-- Go in and out of insert mode one more time.
|
||
api.nvim_input('o')
|
||
eq({ mode = 'i', blocking = false }, api.nvim_get_mode())
|
||
|
||
api.nvim_input('<esc>')
|
||
eq({ mode = 'n', blocking = false }, api.nvim_get_mode())
|
||
|
||
-- Should not have set the virtual text still.
|
||
eq(0, exec_lua [[return _G.DisplayCount]])
|
||
end)
|
||
|
||
it('can perform updates while in insert mode, if desired', function()
|
||
exec_lua(function()
|
||
vim.diagnostic.config({ virtual_text = true })
|
||
vim.api.nvim_set_current_buf(_G.diagnostic_bufnr)
|
||
end)
|
||
api.nvim_input('o')
|
||
eq({ mode = 'i', blocking = false }, api.nvim_get_mode())
|
||
|
||
-- Save the diagnostics
|
||
exec_lua(function()
|
||
vim.diagnostic.config({
|
||
update_in_insert = true,
|
||
})
|
||
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_error('Delayed Diagnostic', 4, 4, 4, 4),
|
||
})
|
||
end)
|
||
|
||
-- Diagnostics are displayed, because the user wanted them that way!
|
||
eq({ mode = 'i', blocking = false }, api.nvim_get_mode())
|
||
eq(
|
||
1,
|
||
exec_lua [[return _G.count_diagnostics( _G.diagnostic_bufnr, vim.diagnostic.severity.ERROR, _G.diagnostic_ns)]]
|
||
)
|
||
eq(2, exec_lua [[return _G.count_extmarks( _G.diagnostic_bufnr, _G.diagnostic_ns)]])
|
||
|
||
api.nvim_input('<esc>')
|
||
eq({ mode = 'n', blocking = false }, api.nvim_get_mode())
|
||
|
||
eq(
|
||
1,
|
||
exec_lua [[return _G.count_diagnostics( _G.diagnostic_bufnr, vim.diagnostic.severity.ERROR, _G.diagnostic_ns)]]
|
||
)
|
||
eq(2, exec_lua [[return _G.count_extmarks( _G.diagnostic_bufnr, _G.diagnostic_ns)]])
|
||
end)
|
||
|
||
it('can set diagnostics without displaying them', function()
|
||
exec_lua(function()
|
||
vim.diagnostic.config({ virtual_text = true })
|
||
end)
|
||
|
||
eq(
|
||
0,
|
||
exec_lua(function()
|
||
vim.diagnostic.enable(false, { bufnr = _G.diagnostic_bufnr, ns_id = _G.diagnostic_ns })
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_error('Diagnostic From Server 1:1', 1, 1, 1, 1),
|
||
})
|
||
return _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns)
|
||
end)
|
||
)
|
||
|
||
eq(
|
||
2,
|
||
exec_lua(function()
|
||
vim.diagnostic.enable(true, { bufnr = _G.diagnostic_bufnr, ns_id = _G.diagnostic_ns })
|
||
return _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns)
|
||
end)
|
||
)
|
||
end)
|
||
|
||
it('can set display options', function()
|
||
eq(
|
||
0,
|
||
exec_lua(function()
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_error('Diagnostic From Server 1:1', 1, 1, 1, 1),
|
||
}, { virtual_text = false, underline = false })
|
||
return _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns)
|
||
end)
|
||
)
|
||
|
||
eq(
|
||
1,
|
||
exec_lua(function()
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_error('Diagnostic From Server 1:1', 1, 1, 1, 1),
|
||
}, { virtual_text = true, underline = false })
|
||
return _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns)
|
||
end)
|
||
)
|
||
end)
|
||
|
||
it('sets and clears signs #26193 #26555', function()
|
||
do
|
||
local result = exec_lua(function()
|
||
vim.diagnostic.config({
|
||
signs = true,
|
||
})
|
||
|
||
local diagnostics = {
|
||
_G.make_error('Error', 1, 1, 1, 2),
|
||
_G.make_warning('Warning', 3, 3, 3, 3),
|
||
}
|
||
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics)
|
||
|
||
local ns = vim.diagnostic.get_namespace(_G.diagnostic_ns)
|
||
local sign_ns = ns.user_data.sign_ns
|
||
|
||
local signs = vim.api.nvim_buf_get_extmarks(
|
||
_G.diagnostic_bufnr,
|
||
sign_ns,
|
||
0,
|
||
-1,
|
||
{ type = 'sign', details = true }
|
||
)
|
||
local result = {}
|
||
for _, s in ipairs(signs) do
|
||
result[#result + 1] = { lnum = s[2] + 1, name = s[4].sign_hl_group }
|
||
end
|
||
return result
|
||
end)
|
||
|
||
eq({ 2, 'DiagnosticSignError' }, { result[1].lnum, result[1].name })
|
||
eq({ 4, 'DiagnosticSignWarn' }, { result[2].lnum, result[2].name })
|
||
end
|
||
|
||
do
|
||
local result = exec_lua(function()
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {})
|
||
|
||
local ns = vim.diagnostic.get_namespace(_G.diagnostic_ns)
|
||
local sign_ns = ns.user_data.sign_ns
|
||
|
||
return vim.api.nvim_buf_get_extmarks(
|
||
_G.diagnostic_bufnr,
|
||
sign_ns,
|
||
0,
|
||
-1,
|
||
{ type = 'sign', details = true }
|
||
)
|
||
end)
|
||
|
||
eq({}, result)
|
||
end
|
||
end)
|
||
|
||
it('always passes a table to DiagnosticChanged autocommand', function()
|
||
local result = exec_lua(function()
|
||
local changed_diags --- @type vim.Diagnostic[]?
|
||
vim.api.nvim_create_autocmd('DiagnosticChanged', {
|
||
buf = _G.diagnostic_bufnr,
|
||
callback = function(ev)
|
||
--- @type vim.Diagnostic[]
|
||
changed_diags = ev.data.diagnostics
|
||
end,
|
||
})
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {})
|
||
return changed_diags
|
||
end)
|
||
eq('table', type(result))
|
||
eq(0, #result)
|
||
end)
|
||
end)
|
||
|
||
describe('open_float()', function()
|
||
it('can display a header', function()
|
||
eq(
|
||
{ 'Diagnostics:', '1. Syntax error' },
|
||
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()
|
||
local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
|
||
vim.api.nvim_win_close(winnr, true)
|
||
return lines
|
||
end)
|
||
)
|
||
|
||
eq(
|
||
{ "We're no strangers to love...", '1. Syntax error' },
|
||
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({ header = "We're no strangers to love..." })
|
||
local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
|
||
vim.api.nvim_win_close(winnr, true)
|
||
return lines
|
||
end)
|
||
)
|
||
|
||
eq(
|
||
{ 'You know the rules', '1. Syntax error' },
|
||
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({ header = { 'You know the rules', 'Search' } })
|
||
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('can show diagnostics from the whole buffer', function()
|
||
eq(
|
||
{ '1. Syntax error', '2. Some warning' },
|
||
exec_lua(function()
|
||
local diagnostics = {
|
||
_G.make_error('Syntax error', 0, 1, 0, 3),
|
||
_G.make_warning('Some warning', 1, 1, 1, 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({ header = false, scope = 'buffer' })
|
||
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('can show diagnostics from a single line', function()
|
||
-- Using cursor position
|
||
eq(
|
||
{ '1. Some warning' },
|
||
exec_lua(function()
|
||
local diagnostics = {
|
||
_G.make_error('Syntax error', 0, 1, 0, 3),
|
||
_G.make_warning('Some warning', 1, 1, 1, 3),
|
||
}
|
||
vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics)
|
||
vim.api.nvim_win_set_cursor(0, { 2, 1 })
|
||
local float_bufnr, winnr = vim.diagnostic.open_float({ 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)
|
||
)
|
||
|
||
-- With specified position
|
||
eq(
|
||
{ '1. Some warning' },
|
||
exec_lua(function()
|
||
local diagnostics = {
|
||
_G.make_error('Syntax error', 0, 1, 0, 3),
|
||
_G.make_warning('Some warning', 1, 1, 1, 3),
|
||
}
|
||
vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics)
|
||
vim.api.nvim_win_set_cursor(0, { 1, 1 })
|
||
local float_bufnr, winnr = vim.diagnostic.open_float({ header = false, pos = 1 })
|
||
local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
|
||
vim.api.nvim_win_close(winnr, true)
|
||
return lines
|
||
end)
|
||
)
|
||
|
||
-- End position is exclusive
|
||
eq(
|
||
nil,
|
||
exec_lua(function()
|
||
local diagnostics = {
|
||
_G.make_error('Syntax error', 1, 1, 2, 0),
|
||
}
|
||
vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics)
|
||
vim.api.nvim_win_set_cursor(0, { 1, 1 })
|
||
local _, winnr = vim.diagnostic.open_float(0, { header = false, pos = { 2, 0 } })
|
||
return winnr
|
||
end)
|
||
)
|
||
|
||
-- Works when width == 0
|
||
eq(
|
||
{ '1. Syntax error' },
|
||
exec_lua(function()
|
||
local diagnostics = {
|
||
_G.make_error('Syntax error', 2, 0, 2, 0),
|
||
}
|
||
vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics)
|
||
vim.api.nvim_win_set_cursor(0, { 1, 1 })
|
||
local float_bufnr, winnr =
|
||
vim.diagnostic.open_float(0, { header = false, pos = { 2, 1 } })
|
||
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('can show diagnostics from a specific position', function()
|
||
-- Using cursor position
|
||
eq(
|
||
{ 'Syntax error' },
|
||
exec_lua(function()
|
||
local diagnostics = {
|
||
_G.make_error('Syntax error', 1, 1, 1, 3),
|
||
_G.make_warning('Some warning', 1, 3, 1, 4),
|
||
}
|
||
vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics)
|
||
vim.api.nvim_win_set_cursor(0, { 2, 2 })
|
||
local float_bufnr, winnr = vim.diagnostic.open_float({ header = false, scope = 'cursor' })
|
||
local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
|
||
vim.api.nvim_win_close(winnr, true)
|
||
return lines
|
||
end)
|
||
)
|
||
|
||
-- With specified position
|
||
eq(
|
||
{ 'Some warning' },
|
||
exec_lua(function()
|
||
local diagnostics = {
|
||
_G.make_error('Syntax error', 1, 1, 1, 3),
|
||
_G.make_warning('Some warning', 1, 3, 1, 4),
|
||
}
|
||
vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics)
|
||
vim.api.nvim_win_set_cursor(0, { 1, 1 })
|
||
local float_bufnr, winnr =
|
||
vim.diagnostic.open_float({ header = false, scope = 'cursor', pos = { 1, 3 } })
|
||
local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
|
||
vim.api.nvim_win_close(winnr, true)
|
||
return lines
|
||
end)
|
||
)
|
||
|
||
-- With column position past the end of the line. #16062
|
||
eq(
|
||
{ 'Syntax error' },
|
||
exec_lua(function()
|
||
local first_line_len = #vim.api.nvim_buf_get_lines(_G.diagnostic_bufnr, 0, 1, true)[1]
|
||
local diagnostics = {
|
||
_G.make_error('Syntax error', 0, first_line_len + 1, 1, 0),
|
||
}
|
||
vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics)
|
||
vim.api.nvim_win_set_cursor(0, { 1, 1 })
|
||
local float_bufnr, winnr = vim.diagnostic.open_float({
|
||
header = false,
|
||
scope = 'cursor',
|
||
pos = { 0, first_line_len - 1 },
|
||
})
|
||
local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
|
||
vim.api.nvim_win_close(winnr, true)
|
||
return lines
|
||
end)
|
||
)
|
||
|
||
-- End position is exclusive
|
||
eq(
|
||
nil,
|
||
exec_lua(function()
|
||
local diagnostics = {
|
||
_G.make_error('Syntax error', 1, 1, 1, 3),
|
||
}
|
||
vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics)
|
||
vim.api.nvim_win_set_cursor(0, { 1, 1 })
|
||
local _, winnr =
|
||
vim.diagnostic.open_float(0, { header = false, scope = 'cursor', pos = { 1, 3 } })
|
||
return winnr
|
||
end)
|
||
)
|
||
|
||
-- Works when width == 0
|
||
eq(
|
||
{ 'Syntax error' },
|
||
exec_lua(function()
|
||
local diagnostics = {
|
||
_G.make_error('Syntax error', 2, 0, 2, 0),
|
||
}
|
||
vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics)
|
||
vim.api.nvim_win_set_cursor(0, { 1, 1 })
|
||
local float_bufnr, winnr =
|
||
vim.diagnostic.open_float({ header = false, scope = 'cursor', pos = { 2, 0 } })
|
||
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 and returns float bufnr and winnr if current line contains diagnostics',
|
||
function()
|
||
-- Two lines:
|
||
-- Diagnostic:
|
||
-- 1. <msg>
|
||
eq(
|
||
2,
|
||
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)
|
||
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('only reports diagnostics from the current buffer when bufnr is omitted #15710', function()
|
||
eq(
|
||
2,
|
||
exec_lua(function()
|
||
local other_bufnr = vim.api.nvim_create_buf(true, false)
|
||
local buf_1_diagnostics = {
|
||
_G.make_error('Syntax error', 0, 1, 0, 3),
|
||
}
|
||
local buf_2_diagnostics = {
|
||
_G.make_warning('Some warning', 0, 1, 0, 3),
|
||
}
|
||
vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, buf_1_diagnostics)
|
||
vim.diagnostic.set(_G.other_ns, other_bufnr, buf_2_diagnostics)
|
||
local float_bufnr, winnr = vim.diagnostic.open_float()
|
||
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('allows filtering by namespace', function()
|
||
eq(
|
||
{ 'Diagnostics:', '1. Syntax error' },
|
||
exec_lua(function()
|
||
local ns_1_diagnostics = {
|
||
_G.make_error('Syntax error', 0, 1, 0, 3),
|
||
}
|
||
local ns_2_diagnostics = {
|
||
_G.make_warning('Some warning', 0, 1, 0, 3),
|
||
}
|
||
vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, ns_1_diagnostics)
|
||
vim.diagnostic.set(_G.other_ns, _G.diagnostic_bufnr, ns_2_diagnostics)
|
||
local float_bufnr, winnr =
|
||
vim.diagnostic.open_float(_G.diagnostic_bufnr, { namespace = _G.diagnostic_ns })
|
||
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('allows filtering by multiple namespaces', function()
|
||
eq(
|
||
{ 'Diagnostics:', '1. Syntax error', '2. Some warning' },
|
||
exec_lua(function()
|
||
local ns_1_diagnostics = {
|
||
_G.make_error('Syntax error', 0, 1, 0, 3),
|
||
}
|
||
local ns_2_diagnostics = {
|
||
_G.make_warning('Some warning', 0, 1, 0, 3),
|
||
}
|
||
vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, ns_1_diagnostics)
|
||
vim.diagnostic.set(_G.other_ns, _G.diagnostic_bufnr, ns_2_diagnostics)
|
||
local float_bufnr, winnr = vim.diagnostic.open_float(
|
||
_G.diagnostic_bufnr,
|
||
{ namespace = { _G.diagnostic_ns, _G.other_ns } }
|
||
)
|
||
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. <msg>
|
||
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(
|
||
1,
|
||
exec_lua(function()
|
||
local diagnostics = {
|
||
_G.make_error('Syntax error', 6, 0, 6, 0),
|
||
}
|
||
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, pos = 5 })
|
||
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('can show diagnostic source', function()
|
||
exec_lua [[vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)]]
|
||
|
||
eq(
|
||
{ '1. Syntax error' },
|
||
exec_lua(function()
|
||
local diagnostics = {
|
||
_G.make_error('Syntax error', 0, 1, 0, 3, 'source x'),
|
||
}
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics)
|
||
local float_bufnr, winnr = vim.diagnostic.open_float(_G.diagnostic_bufnr, {
|
||
header = false,
|
||
source = 'if_many',
|
||
})
|
||
local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
|
||
vim.api.nvim_win_close(winnr, true)
|
||
return lines
|
||
end)
|
||
)
|
||
|
||
eq(
|
||
{ '1. source x: Syntax error' },
|
||
exec_lua(function()
|
||
local float_bufnr, winnr = vim.diagnostic.open_float(_G.diagnostic_bufnr, {
|
||
header = false,
|
||
source = 'always',
|
||
})
|
||
local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
|
||
vim.api.nvim_win_close(winnr, true)
|
||
return lines
|
||
end)
|
||
)
|
||
|
||
eq(
|
||
{ '1. source x: Syntax error', '2. source y: Another error' },
|
||
exec_lua(function()
|
||
local diagnostics = {
|
||
_G.make_error('Syntax error', 0, 1, 0, 3, 'source x'),
|
||
_G.make_error('Another error', 0, 1, 0, 3, 'source y'),
|
||
}
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics)
|
||
local float_bufnr, winnr = vim.diagnostic.open_float(_G.diagnostic_bufnr, {
|
||
header = false,
|
||
source = 'if_many',
|
||
})
|
||
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('respects severity_sort', function()
|
||
exec_lua [[vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)]]
|
||
|
||
eq(
|
||
{ '1. Syntax error', '2. Info', '3. Error', '4. Warning' },
|
||
exec_lua(function()
|
||
local diagnostics = {
|
||
_G.make_error('Syntax error', 0, 1, 0, 3),
|
||
_G.make_info('Info', 0, 3, 0, 4),
|
||
_G.make_error('Error', 0, 2, 0, 2),
|
||
_G.make_warning('Warning', 0, 0, 0, 1),
|
||
}
|
||
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics)
|
||
|
||
vim.diagnostic.config({ severity_sort = false })
|
||
|
||
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)
|
||
)
|
||
|
||
eq(
|
||
{ '1. Syntax error', '2. Error', '3. Warning', '4. Info' },
|
||
exec_lua(function()
|
||
vim.diagnostic.config({ severity_sort = true })
|
||
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)
|
||
)
|
||
|
||
eq(
|
||
{ '1. Info', '2. Warning', '3. Error', '4. Syntax error' },
|
||
exec_lua(function()
|
||
vim.diagnostic.config({ severity_sort = { reverse = true } })
|
||
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('can filter by severity', function()
|
||
local count_diagnostics_with_severity = function(min_severity, max_severity)
|
||
return exec_lua(function()
|
||
vim.diagnostic.config({
|
||
float = {
|
||
severity = { min = min_severity, max = max_severity },
|
||
},
|
||
})
|
||
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_error('Syntax error', 0, 1, 0, 3),
|
||
_G.make_info('Info', 0, 3, 0, 4),
|
||
_G.make_error('Error', 0, 2, 0, 2),
|
||
_G.make_warning('Warning', 0, 0, 0, 1),
|
||
})
|
||
|
||
local float_bufnr, winnr =
|
||
vim.diagnostic.open_float(_G.diagnostic_bufnr, { header = false })
|
||
if not float_bufnr then
|
||
return 0
|
||
end
|
||
|
||
local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
|
||
vim.api.nvim_win_close(winnr, true)
|
||
return #lines
|
||
end)
|
||
end
|
||
|
||
eq(2, count_diagnostics_with_severity('ERROR'))
|
||
eq(3, count_diagnostics_with_severity('WARN'))
|
||
eq(1, count_diagnostics_with_severity('WARN', 'WARN'))
|
||
eq(4, count_diagnostics_with_severity('HINT'))
|
||
eq(0, count_diagnostics_with_severity('HINT', 'HINT'))
|
||
end)
|
||
|
||
it('can add a prefix to diagnostics', function()
|
||
-- Default is to add a number
|
||
eq(
|
||
{ '1. Syntax error', '2. Some warning' },
|
||
exec_lua(function()
|
||
local diagnostics = {
|
||
_G.make_error('Syntax error', 0, 1, 0, 3),
|
||
_G.make_warning('Some warning', 1, 1, 1, 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({ header = false, scope = 'buffer' })
|
||
local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
|
||
vim.api.nvim_win_close(winnr, true)
|
||
return lines
|
||
end)
|
||
)
|
||
|
||
eq(
|
||
{ 'Syntax error', 'Some warning' },
|
||
exec_lua(function()
|
||
local diagnostics = {
|
||
_G.make_error('Syntax error', 0, 1, 0, 3),
|
||
_G.make_warning('Some warning', 1, 1, 1, 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({ header = false, scope = 'buffer', prefix = '' })
|
||
local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
|
||
vim.api.nvim_win_close(winnr, true)
|
||
return lines
|
||
end)
|
||
)
|
||
|
||
eq(
|
||
{ '1. Syntax error', '2. Some warning' },
|
||
exec_lua(function()
|
||
local diagnostics = {
|
||
_G.make_error('Syntax error', 0, 1, 0, 3),
|
||
_G.make_warning('Some warning', 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({
|
||
header = false,
|
||
prefix = function(_, i, total)
|
||
-- Only show a number if there is more than one diagnostic
|
||
if total > 1 then
|
||
return string.format('%d. ', i)
|
||
end
|
||
return ''
|
||
end,
|
||
})
|
||
local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
|
||
vim.api.nvim_win_close(winnr, true)
|
||
return lines
|
||
end)
|
||
)
|
||
|
||
eq(
|
||
{ 'Syntax error' },
|
||
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({
|
||
header = false,
|
||
prefix = function(_, i, total)
|
||
-- Only show a number if there is more than one diagnostic
|
||
if total > 1 then
|
||
return string.format('%d. ', i)
|
||
end
|
||
return ''
|
||
end,
|
||
})
|
||
local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
|
||
vim.api.nvim_win_close(winnr, true)
|
||
return lines
|
||
end)
|
||
)
|
||
|
||
eq(
|
||
'.../_float.lua:0: prefix: expected string|table|function, got number',
|
||
pcall_err(exec_lua, [[ vim.diagnostic.open_float({ prefix = 42 }) ]])
|
||
)
|
||
end)
|
||
|
||
it('can add a suffix to diagnostics', function()
|
||
-- Default is to render the diagnostic error code
|
||
eq(
|
||
{ '1. Syntax error [code-x]', '2. Some warning [code-y]' },
|
||
exec_lua(function()
|
||
local diagnostics = {
|
||
_G.make_error('Syntax error', 0, 1, 0, 3, nil, 'code-x'),
|
||
_G.make_warning('Some warning', 1, 1, 1, 3, nil, 'code-y'),
|
||
}
|
||
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({ header = false, scope = 'buffer' })
|
||
local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
|
||
vim.api.nvim_win_close(winnr, true)
|
||
return lines
|
||
end)
|
||
)
|
||
|
||
eq(
|
||
{ '1. Syntax error', '2. Some warning' },
|
||
exec_lua(function()
|
||
local diagnostics = {
|
||
_G.make_error('Syntax error', 0, 1, 0, 3, nil, 'code-x'),
|
||
_G.make_warning('Some warning', 1, 1, 1, 3, nil, 'code-y'),
|
||
}
|
||
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({ header = false, scope = 'buffer', suffix = '' })
|
||
local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
|
||
vim.api.nvim_win_close(winnr, true)
|
||
return lines
|
||
end)
|
||
)
|
||
|
||
-- Suffix is rendered on the last line of a multiline diagnostic
|
||
eq(
|
||
{ '1. Syntax error', ' More context [code-x]' },
|
||
exec_lua(function()
|
||
local diagnostics = {
|
||
_G.make_error('Syntax error\nMore context', 0, 1, 0, 3, nil, 'code-x'),
|
||
}
|
||
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({ header = false, scope = 'buffer' })
|
||
local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
|
||
vim.api.nvim_win_close(winnr, true)
|
||
return lines
|
||
end)
|
||
)
|
||
|
||
eq(
|
||
'.../_float.lua:0: suffix: expected string|table|function, got number',
|
||
pcall_err(exec_lua, [[ vim.diagnostic.open_float({ suffix = 42 }) ]])
|
||
)
|
||
end)
|
||
|
||
it('can add LSP related information to a diagnostic', function()
|
||
local related_info_uri = 'file:///fake/uri'
|
||
|
||
-- Populate the related info buffer.
|
||
exec_lua(function()
|
||
local fake_bufnr = vim.uri_to_bufnr(related_info_uri)
|
||
vim.fn.bufload(fake_bufnr)
|
||
vim.api.nvim_buf_set_lines(fake_bufnr, 0, 1, false, {
|
||
'O, the Pelican,',
|
||
'so smoothly doth he crest.',
|
||
'a wind god!',
|
||
})
|
||
vim.api.nvim_win_set_buf(0, fake_bufnr)
|
||
end)
|
||
|
||
-- Displays related info.
|
||
eq(
|
||
{
|
||
'1. Some warning',
|
||
' uri:2:1: Some extra info',
|
||
' uri:3:4: Some more extra info',
|
||
},
|
||
exec_lua(function()
|
||
---@type vim.Diagnostic
|
||
local diagnostic = _G.make_warning('Some warning', 1, 1, 1, 3)
|
||
diagnostic.user_data = {
|
||
-- Related information comes from LSP user_data
|
||
lsp = {
|
||
relatedInformation = {
|
||
{
|
||
message = 'Some extra info',
|
||
location = {
|
||
uri = related_info_uri,
|
||
range = {
|
||
start = {
|
||
line = 1,
|
||
character = 0,
|
||
},
|
||
['end'] = {
|
||
line = 1,
|
||
character = 1,
|
||
},
|
||
},
|
||
},
|
||
},
|
||
{
|
||
message = 'Some more extra info',
|
||
location = {
|
||
uri = related_info_uri,
|
||
range = {
|
||
start = {
|
||
line = 2,
|
||
character = 3,
|
||
},
|
||
['end'] = {
|
||
line = 4,
|
||
character = 5,
|
||
},
|
||
},
|
||
},
|
||
},
|
||
},
|
||
},
|
||
}
|
||
vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { diagnostic })
|
||
local float_bufnr, winnr = vim.diagnostic.open_float({ header = false, scope = 'buffer' })
|
||
local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
|
||
-- Put the cursor on a line with related info
|
||
vim.api.nvim_tabpage_set_win(0, winnr)
|
||
vim.api.nvim_win_set_cursor(0, { 2, 0 })
|
||
return lines
|
||
end)
|
||
)
|
||
|
||
-- Jumps to related info.
|
||
eq(
|
||
'so smoothly doth he crest.',
|
||
exec_lua(function()
|
||
vim.cmd.norm('gf')
|
||
vim.wait(20, function() end)
|
||
return vim.api.nvim_get_current_line()
|
||
end)
|
||
)
|
||
end)
|
||
|
||
it('errors when LSP relatedInformation is null', function()
|
||
matches(
|
||
'server response has invalid %(null%) relatedInformation',
|
||
pcall_err(
|
||
exec_lua,
|
||
[[
|
||
local diagnostic = _G.make_warning('Some warning', 1, 1, 1, 3)
|
||
diagnostic.user_data = { lsp = { relatedInformation = vim.NIL } }
|
||
vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { diagnostic })
|
||
vim.diagnostic.open_float({ header = false, scope = 'buffer' })
|
||
]]
|
||
)
|
||
)
|
||
end)
|
||
|
||
it('works with the old signature', function()
|
||
eq(
|
||
{ '1. Syntax error' },
|
||
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(0, { 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('works for multi-line diagnostics #21949', function()
|
||
-- create diagnostic
|
||
exec_lua(function()
|
||
local diagnostics = {
|
||
_G.make_error('Error in two lines lnum is 1 and end_lnum is 2', 1, 1, 2, 3),
|
||
}
|
||
vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics)
|
||
end)
|
||
|
||
-- open float failed non diagnostic lnum
|
||
eq(
|
||
nil,
|
||
exec_lua(function()
|
||
vim.api.nvim_win_set_cursor(0, { 1, 0 })
|
||
local _, winnr = vim.diagnostic.open_float(0, { header = false })
|
||
return winnr
|
||
end)
|
||
)
|
||
eq(
|
||
nil,
|
||
exec_lua(function()
|
||
vim.api.nvim_win_set_cursor(0, { 1, 0 })
|
||
local _, winnr = vim.diagnostic.open_float(0, { header = false, scope = 'cursor' })
|
||
return winnr
|
||
end)
|
||
)
|
||
|
||
-- can open a float window on lnum 1
|
||
eq(
|
||
{ '1. Error in two lines lnum is 1 and end_lnum is 2' },
|
||
exec_lua(function()
|
||
vim.api.nvim_win_set_cursor(0, { 2, 0 })
|
||
local float_bufnr, winnr = vim.diagnostic.open_float(0, { 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)
|
||
)
|
||
|
||
-- can open a cursor-scoped float window on lnum 1
|
||
eq(
|
||
{ 'Error in two lines lnum is 1 and end_lnum is 2' },
|
||
exec_lua(function()
|
||
vim.api.nvim_win_set_cursor(0, { 2, 1 })
|
||
local float_bufnr, winnr =
|
||
vim.diagnostic.open_float(0, { header = false, scope = 'cursor' })
|
||
local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
|
||
vim.api.nvim_win_close(winnr, true)
|
||
return lines
|
||
end)
|
||
)
|
||
|
||
-- can open a float window on end_lnum 2
|
||
eq(
|
||
{ '1. Error in two lines lnum is 1 and end_lnum is 2' },
|
||
exec_lua(function()
|
||
vim.api.nvim_win_set_cursor(0, { 3, 0 })
|
||
local float_bufnr, winnr = vim.diagnostic.open_float(0, { 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)
|
||
)
|
||
|
||
-- can open a cursor-scoped float window on end_lnum 2
|
||
eq(
|
||
{ 'Error in two lines lnum is 1 and end_lnum is 2' },
|
||
exec_lua(function()
|
||
vim.api.nvim_win_set_cursor(0, { 3, 2 })
|
||
local float_bufnr, winnr =
|
||
vim.diagnostic.open_float(0, { header = false, scope = 'cursor' })
|
||
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('shows diagnostics at their logical locations after text changes before', function()
|
||
exec_lua(function()
|
||
vim.api.nvim_set_current_buf(_G.diagnostic_bufnr)
|
||
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_error('Diagnostic #1', 1, 4, 1, 7),
|
||
_G.make_error('Diagnostic #2', 3, 0, 3, 3),
|
||
})
|
||
end)
|
||
|
||
api.nvim_buf_set_text(0, 3, 0, 3, 0, { 'new line', 'new ' })
|
||
|
||
eq(
|
||
{ 'Diagnostic #1' },
|
||
exec_lua(function()
|
||
vim.api.nvim_win_set_cursor(0, { 2, 4 })
|
||
local float_bufnr, winnr = vim.diagnostic.open_float({ header = '', scope = 'cursor' })
|
||
local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
|
||
vim.api.nvim_win_close(winnr, true)
|
||
return lines
|
||
end)
|
||
)
|
||
|
||
eq(
|
||
{ 'Diagnostic #2' },
|
||
exec_lua(function()
|
||
vim.api.nvim_win_set_cursor(0, { 5, 4 })
|
||
local float_bufnr, winnr = vim.diagnostic.open_float({ header = '', scope = 'cursor' })
|
||
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('shows diagnostics at their logical locations after text changes inside', function()
|
||
exec_lua(function()
|
||
vim.api.nvim_set_current_buf(_G.diagnostic_bufnr)
|
||
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_error('Diagnostic #1', 1, 0, 1, 7),
|
||
})
|
||
end)
|
||
|
||
api.nvim_buf_set_text(0, 1, 4, 1, 4, { 'new ' })
|
||
|
||
eq(
|
||
{ 'Diagnostic #1' },
|
||
exec_lua(function()
|
||
vim.api.nvim_win_set_cursor(0, { 2, 10 })
|
||
local float_bufnr, winnr = vim.diagnostic.open_float({ header = '', scope = 'cursor' })
|
||
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(
|
||
'shows diagnostics at the end of the line if diagnostic is set after last character in line',
|
||
function()
|
||
exec_lua(function()
|
||
vim.api.nvim_set_current_buf(_G.diagnostic_bufnr)
|
||
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_error('Diagnostic #1', 2, 3, 3, 4),
|
||
})
|
||
end)
|
||
|
||
eq(
|
||
{ 'Diagnostic #1' },
|
||
exec_lua(function()
|
||
vim.api.nvim_win_set_cursor(0, { 3, 2 })
|
||
local float_bufnr, winnr = vim.diagnostic.open_float({ header = '', scope = 'cursor' })
|
||
local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
|
||
vim.api.nvim_win_close(winnr, true)
|
||
return lines
|
||
end)
|
||
)
|
||
end
|
||
)
|
||
end)
|
||
|
||
describe('setloclist()', function()
|
||
it('sets diagnostics in lnum order', function()
|
||
local loc_list = exec_lua(function()
|
||
vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
|
||
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_error('Farther Diagnostic', 4, 4, 4, 4),
|
||
_G.make_error('Lower Diagnostic', 1, 1, 1, 1),
|
||
})
|
||
|
||
vim.diagnostic.setloclist()
|
||
|
||
return vim.fn.getloclist(0)
|
||
end)
|
||
|
||
assert(loc_list[1].lnum < loc_list[2].lnum)
|
||
end)
|
||
|
||
it('sets diagnostics in lnum order, regardless of namespace', function()
|
||
local loc_list = exec_lua(function()
|
||
vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
|
||
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_error('Lower Diagnostic', 1, 1, 1, 1),
|
||
})
|
||
|
||
vim.diagnostic.set(_G.other_ns, _G.diagnostic_bufnr, {
|
||
_G.make_warning('Farther Diagnostic', 4, 4, 4, 4),
|
||
})
|
||
|
||
vim.diagnostic.setloclist()
|
||
|
||
return vim.fn.getloclist(0)
|
||
end)
|
||
|
||
assert(loc_list[1].lnum < loc_list[2].lnum)
|
||
end)
|
||
|
||
it('sets diagnostics from the specified namespaces', function()
|
||
local loc_list = exec_lua(function()
|
||
vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
|
||
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_error('Error here!', 1, 1, 1, 1),
|
||
})
|
||
vim.diagnostic.set(_G.other_ns, _G.diagnostic_bufnr, {
|
||
_G.make_warning('Error there!', 2, 2, 2, 2),
|
||
})
|
||
|
||
vim.diagnostic.setloclist({ namespace = { _G.diagnostic_ns } })
|
||
|
||
return vim.fn.getloclist(0)
|
||
end)
|
||
|
||
eq(1, #loc_list)
|
||
eq('Error here!', loc_list[1].text)
|
||
end)
|
||
|
||
it('supports format function', function()
|
||
local loc_list = exec_lua(function()
|
||
vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
|
||
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_error('Error', 1, 1, 1, 1, 'foo_ls'),
|
||
_G.make_error('Another error', 2, 2, 2, 2, 'foo_ls'),
|
||
})
|
||
|
||
vim.diagnostic.setloclist({
|
||
format = function(diagnostic)
|
||
if diagnostic.lnum > 1 then
|
||
return nil
|
||
end
|
||
|
||
return string.format('%s: %s', diagnostic.source, diagnostic.message)
|
||
end,
|
||
})
|
||
|
||
return vim.fn.getloclist(0)
|
||
end)
|
||
|
||
eq(1, #loc_list)
|
||
eq('foo_ls: Error', loc_list[1].text)
|
||
end)
|
||
end)
|
||
|
||
describe('setqflist()', function()
|
||
it('updates existing diagnostics quickfix if one already exists', function()
|
||
local result = exec_lua(function()
|
||
vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
|
||
|
||
vim.fn.setqflist({}, ' ', { title = 'Diagnostics' })
|
||
local diagnostics_qf_id = vim.fn.getqflist({ id = 0 }).id
|
||
|
||
vim.diagnostic.setqflist({ title = 'Diagnostics' })
|
||
local qf_id = vim.fn.getqflist({ id = 0, nr = '$' }).id
|
||
|
||
return { diagnostics_qf_id, qf_id }
|
||
end)
|
||
|
||
eq(result[1], result[2])
|
||
end)
|
||
|
||
it('navigates to existing diagnostics quickfix if one already exists and open=true', function()
|
||
local result = exec_lua(function()
|
||
vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
|
||
|
||
vim.fn.setqflist({}, ' ', { title = 'Diagnostics' })
|
||
local diagnostics_qf_id = vim.fn.getqflist({ id = 0 }).id
|
||
|
||
vim.fn.setqflist({}, ' ', { title = 'Other' })
|
||
|
||
vim.diagnostic.setqflist({ title = 'Diagnostics', open = true })
|
||
local qf_id = vim.fn.getqflist({ id = 0 }).id
|
||
|
||
return { diagnostics_qf_id, qf_id }
|
||
end)
|
||
|
||
eq(result[1], result[2])
|
||
end)
|
||
|
||
it('sets new diagnostics quickfix as active when open=true', function()
|
||
local result = exec_lua(function()
|
||
vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
|
||
|
||
vim.fn.setqflist({}, ' ', { title = 'Other' })
|
||
local other_qf_id = vim.fn.getqflist({ id = 0 }).id
|
||
|
||
vim.diagnostic.setqflist({ title = 'Diagnostics', open = true })
|
||
local qf_id = vim.fn.getqflist({ id = 0 }).id
|
||
|
||
return { other_qf_id, qf_id }
|
||
end)
|
||
|
||
neq(result[1], result[2])
|
||
end)
|
||
|
||
it('opens quickfix window when open=true', function()
|
||
local qf_winid = exec_lua(function()
|
||
vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
|
||
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_error('Error', 1, 1, 1, 1),
|
||
})
|
||
|
||
vim.diagnostic.setqflist({ open = true })
|
||
|
||
return vim.fn.getqflist({ winid = 0 }).winid
|
||
end)
|
||
|
||
neq(0, qf_winid)
|
||
end)
|
||
|
||
it('supports format function', function()
|
||
local qf_list = exec_lua(function()
|
||
vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
|
||
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_error('Error', 1, 1, 1, 1, 'foo_ls'),
|
||
_G.make_error('Another error', 2, 2, 2, 2, 'foo_ls'),
|
||
})
|
||
|
||
vim.diagnostic.setqflist({
|
||
format = function(diagnostic)
|
||
if diagnostic.lnum > 1 then
|
||
return nil
|
||
end
|
||
|
||
return string.format('%s: %s', diagnostic.source, diagnostic.message)
|
||
end,
|
||
})
|
||
|
||
return vim.fn.getqflist()
|
||
end)
|
||
|
||
eq(1, #qf_list)
|
||
eq('foo_ls: Error', qf_list[1].text)
|
||
end)
|
||
end)
|
||
|
||
describe('match()', function()
|
||
it('matches a string', function()
|
||
local msg = 'ERROR: george.txt:19:84:Two plus two equals five'
|
||
local diagnostic = {
|
||
severity = exec_lua [[return vim.diagnostic.severity.ERROR]],
|
||
lnum = 18,
|
||
col = 83,
|
||
end_lnum = 18,
|
||
end_col = 83,
|
||
message = 'Two plus two equals five',
|
||
}
|
||
eq(
|
||
diagnostic,
|
||
exec_lua(function()
|
||
return vim.diagnostic.match(
|
||
msg,
|
||
'^(%w+): [^:]+:(%d+):(%d+):(.+)$',
|
||
{ 'severity', 'lnum', 'col', 'message' }
|
||
)
|
||
end)
|
||
)
|
||
end)
|
||
|
||
it('returns nil if the pattern fails to match', function()
|
||
eq(
|
||
nil,
|
||
exec_lua(function()
|
||
local msg = 'The answer to life, the universe, and everything is'
|
||
return vim.diagnostic.match(msg, 'This definitely will not match', {})
|
||
end)
|
||
)
|
||
end)
|
||
|
||
it('respects default values', function()
|
||
local msg = 'anna.txt:1:Happy families are all alike'
|
||
local diagnostic = {
|
||
severity = exec_lua [[return vim.diagnostic.severity.INFO]],
|
||
lnum = 0,
|
||
col = 0,
|
||
end_lnum = 0,
|
||
end_col = 0,
|
||
message = 'Happy families are all alike',
|
||
}
|
||
eq(
|
||
diagnostic,
|
||
exec_lua(function()
|
||
return vim.diagnostic.match(
|
||
msg,
|
||
'^[^:]+:(%d+):(.+)$',
|
||
{ 'lnum', 'message' },
|
||
nil,
|
||
{ severity = vim.diagnostic.severity.INFO }
|
||
)
|
||
end)
|
||
)
|
||
end)
|
||
|
||
it('accepts a severity map', function()
|
||
local msg = '46:FATAL:Et tu, Brute?'
|
||
local diagnostic = {
|
||
severity = exec_lua [[return vim.diagnostic.severity.ERROR]],
|
||
lnum = 45,
|
||
col = 0,
|
||
end_lnum = 45,
|
||
end_col = 0,
|
||
message = 'Et tu, Brute?',
|
||
}
|
||
eq(
|
||
diagnostic,
|
||
exec_lua(function()
|
||
return vim.diagnostic.match(
|
||
msg,
|
||
'^(%d+):(%w+):(.+)$',
|
||
{ 'lnum', 'severity', 'message' },
|
||
{ FATAL = vim.diagnostic.severity.ERROR }
|
||
)
|
||
end)
|
||
)
|
||
end)
|
||
end)
|
||
|
||
describe('toqflist(), fromqflist()', function()
|
||
it('works', function()
|
||
local result = exec_lua(function()
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_error('Error 1', 0, 1, 0, 1),
|
||
_G.make_error('Error 2', 1, 1, 1, 1),
|
||
_G.make_warning('Warning', 2, 2, 2, 2),
|
||
})
|
||
|
||
local diagnostics = vim.diagnostic.get(_G.diagnostic_bufnr)
|
||
vim.fn.setqflist(vim.diagnostic.toqflist(diagnostics))
|
||
local list = vim.fn.getqflist()
|
||
local new_diagnostics = vim.diagnostic.fromqflist(list)
|
||
|
||
-- Remove extra properties not present in the return value of fromlist()
|
||
for _, v in ipairs(diagnostics) do
|
||
v._extmark_id = nil
|
||
v.namespace = nil
|
||
end
|
||
|
||
return { diagnostics, new_diagnostics }
|
||
end)
|
||
eq(result[1], result[2])
|
||
end)
|
||
|
||
it('merge_lines=true merges continuation lines', function()
|
||
local function get_fromqflist(merge_lines)
|
||
return exec_lua(function(merge_lines_)
|
||
local qflist = {
|
||
{
|
||
bufnr = 1,
|
||
lnum = 10,
|
||
col = 5,
|
||
end_lnum = 10,
|
||
end_col = 10,
|
||
text = 'error: [GHC-83865]',
|
||
type = 'E',
|
||
nr = 0,
|
||
valid = 1,
|
||
},
|
||
{
|
||
bufnr = 1,
|
||
lnum = 0,
|
||
col = 0,
|
||
end_lnum = 0,
|
||
end_col = 0,
|
||
text = " Couldn't match expected type",
|
||
type = '',
|
||
nr = 0,
|
||
valid = 0,
|
||
},
|
||
{
|
||
bufnr = 1,
|
||
lnum = 0,
|
||
col = 0,
|
||
end_lnum = 0,
|
||
end_col = 0,
|
||
text = ' with actual type',
|
||
type = '',
|
||
nr = 0,
|
||
valid = 0,
|
||
},
|
||
{
|
||
bufnr = 1,
|
||
lnum = 20,
|
||
col = 1,
|
||
end_lnum = 20,
|
||
end_col = 5,
|
||
text = 'warning: unused',
|
||
type = 'W',
|
||
nr = 0,
|
||
valid = 1,
|
||
},
|
||
}
|
||
return vim.diagnostic.fromqflist(qflist, { merge_lines = merge_lines_ })
|
||
end, merge_lines)
|
||
end
|
||
|
||
-- merge_lines=true
|
||
local result = get_fromqflist(true)
|
||
eq(2, #result)
|
||
eq(
|
||
"error: [GHC-83865]\n Couldn't match expected type\n with actual type",
|
||
result[1].message
|
||
)
|
||
eq('warning: unused', result[2].message)
|
||
|
||
-- merge_lines=false
|
||
result = get_fromqflist(false)
|
||
eq(2, #result)
|
||
eq('error: [GHC-83865]', result[1].message)
|
||
end)
|
||
end)
|
||
|
||
describe('status()', function()
|
||
it('returns empty string if no diagnostics', function()
|
||
local result = exec_lua(function()
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {})
|
||
return vim.diagnostic.status()
|
||
end)
|
||
|
||
eq('', result)
|
||
end)
|
||
|
||
it('returns count for each diagnostic kind', function()
|
||
local result = exec_lua(function()
|
||
vim.diagnostic.set(_G.diagnostic_ns, 0, {
|
||
_G.make_error('Error 1', 0, 1, 0, 1),
|
||
|
||
_G.make_warning('Warning 1', 2, 2, 2, 2),
|
||
_G.make_warning('Warning 2', 2, 2, 2, 2),
|
||
|
||
_G.make_info('Info 1', 3, 3, 3, 3),
|
||
_G.make_info('Info 2', 3, 3, 3, 3),
|
||
_G.make_info('Info 3', 3, 3, 3, 3),
|
||
|
||
_G.make_hint('Hint 1', 4, 4, 4, 4),
|
||
_G.make_hint('Hint 2', 4, 4, 4, 4),
|
||
_G.make_hint('Hint 3', 4, 4, 4, 4),
|
||
_G.make_hint('Hint 4', 4, 4, 4, 4),
|
||
})
|
||
return vim.diagnostic.status()
|
||
end)
|
||
|
||
eq(
|
||
'%#DiagnosticSignError#E:1 %#DiagnosticSignWarn#W:2 %#DiagnosticSignInfo#I:3 %#DiagnosticSignHint#H:4%##',
|
||
result
|
||
)
|
||
|
||
exec_lua('vim.cmd.enew()')
|
||
|
||
-- Empty diagnostics for a buffer without diagnostics
|
||
eq(
|
||
'',
|
||
exec_lua(function()
|
||
return vim.diagnostic.status()
|
||
end)
|
||
)
|
||
end)
|
||
|
||
it('uses text from diagnostic.config().signs.text[severity]', function()
|
||
local result = exec_lua(function()
|
||
vim.diagnostic.config({
|
||
signs = {
|
||
text = {
|
||
[vim.diagnostic.severity.ERROR] = '⨯',
|
||
[vim.diagnostic.severity.WARN] = '⚠︎',
|
||
},
|
||
},
|
||
})
|
||
|
||
vim.diagnostic.set(_G.diagnostic_ns, 0, {
|
||
_G.make_error('Error 1', 0, 1, 0, 1),
|
||
_G.make_warning('Warning 1', 2, 2, 2, 2),
|
||
})
|
||
|
||
return vim.diagnostic.status()
|
||
end)
|
||
|
||
eq('%#DiagnosticSignError#⨯:1 %#DiagnosticSignWarn#⚠︎:1%##', result)
|
||
end)
|
||
|
||
it('works when signs are disabled', function()
|
||
local result = exec_lua(function()
|
||
vim.diagnostic.config({ signs = false })
|
||
|
||
vim.diagnostic.set(_G.diagnostic_ns, 0, {
|
||
_G.make_error('Error 1', 0, 1, 0, 1),
|
||
_G.make_warning('Warning 1', 2, 2, 2, 2),
|
||
})
|
||
|
||
return vim.diagnostic.status()
|
||
end)
|
||
|
||
eq('%#DiagnosticSignError#E:1 %#DiagnosticSignWarn#W:1%##', result)
|
||
end)
|
||
|
||
it('uses format function diagnostic.config().status.format', function()
|
||
local result = exec_lua(function()
|
||
local signs = {
|
||
[vim.diagnostic.severity.ERROR] = 'EE',
|
||
[vim.diagnostic.severity.WARN] = 'WW',
|
||
[vim.diagnostic.severity.INFO] = 'II',
|
||
[vim.diagnostic.severity.HINT] = 'HH',
|
||
}
|
||
local hl_map = {
|
||
[vim.diagnostic.severity.ERROR] = 'ERROR',
|
||
[vim.diagnostic.severity.WARN] = 'WARN',
|
||
[vim.diagnostic.severity.INFO] = 'INFO',
|
||
[vim.diagnostic.severity.HINT] = 'HINT',
|
||
}
|
||
vim.diagnostic.config({
|
||
status = {
|
||
format = function(counts)
|
||
local items = {}
|
||
for severity, sign in ipairs(signs) do
|
||
local count = counts[severity] or 0
|
||
local hl = hl_map[severity]
|
||
table.insert(items, ('%%#%s#%s %s'):format(hl, sign, count))
|
||
end
|
||
return table.concat(items, ' ')
|
||
end,
|
||
},
|
||
})
|
||
|
||
vim.diagnostic.set(_G.diagnostic_ns, 0, {
|
||
_G.make_error('Error 1', 0, 1, 0, 1),
|
||
_G.make_warning('Warning 1', 2, 2, 2, 2),
|
||
})
|
||
|
||
return vim.diagnostic.status()
|
||
end)
|
||
|
||
eq('%#ERROR#EE 1 %#WARN#WW 1 %#INFO#II 0 %#HINT#HH 0%##', result)
|
||
end)
|
||
end)
|
||
|
||
describe('handlers', function()
|
||
it('checks that a new handler is a table', function()
|
||
matches(
|
||
[[.*handler: expected table, got string.*]],
|
||
pcall_err(exec_lua, [[ vim.diagnostic.handlers.foo = "bar" ]])
|
||
)
|
||
matches(
|
||
[[.*handler: expected table, got function.*]],
|
||
pcall_err(exec_lua, [[ vim.diagnostic.handlers.foo = function() end ]])
|
||
)
|
||
end)
|
||
|
||
it('can add new handlers', function()
|
||
eq(
|
||
true,
|
||
exec_lua(function()
|
||
local handler_called = false
|
||
vim.diagnostic.handlers.test = {
|
||
show = function(namespace, bufnr, diagnostics, opts)
|
||
assert(namespace == _G.diagnostic_ns)
|
||
assert(bufnr == _G.diagnostic_bufnr)
|
||
assert(#diagnostics == 1)
|
||
assert(opts.test.some_opt == 42)
|
||
handler_called = true
|
||
end,
|
||
}
|
||
|
||
vim.diagnostic.config({ test = { some_opt = 42 } })
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_warning('Warning', 0, 0, 0, 0),
|
||
})
|
||
return handler_called
|
||
end)
|
||
)
|
||
end)
|
||
|
||
it('can disable handlers by setting the corresponding option to false', function()
|
||
eq(
|
||
false,
|
||
exec_lua(function()
|
||
local handler_called = false
|
||
vim.diagnostic.handlers.test = {
|
||
show = function(_, _, _, _)
|
||
handler_called = true
|
||
end,
|
||
}
|
||
|
||
vim.diagnostic.config({ test = false })
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_warning('Warning', 0, 0, 0, 0),
|
||
})
|
||
return handler_called
|
||
end)
|
||
)
|
||
end)
|
||
|
||
it("always calls a handler's hide function if defined", function()
|
||
eq(
|
||
{ false, true },
|
||
exec_lua(function()
|
||
local hide_called = false
|
||
local show_called = false
|
||
vim.diagnostic.handlers.test = {
|
||
show = function(_, _, _, _)
|
||
show_called = true
|
||
end,
|
||
hide = function(namespace, bufnr)
|
||
assert(namespace == _G.diagnostic_ns)
|
||
assert(bufnr == _G.diagnostic_bufnr)
|
||
hide_called = true
|
||
end,
|
||
}
|
||
|
||
vim.diagnostic.config({ test = false })
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_warning('Warning', 0, 0, 0, 0),
|
||
})
|
||
vim.diagnostic.hide(_G.diagnostic_ns, _G.diagnostic_bufnr)
|
||
return { show_called, hide_called }
|
||
end)
|
||
)
|
||
end)
|
||
|
||
it('triggers the autocommand when diagnostics are set', function()
|
||
eq(
|
||
{ true, true },
|
||
exec_lua(function()
|
||
-- Set a different buffer as current to test that <abuf> is being set properly in
|
||
-- DiagnosticChanged callbacks
|
||
local tmp = vim.api.nvim_create_buf(false, true)
|
||
vim.api.nvim_set_current_buf(tmp)
|
||
|
||
local triggered = {}
|
||
vim.api.nvim_create_autocmd('DiagnosticChanged', {
|
||
callback = function(ev)
|
||
triggered = { ev.buf, #ev.data.diagnostics }
|
||
end,
|
||
})
|
||
vim.api.nvim_buf_set_name(_G.diagnostic_bufnr, 'test | test')
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_error('Diagnostic', 0, 0, 0, 0),
|
||
})
|
||
return {
|
||
triggered[1] == _G.diagnostic_bufnr,
|
||
triggered[2] == 1,
|
||
}
|
||
end)
|
||
)
|
||
end)
|
||
|
||
it('triggers the autocommand when diagnostics are cleared', function()
|
||
eq(
|
||
true,
|
||
exec_lua(function()
|
||
local tmp = vim.api.nvim_create_buf(false, true)
|
||
vim.api.nvim_set_current_buf(tmp)
|
||
vim.g.diagnostic_autocmd_triggered = 0
|
||
vim.cmd(
|
||
'autocmd DiagnosticChanged * let g:diagnostic_autocmd_triggered = +expand("<abuf>")'
|
||
)
|
||
vim.api.nvim_buf_set_name(_G.diagnostic_bufnr, 'test | test')
|
||
vim.diagnostic.reset(_G.diagnostic_ns, _G.diagnostic_bufnr)
|
||
return vim.g.diagnostic_autocmd_triggered == _G.diagnostic_bufnr
|
||
end)
|
||
)
|
||
end)
|
||
|
||
it('is_enabled', function()
|
||
eq(
|
||
{ false, false, false, false, false },
|
||
exec_lua(function()
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_error('Diagnostic #1', 1, 1, 1, 1),
|
||
})
|
||
vim.api.nvim_set_current_buf(_G.diagnostic_bufnr)
|
||
vim.diagnostic.enable(false)
|
||
return {
|
||
vim.diagnostic.is_enabled(),
|
||
vim.diagnostic.is_enabled { bufnr = 0 },
|
||
vim.diagnostic.is_enabled { bufnr = _G.diagnostic_bufnr },
|
||
vim.diagnostic.is_enabled { bufnr = _G.diagnostic_bufnr, ns_id = _G.diagnostic_ns },
|
||
vim.diagnostic.is_enabled { bufnr = 0, ns_id = _G.diagnostic_ns },
|
||
}
|
||
end)
|
||
)
|
||
|
||
eq(
|
||
{ true, true, true, true, true },
|
||
exec_lua(function()
|
||
vim.diagnostic.enable()
|
||
return {
|
||
vim.diagnostic.is_enabled(),
|
||
vim.diagnostic.is_enabled { bufnr = 0 },
|
||
vim.diagnostic.is_enabled { bufnr = _G.diagnostic_bufnr },
|
||
vim.diagnostic.is_enabled { bufnr = _G.diagnostic_bufnr, ns_id = _G.diagnostic_ns },
|
||
vim.diagnostic.is_enabled { bufnr = 0, ns_id = _G.diagnostic_ns },
|
||
}
|
||
end)
|
||
)
|
||
end)
|
||
|
||
it('does not redraw for buffer not in window', function()
|
||
local did_status = exec_lua(function()
|
||
_G.Status = function()
|
||
_G.did_status = (_G.did_status or 0) + 1
|
||
end
|
||
vim.o.laststatus, vim.o.statusline = 2, '%!v:lua._G.Status()'
|
||
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
|
||
_G.make_error('Diagnostic #1', 1, 1, 1, 1),
|
||
})
|
||
return _G.did_status
|
||
end)
|
||
eq(nil, did_status)
|
||
end)
|
||
end)
|
||
end)
|