aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/doc/diagnostic.txt4
-rw-r--r--runtime/lua/vim/diagnostic.lua136
-rw-r--r--runtime/lua/vim/lsp/diagnostic.lua11
-rw-r--r--test/functional/lua/diagnostic_spec.lua52
4 files changed, 105 insertions, 98 deletions
diff --git a/runtime/doc/diagnostic.txt b/runtime/doc/diagnostic.txt
index 9ed75e1356..199c04be98 100644
--- a/runtime/doc/diagnostic.txt
+++ b/runtime/doc/diagnostic.txt
@@ -239,7 +239,9 @@ config({opts}, {namespace}) *vim.diagnostic.config()*
• severity_sort: (default false) Sort
diagnostics by severity. This affects the
order in which signs and virtual text are
- displayed. Options:
+ displayed. When true, higher severities are
+ displayed before lower severities (e.g.
+ ERROR is displayed before WARN). Options:
• reverse: (boolean) Reverse sort order
{namespace} number|nil Update the options for the given
namespace. When omitted, update the global
diff --git a/runtime/lua/vim/diagnostic.lua b/runtime/lua/vim/diagnostic.lua
index 6547188594..1e7f95a353 100644
--- a/runtime/lua/vim/diagnostic.lua
+++ b/runtime/lua/vim/diagnostic.lua
@@ -426,6 +426,70 @@ local function set_list(loclist, opts)
end
end
+---@private
+local function next_diagnostic(position, search_forward, bufnr, opts, namespace)
+ position[1] = position[1] - 1
+ bufnr = bufnr or vim.api.nvim_get_current_buf()
+ local wrap = vim.F.if_nil(opts.wrap, true)
+ local line_count = vim.api.nvim_buf_line_count(bufnr)
+ opts.namespace = namespace
+ for i = 0, line_count do
+ local offset = i * (search_forward and 1 or -1)
+ local lnum = position[1] + offset
+ if lnum < 0 or lnum >= line_count then
+ if not wrap then
+ return
+ end
+ lnum = (lnum + line_count) % line_count
+ end
+ opts.lnum = lnum
+ local line_diagnostics = M.get(bufnr, opts)
+ if line_diagnostics and not vim.tbl_isempty(line_diagnostics) then
+ local sort_diagnostics, is_next
+ if search_forward then
+ sort_diagnostics = function(a, b) return a.col < b.col end
+ is_next = function(diagnostic) return diagnostic.col > position[2] end
+ else
+ sort_diagnostics = function(a, b) return a.col > b.col end
+ is_next = function(diagnostic) return diagnostic.col < position[2] end
+ end
+ table.sort(line_diagnostics, sort_diagnostics)
+ if i == 0 then
+ for _, v in pairs(line_diagnostics) do
+ if is_next(v) then
+ return v
+ end
+ end
+ else
+ return line_diagnostics[1]
+ end
+ end
+ end
+end
+
+---@private
+local function diagnostic_move_pos(opts, pos)
+ opts = opts or {}
+
+ local enable_popup = vim.F.if_nil(opts.enable_popup, true)
+ local win_id = opts.win_id or vim.api.nvim_get_current_win()
+
+ if not pos then
+ vim.api.nvim_echo({{"No more valid diagnostics to move to", "WarningMsg"}}, true, {})
+ return
+ end
+
+ vim.api.nvim_win_set_cursor(win_id, {pos[1] + 1, pos[2]})
+
+ if enable_popup then
+ -- This is a bit weird... I'm surprised that we need to wait til the next tick to do this.
+ vim.schedule(function()
+ M.show_position_diagnostics(opts.popup_opts, vim.api.nvim_win_get_buf(win_id))
+ end)
+ end
+end
+
+
-- }}}
-- Public API {{{
@@ -452,7 +516,9 @@ end
--- - update_in_insert: (default false) Update diagnostics in Insert mode (if false,
--- diagnostics are updated on InsertLeave)
--- - severity_sort: (default false) Sort diagnostics by severity. This affects the order in
---- which signs and virtual text are displayed. Options:
+--- which signs and virtual text are displayed. When true, higher severities
+--- are displayed before lower severities (e.g. ERROR is displayed before WARN).
+--- Options:
--- * reverse: (boolean) Reverse sort order
---@param namespace number|nil Update the options for the given namespace. When omitted, update the
--- global diagnostic options.
@@ -594,70 +660,6 @@ function M.get(bufnr, opts)
return diagnostics
end
--- Diagnostic Movements {{{
-
-local next_diagnostic = function(position, search_forward, bufnr, opts, namespace)
- position[1] = position[1] - 1
- bufnr = bufnr or vim.api.nvim_get_current_buf()
- local wrap = vim.F.if_nil(opts.wrap, true)
- local line_count = vim.api.nvim_buf_line_count(bufnr)
- opts.namespace = namespace
- for i = 0, line_count do
- local offset = i * (search_forward and 1 or -1)
- local lnum = position[1] + offset
- if lnum < 0 or lnum >= line_count then
- if not wrap then
- return
- end
- lnum = (lnum + line_count) % line_count
- end
- opts.lnum = lnum
- local line_diagnostics = M.get(bufnr, opts)
- if line_diagnostics and not vim.tbl_isempty(line_diagnostics) then
- local sort_diagnostics, is_next
- if search_forward then
- sort_diagnostics = function(a, b) return a.col < b.col end
- is_next = function(diagnostic) return diagnostic.col > position[2] end
- else
- sort_diagnostics = function(a, b) return a.col > b.col end
- is_next = function(diagnostic) return diagnostic.col < position[2] end
- end
- table.sort(line_diagnostics, sort_diagnostics)
- if i == 0 then
- for _, v in pairs(line_diagnostics) do
- if is_next(v) then
- return v
- end
- end
- else
- return line_diagnostics[1]
- end
- end
- end
-end
-
----@private
-local function diagnostic_move_pos(opts, pos)
- opts = opts or {}
-
- local enable_popup = vim.F.if_nil(opts.enable_popup, true)
- local win_id = opts.win_id or vim.api.nvim_get_current_win()
-
- if not pos then
- vim.api.nvim_echo({{"No more valid diagnostics to move to", "WarningMsg"}}, true, {})
- return
- end
-
- vim.api.nvim_win_set_cursor(win_id, {pos[1] + 1, pos[2]})
-
- if enable_popup then
- -- This is a bit weird... I'm surprised that we need to wait til the next tick to do this.
- vim.schedule(function()
- M.show_position_diagnostics(opts.popup_opts, vim.api.nvim_win_get_buf(win_id))
- end)
- end
-end
-
--- Get the previous diagnostic closest to the cursor position.
---
---@param opts table See |vim.diagnostic.goto_next()|
@@ -998,9 +1000,9 @@ function M.show(namespace, bufnr, diagnostics, opts)
if vim.F.if_nil(opts.severity_sort, false) then
if type(opts.severity_sort) == "table" and opts.severity_sort.reverse then
- table.sort(diagnostics, function(a, b) return a.severity > b.severity end)
- else
table.sort(diagnostics, function(a, b) return a.severity < b.severity end)
+ else
+ table.sort(diagnostics, function(a, b) return a.severity > b.severity end)
end
end
diff --git a/runtime/lua/vim/lsp/diagnostic.lua b/runtime/lua/vim/lsp/diagnostic.lua
index 41c8bd36ec..148836a93a 100644
--- a/runtime/lua/vim/lsp/diagnostic.lua
+++ b/runtime/lua/vim/lsp/diagnostic.lua
@@ -1,5 +1,3 @@
-local log = require('vim.lsp.log')
-
---@brief lsp-diagnostic
---
---@class Diagnostic
@@ -202,11 +200,9 @@ function M.on_publish_diagnostics(_, result, ctx, config)
end
end
end
-
- vim.diagnostic.config(config, namespace)
end
- vim.diagnostic.set(namespace, bufnr, diagnostic_lsp_to_vim(diagnostics, bufnr, client_id))
+ vim.diagnostic.set(namespace, bufnr, diagnostic_lsp_to_vim(diagnostics, bufnr, client_id), config)
-- Keep old autocmd for back compat. This should eventually be removed.
vim.api.nvim_command("doautocmd <nomodeline> User LspDiagnosticsChanged")
@@ -468,10 +464,7 @@ function M.set_signs(diagnostics, bufnr, client_id, _, opts)
opts.severity = {min=severity_lsp_to_vim(opts.severity_limit)}
end
- local ok = vim.diagnostic._set_signs(namespace, bufnr, diagnostic_lsp_to_vim(diagnostics, bufnr, client_id), opts)
- if not ok then
- log.debug("Failed to place signs:", diagnostics)
- end
+ vim.diagnostic._set_signs(namespace, bufnr, diagnostic_lsp_to_vim(diagnostics, bufnr, client_id), opts)
end
--- Set underline for given diagnostics
diff --git a/test/functional/lua/diagnostic_spec.lua b/test/functional/lua/diagnostic_spec.lua
index 3c8d6e8f2c..2971d3bc51 100644
--- a/test/functional/lua/diagnostic_spec.lua
+++ b/test/functional/lua/diagnostic_spec.lua
@@ -540,11 +540,11 @@ describe('vim.diagnostic', function()
end)
it('allows sorting by severity', function()
- local result = exec_lua([[
+ exec_lua [[
vim.diagnostic.config({
- underline = true,
- virtual_text = false,
- severity_sort = false,
+ underline = false,
+ signs = true,
+ virtual_text = true,
})
vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
@@ -553,31 +553,41 @@ describe('vim.diagnostic', function()
make_info('Info', 4, 4, 4, 4),
})
- local extmarks = vim.api.nvim_buf_get_extmarks(diagnostic_bufnr, diagnostic_ns, 0, -1, {details = true})
+ function get_virt_text_and_signs(severity_sort)
+ vim.diagnostic.config({
+ severity_sort = severity_sort,
+ })
- local warn_highlight = extmarks[1][4].hl_group
+ local virt_text = vim.api.nvim_buf_get_extmarks(diagnostic_bufnr, diagnostic_ns, 0, -1, {details = true})[1][4].virt_text
- vim.diagnostic.config({
- severity_sort = true,
- })
+ local virt_texts = {}
+ for i = 2, #virt_text do
+ table.insert(virt_texts, (string.gsub(virt_text[i][2], "DiagnosticVirtualText", "")))
+ end
- extmarks = vim.api.nvim_buf_get_extmarks(diagnostic_bufnr, diagnostic_ns, 0, -1, {details = true})
+ local signs = {}
+ for _, v in ipairs(vim.fn.sign_getplaced(diagnostic_bufnr, {group = "*"})[1].signs) do
+ table.insert(signs, (string.gsub(v.name, "DiagnosticSign", "")))
+ end
- local err_highlight = extmarks[1][4].hl_group
+ return {virt_texts, signs}
+ end
+ ]]
- vim.diagnostic.config({
- severity_sort = { reverse = true },
- })
+ local result = exec_lua [[return get_virt_text_and_signs(false)]]
- extmarks = vim.api.nvim_buf_get_extmarks(diagnostic_bufnr, diagnostic_ns, 0, -1, {details = true})
+ -- 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])
- local info_highlight = extmarks[1][4].hl_group
+ result = exec_lua [[return get_virt_text_and_signs(true)]]
+ eq({'Info', 'Warn', 'Error'}, result[1])
+ eq({'Error', 'Warn', 'Info'}, result[2])
- return { warn_highlight, err_highlight, info_highlight }
- ]])
- eq('DiagnosticUnderlineWarn', result[1])
- eq('DiagnosticUnderlineError', result[2])
- eq('DiagnosticUnderlineInfo', result[3])
+ result = exec_lua [[return get_virt_text_and_signs({ reverse = true })]]
+ eq({'Error', 'Warn', 'Info'}, result[1])
+ eq({'Info', 'Warn', 'Error'}, result[2])
end)
end)