aboutsummaryrefslogtreecommitdiff
path: root/runtime/lua/vim/diagnostic.lua
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/lua/vim/diagnostic.lua')
-rw-r--r--runtime/lua/vim/diagnostic.lua116
1 files changed, 90 insertions, 26 deletions
diff --git a/runtime/lua/vim/diagnostic.lua b/runtime/lua/vim/diagnostic.lua
index 09eeb617f5..18df1f1586 100644
--- a/runtime/lua/vim/diagnostic.lua
+++ b/runtime/lua/vim/diagnostic.lua
@@ -2,6 +2,7 @@ local api, if_nil = vim.api, vim.F.if_nil
local M = {}
+---@enum DiagnosticSeverity
M.severity = {
ERROR = 1,
WARN = 2,
@@ -613,6 +614,10 @@ end
--- * spacing: (number) Amount of empty spaces inserted at the beginning
--- of the virtual text.
--- * prefix: (string) Prepend diagnostic message with prefix.
+--- * suffix: (string or function) Append diagnostic message with suffix.
+--- If a function, it must have the signature (diagnostic) ->
+--- string, where {diagnostic} is of type |diagnostic-structure|.
+--- This can be used to render an LSP diagnostic error code.
--- * format: (function) A function that takes a diagnostic as input and
--- returns a string. The return value is the text used to display
--- the diagnostic. Example:
@@ -751,6 +756,18 @@ function M.get_namespaces()
return vim.deepcopy(all_namespaces)
end
+---@class Diagnostic
+---@field buffer number
+---@field lnum number 0-indexed
+---@field end_lnum nil|number 0-indexed
+---@field col number 0-indexed
+---@field end_col nil|number 0-indexed
+---@field severity DiagnosticSeverity
+---@field message string
+---@field source nil|string
+---@field code nil|string
+---@field user_data nil|any arbitrary data plugins can add
+
--- Get current diagnostics.
---
---@param bufnr number|nil Buffer number to get diagnostics from. Use 0 for
@@ -759,7 +776,7 @@ end
--- - namespace: (number) Limit diagnostics to the given namespace.
--- - lnum: (number) Limit diagnostics to the given line number.
--- - severity: See |diagnostic-severity|.
----@return table A list of diagnostic items |diagnostic-structure|.
+---@return Diagnostic[] table A list of diagnostic items |diagnostic-structure|.
function M.get(bufnr, opts)
vim.validate({
bufnr = { bufnr, 'n', true },
@@ -771,8 +788,8 @@ end
--- Get the previous diagnostic closest to the cursor position.
---
----@param opts table See |vim.diagnostic.goto_next()|
----@return table Previous diagnostic
+---@param opts nil|table See |vim.diagnostic.goto_next()|
+---@return Diagnostic|nil Previous diagnostic
function M.get_prev(opts)
opts = opts or {}
@@ -785,8 +802,9 @@ end
--- Return the position of the previous diagnostic in the current buffer.
---
----@param opts table See |vim.diagnostic.goto_next()|
----@return table Previous diagnostic position as a (row, col) tuple.
+---@param opts table|nil See |vim.diagnostic.goto_next()|
+---@return table|false Previous diagnostic position as a (row, col) tuple or false if there is no
+--- prior diagnostic
function M.get_prev_pos(opts)
local prev = M.get_prev(opts)
if not prev then
@@ -804,8 +822,8 @@ end
--- Get the next diagnostic closest to the cursor position.
---
----@param opts table See |vim.diagnostic.goto_next()|
----@return table Next diagnostic
+---@param opts table|nil See |vim.diagnostic.goto_next()|
+---@return Diagnostic|nil Next diagnostic
function M.get_next(opts)
opts = opts or {}
@@ -818,8 +836,9 @@ end
--- Return the position of the next diagnostic in the current buffer.
---
----@param opts table See |vim.diagnostic.goto_next()|
----@return table Next diagnostic position as a (row, col) tuple.
+---@param opts table|nil See |vim.diagnostic.goto_next()|
+---@return table|false Next diagnostic position as a (row, col) tuple or false if no next
+--- diagnostic.
function M.get_next_pos(opts)
local next = M.get_next(opts)
if not next then
@@ -1039,6 +1058,7 @@ function M._get_virt_text_chunks(line_diags, opts)
opts = opts or {}
local prefix = opts.prefix or '■'
+ local suffix = opts.suffix or ''
local spacing = opts.spacing or 4
-- Create a little more space between virtual text and contents
@@ -1052,8 +1072,11 @@ function M._get_virt_text_chunks(line_diags, opts)
-- TODO(tjdevries): Allow different servers to be shown first somehow?
-- TODO(tjdevries): Display server name associated with these?
if last.message then
+ if type(suffix) == 'function' then
+ suffix = suffix(last) or ''
+ end
table.insert(virt_texts, {
- string.format('%s %s', prefix, last.message:gsub('\r', ''):gsub('\n', ' ')),
+ string.format('%s %s%s', prefix, last.message:gsub('\r', ''):gsub('\n', ' '), suffix),
virtual_text_highlight_map[last.severity],
})
@@ -1220,7 +1243,9 @@ end
--- string, it is prepended to each diagnostic in the window with no
--- highlight.
--- Overrides the setting from |vim.diagnostic.config()|.
----@return tuple ({float_bufnr}, {win_id})
+--- - suffix: Same as {prefix}, but appends the text to the diagnostic instead of
+--- prepending it. Overrides the setting from |vim.diagnostic.config()|.
+---@return number|nil, number|nil: ({float_bufnr}, {win_id})
function M.open_float(opts, ...)
-- Support old (bufnr, opts) signature
local bufnr
@@ -1313,11 +1338,11 @@ function M.open_float(opts, ...)
-- Don't insert any lines for an empty string
if string.len(if_nil(header[1], '')) > 0 then
table.insert(lines, header[1])
- table.insert(highlights, { 0, header[2] or 'Bold' })
+ table.insert(highlights, { hlname = header[2] or 'Bold' })
end
elseif #header > 0 then
table.insert(lines, header)
- table.insert(highlights, { 0, 'Bold' })
+ table.insert(highlights, { hlname = 'Bold' })
end
end
@@ -1350,18 +1375,52 @@ function M.open_float(opts, ...)
end
end
+ local suffix_opt = if_nil(opts.suffix, function(diagnostic)
+ return diagnostic.code and string.format(' [%s]', diagnostic.code) or ''
+ end)
+
+ local suffix, suffix_hl_group
+ if suffix_opt then
+ vim.validate({
+ suffix = {
+ suffix_opt,
+ { 'string', 'table', 'function' },
+ "'string' or 'table' or 'function'",
+ },
+ })
+ if type(suffix_opt) == 'string' then
+ suffix, suffix_hl_group = suffix_opt, 'NormalFloat'
+ elseif type(suffix_opt) == 'table' then
+ suffix, suffix_hl_group = suffix_opt[1] or '', suffix_opt[2] or 'NormalFloat'
+ end
+ end
+
for i, diagnostic in ipairs(diagnostics) do
if prefix_opt and type(prefix_opt) == 'function' then
prefix, prefix_hl_group = prefix_opt(diagnostic, i, #diagnostics)
prefix, prefix_hl_group = prefix or '', prefix_hl_group or 'NormalFloat'
end
+ if suffix_opt and type(suffix_opt) == 'function' then
+ suffix, suffix_hl_group = suffix_opt(diagnostic, i, #diagnostics)
+ suffix, suffix_hl_group = suffix or '', suffix_hl_group or 'NormalFloat'
+ end
local hiname = floating_highlight_map[diagnostic.severity]
local message_lines = vim.split(diagnostic.message, '\n')
- table.insert(lines, prefix .. message_lines[1])
- table.insert(highlights, { #prefix, hiname, prefix_hl_group })
- for j = 2, #message_lines do
- table.insert(lines, string.rep(' ', #prefix) .. message_lines[j])
- table.insert(highlights, { 0, hiname })
+ for j = 1, #message_lines do
+ local pre = j == 1 and prefix or string.rep(' ', #prefix)
+ local suf = j == #message_lines and suffix or ''
+ table.insert(lines, pre .. message_lines[j] .. suf)
+ table.insert(highlights, {
+ hlname = hiname,
+ prefix = {
+ length = j == 1 and #prefix or 0,
+ hlname = prefix_hl_group,
+ },
+ suffix = {
+ length = j == #message_lines and #suffix or 0,
+ hlname = suffix_hl_group,
+ },
+ })
end
end
@@ -1370,12 +1429,17 @@ function M.open_float(opts, ...)
opts.focus_id = scope
end
local float_bufnr, winnr = require('vim.lsp.util').open_floating_preview(lines, 'plaintext', opts)
- for i, hi in ipairs(highlights) do
- local prefixlen, hiname, prefix_hiname = unpack(hi)
- if prefix_hiname then
- api.nvim_buf_add_highlight(float_bufnr, -1, prefix_hiname, i - 1, 0, prefixlen)
+ for i, hl in ipairs(highlights) do
+ local line = lines[i]
+ local prefix_len = hl.prefix and hl.prefix.length or 0
+ local suffix_len = hl.suffix and hl.suffix.length or 0
+ if prefix_len > 0 then
+ api.nvim_buf_add_highlight(float_bufnr, -1, hl.prefix.hlname, i - 1, 0, prefix_len)
+ end
+ api.nvim_buf_add_highlight(float_bufnr, -1, hl.hlname, i - 1, prefix_len, #line - suffix_len)
+ if suffix_len > 0 then
+ api.nvim_buf_add_highlight(float_bufnr, -1, hl.suffix.hlname, i - 1, #line - suffix_len, -1)
end
- api.nvim_buf_add_highlight(float_bufnr, -1, hiname, i - 1, prefixlen, -1)
end
return float_bufnr, winnr
@@ -1529,7 +1593,7 @@ end
---@param defaults table|nil Table of default values for any fields not listed in {groups}.
--- When omitted, numeric values default to 0 and "severity" defaults to
--- ERROR.
----@return diagnostic |diagnostic-structure| or `nil` if {pat} fails to match {str}.
+---@return Diagnostic|nil: |diagnostic-structure| or `nil` if {pat} fails to match {str}.
function M.match(str, pat, groups, severity_map, defaults)
vim.validate({
str = { str, 's' },
@@ -1576,7 +1640,7 @@ local errlist_type_map = {
--- passed to |setqflist()| or |setloclist()|.
---
---@param diagnostics table List of diagnostics |diagnostic-structure|.
----@return array of quickfix list items |setqflist-what|
+---@return table[] of quickfix list items |setqflist-what|
function M.toqflist(diagnostics)
vim.validate({
diagnostics = {
@@ -1613,7 +1677,7 @@ end
---
---@param list table A list of quickfix items from |getqflist()| or
--- |getloclist()|.
----@return array of diagnostics |diagnostic-structure|
+---@return Diagnostic[] array of |diagnostic-structure|
function M.fromqflist(list)
vim.validate({
list = {