mirror of
https://github.com/neovim/neovim
synced 2025-07-15 16:51:49 +00:00
feat(diagnostic): virtual_lines #31959
This commit is contained in:
committed by
GitHub
parent
d84a95da7e
commit
1759b7844a
@ -97,8 +97,8 @@ If a diagnostic handler is configured with a "severity" key then the list of
|
||||
diagnostics passed to that handler will be filtered using the value of that
|
||||
key (see example below).
|
||||
|
||||
Nvim provides these handlers by default: "virtual_text", "signs", and
|
||||
"underline".
|
||||
Nvim provides these handlers by default: "virtual_text", "virtual_lines",
|
||||
"signs", and "underline".
|
||||
|
||||
*diagnostic-handlers-example*
|
||||
The example below creates a new handler that notifies the user of diagnostics
|
||||
@ -170,6 +170,16 @@ show a sign for the highest severity diagnostic on a given line: >lua
|
||||
}
|
||||
<
|
||||
|
||||
*diagnostic-toggle-virtual-lines-example*
|
||||
Diagnostic handlers can also be toggled. For example, you might want to toggle
|
||||
the `virtual_lines` handler with the following keymap: >lua
|
||||
|
||||
vim.keymap.set('n', 'gK', function()
|
||||
local new_config = not vim.diagnostic.config().virtual_lines
|
||||
vim.diagnostic.config({ virtual_lines = new_config })
|
||||
end, { desc = 'Toggle diagnostic virtual_lines' })
|
||||
<
|
||||
|
||||
*diagnostic-loclist-example*
|
||||
Whenever the |location-list| is opened, the following `show` handler will show
|
||||
the most recent diagnostics: >lua
|
||||
@ -469,6 +479,8 @@ Lua module: vim.diagnostic *diagnostic-api*
|
||||
diagnostics are set for a namespace, one prefix
|
||||
per diagnostic + the last diagnostic message are
|
||||
shown.
|
||||
• {virtual_lines}? (`boolean|vim.diagnostic.Opts.VirtualLines|fun(namespace: integer, bufnr:integer): vim.diagnostic.Opts.VirtualLines`, default: `false`)
|
||||
Use virtual lines for diagnostics.
|
||||
• {signs}? (`boolean|vim.diagnostic.Opts.Signs|fun(namespace: integer, bufnr:integer): vim.diagnostic.Opts.Signs`, default: `true`)
|
||||
Use signs for diagnostics |diagnostic-signs|.
|
||||
• {float}? (`boolean|vim.diagnostic.Opts.Float|fun(namespace: integer, bufnr:integer): vim.diagnostic.Opts.Float`)
|
||||
@ -590,6 +602,16 @@ Lua module: vim.diagnostic *diagnostic-api*
|
||||
diagnostics matching the given severity
|
||||
|diagnostic-severity|.
|
||||
|
||||
*vim.diagnostic.Opts.VirtualLines*
|
||||
|
||||
Fields: ~
|
||||
• {current_line}? (`boolean`, default: `false`) Only show diagnostics
|
||||
for the current line.
|
||||
• {format}? (`fun(diagnostic:vim.Diagnostic): string`) A function
|
||||
that takes a diagnostic as input and returns a
|
||||
string. The return value is the text used to display
|
||||
the diagnostic.
|
||||
|
||||
*vim.diagnostic.Opts.VirtualText*
|
||||
|
||||
Fields: ~
|
||||
|
@ -235,6 +235,8 @@ DIAGNOSTICS
|
||||
|
||||
• |vim.diagnostic.config()| accepts a "jump" table to specify defaults for
|
||||
|vim.diagnostic.jump()|.
|
||||
• A "virtual_lines" diagnostic handler was added to render diagnostics using
|
||||
virtual lines below the respective code.
|
||||
|
||||
EDITOR
|
||||
|
||||
|
@ -73,6 +73,10 @@ end
|
||||
--- (default: `false`)
|
||||
--- @field virtual_text? boolean|vim.diagnostic.Opts.VirtualText|fun(namespace: integer, bufnr:integer): vim.diagnostic.Opts.VirtualText
|
||||
---
|
||||
--- Use virtual lines for diagnostics.
|
||||
--- (default: `false`)
|
||||
--- @field virtual_lines? boolean|vim.diagnostic.Opts.VirtualLines|fun(namespace: integer, bufnr:integer): vim.diagnostic.Opts.VirtualLines
|
||||
---
|
||||
--- Use signs for diagnostics |diagnostic-signs|.
|
||||
--- (default: `true`)
|
||||
--- @field signs? boolean|vim.diagnostic.Opts.Signs|fun(namespace: integer, bufnr:integer): vim.diagnostic.Opts.Signs
|
||||
@ -101,6 +105,7 @@ end
|
||||
--- @field update_in_insert boolean
|
||||
--- @field underline vim.diagnostic.Opts.Underline
|
||||
--- @field virtual_text vim.diagnostic.Opts.VirtualText
|
||||
--- @field virtual_lines vim.diagnostic.Opts.VirtualLines
|
||||
--- @field signs vim.diagnostic.Opts.Signs
|
||||
--- @field severity_sort {reverse?:boolean}
|
||||
|
||||
@ -228,6 +233,16 @@ end
|
||||
--- See |nvim_buf_set_extmark()|.
|
||||
--- @field virt_text_hide? boolean
|
||||
|
||||
--- @class vim.diagnostic.Opts.VirtualLines
|
||||
---
|
||||
--- Only show diagnostics for the current line.
|
||||
--- (default: `false`)
|
||||
--- @field current_line? boolean
|
||||
---
|
||||
--- A function that takes a diagnostic as input and returns a string.
|
||||
--- The return value is the text used to display the diagnostic.
|
||||
--- @field format? fun(diagnostic:vim.Diagnostic): string
|
||||
|
||||
--- @class vim.diagnostic.Opts.Signs
|
||||
---
|
||||
--- Only show virtual text for diagnostics matching the given
|
||||
@ -313,6 +328,7 @@ local global_diagnostic_options = {
|
||||
signs = true,
|
||||
underline = true,
|
||||
virtual_text = false,
|
||||
virtual_lines = false,
|
||||
float = true,
|
||||
update_in_insert = false,
|
||||
severity_sort = false,
|
||||
@ -328,6 +344,7 @@ local global_diagnostic_options = {
|
||||
--- @class (private) vim.diagnostic.Handler
|
||||
--- @field show? fun(namespace: integer, bufnr: integer, diagnostics: vim.Diagnostic[], opts?: vim.diagnostic.OptsResolved)
|
||||
--- @field hide? fun(namespace:integer, bufnr:integer)
|
||||
--- @field _augroup? integer
|
||||
|
||||
--- @nodoc
|
||||
--- @type table<string,vim.diagnostic.Handler>
|
||||
@ -581,6 +598,7 @@ end
|
||||
-- TODO(lewis6991): these highlight maps can only be indexed with an integer, however there usage
|
||||
-- implies they can be indexed with any vim.diagnostic.Severity
|
||||
local virtual_text_highlight_map = make_highlight_map('VirtualText')
|
||||
local virtual_lines_highlight_map = make_highlight_map('VirtualLines')
|
||||
local underline_highlight_map = make_highlight_map('Underline')
|
||||
local floating_highlight_map = make_highlight_map('Floating')
|
||||
local sign_highlight_map = make_highlight_map('Sign')
|
||||
@ -1603,6 +1621,264 @@ M.handlers.virtual_text = {
|
||||
end,
|
||||
}
|
||||
|
||||
--- Some characters (like tabs) take up more than one cell. Additionally, inline
|
||||
--- virtual text can make the distance between 2 columns larger.
|
||||
--- A diagnostic aligned under such characters needs to account for that and that
|
||||
--- many spaces to its left.
|
||||
--- @param bufnr integer
|
||||
--- @param lnum integer
|
||||
--- @param start_col integer
|
||||
--- @param end_col integer
|
||||
--- @return integer
|
||||
local function distance_between_cols(bufnr, lnum, start_col, end_col)
|
||||
return api.nvim_buf_call(bufnr, function()
|
||||
local s = vim.fn.virtcol({ lnum + 1, start_col })
|
||||
local e = vim.fn.virtcol({ lnum + 1, end_col + 1 })
|
||||
return e - 1 - s
|
||||
end)
|
||||
end
|
||||
|
||||
--- @param namespace integer
|
||||
--- @param bufnr integer
|
||||
--- @param diagnostics vim.Diagnostic[]
|
||||
local function render_virtual_lines(namespace, bufnr, diagnostics)
|
||||
table.sort(diagnostics, function(d1, d2)
|
||||
if d1.lnum == d2.lnum then
|
||||
return d1.col < d2.col
|
||||
else
|
||||
return d1.lnum < d2.lnum
|
||||
end
|
||||
end)
|
||||
|
||||
api.nvim_buf_clear_namespace(bufnr, namespace, 0, -1)
|
||||
|
||||
if not next(diagnostics) then
|
||||
return
|
||||
end
|
||||
|
||||
-- This loop reads each line, putting them into stacks with some extra data since
|
||||
-- rendering each line requires understanding what is beneath it.
|
||||
local ElementType = { Space = 1, Diagnostic = 2, Overlap = 3, Blank = 4 } ---@enum ElementType
|
||||
local line_stacks = {} ---@type table<integer, {[1]:ElementType, [2]:string|vim.diagnostic.Severity|vim.Diagnostic}[]>
|
||||
local prev_lnum = -1
|
||||
local prev_col = 0
|
||||
for _, diag in ipairs(diagnostics) do
|
||||
if not line_stacks[diag.lnum] then
|
||||
line_stacks[diag.lnum] = {}
|
||||
end
|
||||
|
||||
local stack = line_stacks[diag.lnum]
|
||||
|
||||
if diag.lnum ~= prev_lnum then
|
||||
table.insert(stack, {
|
||||
ElementType.Space,
|
||||
string.rep(' ', distance_between_cols(bufnr, diag.lnum, 0, diag.col)),
|
||||
})
|
||||
elseif diag.col ~= prev_col then
|
||||
table.insert(stack, {
|
||||
ElementType.Space,
|
||||
string.rep(
|
||||
' ',
|
||||
-- +1 because indexing starts at 0 in one API but at 1 in the other.
|
||||
-- -1 for non-first lines, since the previous column was already drawn.
|
||||
distance_between_cols(bufnr, diag.lnum, prev_col + 1, diag.col) - 1
|
||||
),
|
||||
})
|
||||
else
|
||||
table.insert(stack, { ElementType.Overlap, diag.severity })
|
||||
end
|
||||
|
||||
if diag.message:find('^%s*$') then
|
||||
table.insert(stack, { ElementType.Blank, diag })
|
||||
else
|
||||
table.insert(stack, { ElementType.Diagnostic, diag })
|
||||
end
|
||||
|
||||
prev_lnum, prev_col = diag.lnum, diag.col
|
||||
end
|
||||
|
||||
local chars = {
|
||||
cross = '┼',
|
||||
horizontal = '─',
|
||||
horizontal_up = '┴',
|
||||
up_right = '└',
|
||||
vertical = '│',
|
||||
vertical_right = '├',
|
||||
}
|
||||
|
||||
for lnum, stack in pairs(line_stacks) do
|
||||
local virt_lines = {}
|
||||
|
||||
-- Note that we read in the order opposite to insertion.
|
||||
for i = #stack, 1, -1 do
|
||||
if stack[i][1] == ElementType.Diagnostic then
|
||||
local diagnostic = stack[i][2]
|
||||
local left = {} ---@type {[1]:string, [2]:string}
|
||||
local overlap = false
|
||||
local multi = false
|
||||
|
||||
-- Iterate the stack for this line to find elements on the left.
|
||||
for j = 1, i - 1 do
|
||||
local type = stack[j][1]
|
||||
local data = stack[j][2]
|
||||
if type == ElementType.Space then
|
||||
if multi then
|
||||
---@cast data string
|
||||
table.insert(left, {
|
||||
string.rep(chars.horizontal, data:len()),
|
||||
virtual_lines_highlight_map[diagnostic.severity],
|
||||
})
|
||||
else
|
||||
table.insert(left, { data, '' })
|
||||
end
|
||||
elseif type == ElementType.Diagnostic then
|
||||
-- If an overlap follows this line, don't add an extra column.
|
||||
if stack[j + 1][1] ~= ElementType.Overlap then
|
||||
table.insert(left, { chars.vertical, virtual_lines_highlight_map[data.severity] })
|
||||
end
|
||||
overlap = false
|
||||
elseif type == ElementType.Blank then
|
||||
if multi then
|
||||
table.insert(
|
||||
left,
|
||||
{ chars.horizontal_up, virtual_lines_highlight_map[data.severity] }
|
||||
)
|
||||
else
|
||||
table.insert(left, { chars.up_right, virtual_lines_highlight_map[data.severity] })
|
||||
end
|
||||
multi = true
|
||||
elseif type == ElementType.Overlap then
|
||||
overlap = true
|
||||
end
|
||||
end
|
||||
|
||||
local center_char ---@type string
|
||||
if overlap and multi then
|
||||
center_char = chars.cross
|
||||
elseif overlap then
|
||||
center_char = chars.vertical_right
|
||||
elseif multi then
|
||||
center_char = chars.horizontal_up
|
||||
else
|
||||
center_char = chars.up_right
|
||||
end
|
||||
local center = {
|
||||
{
|
||||
string.format('%s%s', center_char, string.rep(chars.horizontal, 4) .. ' '),
|
||||
virtual_lines_highlight_map[diagnostic.severity],
|
||||
},
|
||||
}
|
||||
|
||||
-- We can draw on the left side if and only if:
|
||||
-- a. Is the last one stacked this line.
|
||||
-- b. Has enough space on the left.
|
||||
-- c. Is just one line.
|
||||
-- d. Is not an overlap.
|
||||
local msg ---@type string
|
||||
if diagnostic.code then
|
||||
msg = string.format('%s: %s', diagnostic.code, diagnostic.message)
|
||||
else
|
||||
msg = diagnostic.message
|
||||
end
|
||||
for msg_line in msg:gmatch('([^\n]+)') do
|
||||
local vline = {}
|
||||
vim.list_extend(vline, left)
|
||||
vim.list_extend(vline, center)
|
||||
vim.list_extend(vline, { { msg_line, virtual_lines_highlight_map[diagnostic.severity] } })
|
||||
|
||||
table.insert(virt_lines, vline)
|
||||
|
||||
-- Special-case for continuation lines:
|
||||
if overlap then
|
||||
center = {
|
||||
{ chars.vertical, virtual_lines_highlight_map[diagnostic.severity] },
|
||||
{ ' ', '' },
|
||||
}
|
||||
else
|
||||
center = { { ' ', '' } }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
api.nvim_buf_set_extmark(bufnr, namespace, lnum, 0, { virt_lines = virt_lines })
|
||||
end
|
||||
end
|
||||
|
||||
--- @param diagnostics vim.Diagnostic[]
|
||||
--- @param namespace integer
|
||||
--- @param bufnr integer
|
||||
local function render_virtual_lines_at_current_line(diagnostics, namespace, bufnr)
|
||||
local line_diagnostics = {}
|
||||
local lnum = api.nvim_win_get_cursor(0)[1] - 1
|
||||
|
||||
for _, diag in ipairs(diagnostics) do
|
||||
if (lnum == diag.lnum) or (diag.end_lnum and lnum >= diag.lnum and lnum <= diag.end_lnum) then
|
||||
table.insert(line_diagnostics, diag)
|
||||
end
|
||||
end
|
||||
|
||||
render_virtual_lines(namespace, bufnr, line_diagnostics)
|
||||
end
|
||||
|
||||
M.handlers.virtual_lines = {
|
||||
show = function(namespace, bufnr, diagnostics, opts)
|
||||
vim.validate('namespace', namespace, 'number')
|
||||
vim.validate('bufnr', bufnr, 'number')
|
||||
vim.validate('diagnostics', diagnostics, vim.islist, 'a list of diagnostics')
|
||||
vim.validate('opts', opts, 'table', true)
|
||||
|
||||
bufnr = vim._resolve_bufnr(bufnr)
|
||||
opts = opts or {}
|
||||
|
||||
if not api.nvim_buf_is_loaded(bufnr) then
|
||||
return
|
||||
end
|
||||
|
||||
local ns = M.get_namespace(namespace)
|
||||
if not ns.user_data.virt_lines_ns then
|
||||
ns.user_data.virt_lines_ns =
|
||||
api.nvim_create_namespace(string.format('nvim.%s.diagnostic.virtual_lines', ns.name))
|
||||
end
|
||||
if not M.handlers.virtual_lines._augroup then
|
||||
M.handlers.virtual_lines._augroup =
|
||||
api.nvim_create_augroup('nvim.lsp.diagnostic.virt_lines', { clear = true })
|
||||
end
|
||||
|
||||
api.nvim_clear_autocmds({ group = M.handlers.virtual_lines._augroup })
|
||||
|
||||
if opts.virtual_lines.format then
|
||||
diagnostics = reformat_diagnostics(opts.virtual_lines.format, diagnostics)
|
||||
end
|
||||
|
||||
if opts.virtual_lines.current_line == true then
|
||||
api.nvim_create_autocmd('CursorMoved', {
|
||||
buffer = bufnr,
|
||||
group = M.handlers.virtual_lines._augroup,
|
||||
callback = function()
|
||||
render_virtual_lines_at_current_line(diagnostics, ns.user_data.virt_lines_ns, bufnr)
|
||||
end,
|
||||
})
|
||||
-- Also show diagnostics for the current line before the first CursorMoved event.
|
||||
render_virtual_lines_at_current_line(diagnostics, ns.user_data.virt_lines_ns, bufnr)
|
||||
else
|
||||
render_virtual_lines(ns.user_data.virt_lines_ns, bufnr, diagnostics)
|
||||
end
|
||||
|
||||
save_extmarks(ns.user_data.virt_lines_ns, bufnr)
|
||||
end,
|
||||
hide = function(namespace, bufnr)
|
||||
local ns = M.get_namespace(namespace)
|
||||
if ns.user_data.virt_lines_ns then
|
||||
diagnostic_cache_extmarks[bufnr][ns.user_data.virt_lines_ns] = {}
|
||||
if api.nvim_buf_is_valid(bufnr) then
|
||||
api.nvim_buf_clear_namespace(bufnr, ns.user_data.virt_lines_ns, 0, -1)
|
||||
end
|
||||
api.nvim_clear_autocmds({ group = M.handlers.virtual_lines._augroup })
|
||||
end
|
||||
end,
|
||||
}
|
||||
|
||||
--- Get virtual text chunks to display using |nvim_buf_set_extmark()|.
|
||||
---
|
||||
--- Exported for backward compatibility with
|
||||
|
@ -232,6 +232,11 @@ static const char *highlight_init_both[] = {
|
||||
"default link DiagnosticVirtualTextInfo DiagnosticInfo",
|
||||
"default link DiagnosticVirtualTextHint DiagnosticHint",
|
||||
"default link DiagnosticVirtualTextOk DiagnosticOk",
|
||||
"default link DiagnosticVirtualLinesError DiagnosticError",
|
||||
"default link DiagnosticVirtualLinesWarn DiagnosticWarn",
|
||||
"default link DiagnosticVirtualLinesInfo DiagnosticInfo",
|
||||
"default link DiagnosticVirtualLinesHint DiagnosticHint",
|
||||
"default link DiagnosticVirtualLinesOk DiagnosticOk",
|
||||
"default link DiagnosticSignError DiagnosticError",
|
||||
"default link DiagnosticSignWarn DiagnosticWarn",
|
||||
"default link DiagnosticSignInfo DiagnosticInfo",
|
||||
|
@ -113,6 +113,18 @@ describe('vim.diagnostic', function()
|
||||
)
|
||||
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
|
||||
@ -161,6 +173,11 @@ describe('vim.diagnostic', function()
|
||||
'DiagnosticUnderlineOk',
|
||||
'DiagnosticUnderlineWarn',
|
||||
'DiagnosticUnnecessary',
|
||||
'DiagnosticVirtualLinesError',
|
||||
'DiagnosticVirtualLinesHint',
|
||||
'DiagnosticVirtualLinesInfo',
|
||||
'DiagnosticVirtualLinesOk',
|
||||
'DiagnosticVirtualLinesWarn',
|
||||
'DiagnosticVirtualTextError',
|
||||
'DiagnosticVirtualTextHint',
|
||||
'DiagnosticVirtualTextInfo',
|
||||
@ -582,7 +599,7 @@ describe('vim.diagnostic', function()
|
||||
vim.diagnostic.set(
|
||||
_G.diagnostic_ns,
|
||||
_G.diagnostic_bufnr,
|
||||
{ { lnum = 0, end_lnum = 0, col = 0, end_col = 0 } }
|
||||
{ { message = '', lnum = 0, end_lnum = 0, col = 0, end_col = 0 } }
|
||||
)
|
||||
vim.cmd('bwipeout! ' .. _G.diagnostic_bufnr)
|
||||
|
||||
@ -1017,7 +1034,7 @@ describe('vim.diagnostic', function()
|
||||
vim.diagnostic.set(
|
||||
_G.diagnostic_ns,
|
||||
_G.diagnostic_bufnr,
|
||||
{ { lnum = 0, end_lnum = 0, col = 0, end_col = 0 } }
|
||||
{ { message = '', lnum = 0, end_lnum = 0, col = 0, end_col = 0 } }
|
||||
)
|
||||
vim.cmd('bwipeout! ' .. _G.diagnostic_bufnr)
|
||||
|
||||
@ -2119,6 +2136,94 @@ describe('vim.diagnostic', function()
|
||||
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[1][4].virt_lines
|
||||
end)
|
||||
|
||||
eq('miss-symbol: Missed symbol `,`', result[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', 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, 1, 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])
|
||||
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'),
|
||||
})
|
||||
|
||||
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)
|
||||
end)
|
||||
|
||||
describe('set()', function()
|
||||
it('validation', function()
|
||||
matches(
|
||||
|
@ -858,7 +858,7 @@ local function test_cmdline(linegrid)
|
||||
cmdline = {
|
||||
{
|
||||
content = { { '' } },
|
||||
hl_id = 237,
|
||||
hl_id = 242,
|
||||
pos = 0,
|
||||
prompt = 'Prompt:',
|
||||
},
|
||||
|
@ -254,11 +254,11 @@ describe('ui/ext_messages', function()
|
||||
{
|
||||
content = {
|
||||
{ '\n@character ' },
|
||||
{ 'xxx', 26, 150 },
|
||||
{ 'xxx', 26, 155 },
|
||||
{ ' ' },
|
||||
{ 'links to', 18, 5 },
|
||||
{ ' Character\n@character.special ' },
|
||||
{ 'xxx', 16, 151 },
|
||||
{ 'xxx', 16, 156 },
|
||||
{ ' ' },
|
||||
{ 'links to', 18, 5 },
|
||||
{ ' SpecialChar' },
|
||||
|
Reference in New Issue
Block a user