From c319c800cfaa84ec31d074f9dacb91467fdfda64 Mon Sep 17 00:00:00 2001 From: Gregory Anders Date: Sat, 25 Sep 2021 09:44:02 -0600 Subject: [PATCH 1/3] test(diagnostic): add test case for signs --- test/functional/lua/diagnostic_spec.lua | 51 ++++++++++--------------- 1 file changed, 20 insertions(+), 31 deletions(-) diff --git a/test/functional/lua/diagnostic_spec.lua b/test/functional/lua/diagnostic_spec.lua index 9397af9d9f..45aa4915cd 100644 --- a/test/functional/lua/diagnostic_spec.lua +++ b/test/functional/lua/diagnostic_spec.lua @@ -874,6 +874,26 @@ describe('vim.diagnostic', function() return count_extmarks(diagnostic_bufnr, diagnostic_ns) ]]) end) + + it('sets signs', function() + local result = exec_lua [[ + vim.diagnostic.config({ + signs = true, + }) + + local diagnostics = { + make_error('Error', 1, 1, 1, 2), + make_warning('Warning', 3, 3, 3, 3), + } + + vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) + + return vim.fn.sign_getplaced(diagnostic_bufnr, {group = '*'})[1].signs + ]] + + eq({2, 'DiagnosticSignError'}, {result[1].lnum, result[1].name}) + eq({4, 'DiagnosticSignWarn'}, {result[2].lnum, result[2].name}) + end) end) describe('show_line_diagnostics()', function() @@ -995,37 +1015,6 @@ describe('vim.diagnostic', function() end) end) - describe('set_signs()', function() - -- TODO(tjdevries): Find out why signs are not displayed when set from Lua...?? - pending('sets signs by default', function() - exec_lua [[ - vim.diagnostic.config({ - update_in_insert = true, - signs = true, - }) - - local diagnostics = { - make_error('Delayed Diagnostic', 1, 1, 1, 2), - make_error('Delayed Diagnostic', 3, 3, 3, 3), - } - - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) - - vim.diagnostic._set_signs(diagnostic_ns, diagnostic_bufnr, diagnostics) - -- return vim.fn.sign_getplaced() - ]] - - nvim("input", "o") - nvim("input", "") - - -- TODO(tjdevries): Find a way to get the signs to display in the test... - eq(nil, exec_lua [[ - return im.fn.sign_getplaced()[1].signs - ]]) - end) - end) - describe('setloclist()', function() it('sets diagnostics in lnum order', function() local loc_list = exec_lua [[ From 112443995472a71e6882e449d3afc6d54d2808db Mon Sep 17 00:00:00 2001 From: Gregory Anders Date: Sat, 25 Sep 2021 09:52:20 -0600 Subject: [PATCH 2/3] docs(diagnostic): add blurb on how to replace builtin handlers --- runtime/doc/diagnostic.txt | 45 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/runtime/doc/diagnostic.txt b/runtime/doc/diagnostic.txt index 586ce02b2e..276571d042 100644 --- a/runtime/doc/diagnostic.txt +++ b/runtime/doc/diagnostic.txt @@ -201,7 +201,52 @@ DiagnosticsChanged After diagnostics have changed. Example: > autocmd User DiagnosticsChanged lua vim.diagnostic.setqflist({open = false }) < +============================================================================== +CUSTOMIZATION *diagnostic-config* +If you need more customization over the way diagnostics are displayed than the +built-in configuration options provide, you can override the display handler +explicitly. For example, use the following to only show a sign for the highest +severity diagnostic on a given line: > + + -- Disable the default signs handler + vim.diagnostic.config({signs = false}) + + -- Create a namespace. This won't be used to add any diagnostics, + -- only to display them. + local ns = vim.api.nvim_create_namespace("my_namespace") + + -- Create a reference to the original function + local orig_show = vim.diagnostic.show + + local function set_signs(bufnr) + -- Get all diagnostics from the current buffer + local diagnostics = vim.diagnostic.get(bufnr) + + -- Find the "worst" diagnostic per line + local max_severity_per_line = {} + for _, d in pairs(diagnostics) do + local m = max_severity_per_line[d.lnum] + if not m or d.severity < m.severity then + max_severity_per_line[d.lnum] = d + end + end + + -- Show the filtered diagnostics using the custom namespace. Use the + -- reference to the original function to avoid a loop. + local filtered_diagnostics = vim.tbl_values(max_severity_per_line) + orig_show(ns, bufnr, filtered_diagnostics, { + virtual_text=false, + underline=false, + signs=true + }) + end + + function vim.diagnostic.show(namespace, bufnr, ...) + orig_show(namespace, bufnr, ...) + set_signs(bufnr) + end +< ============================================================================== Lua module: vim.diagnostic *diagnostic-api* From 0f554ef6f864a723736b061ee740daf419ff94e1 Mon Sep 17 00:00:00 2001 From: Gregory Anders Date: Mon, 27 Sep 2021 07:57:53 -0700 Subject: [PATCH 3/3] refactor(diagnostics): always make 'set' go through 'show' Always make calls to `vim.diagnostic.set` call `vim.diagnostic.show`. This creates an easier to reason about code path and is also less surprising when users wish to override override `vim.diagnostic.show` with custom behavior and `vim.diagnostic.set` is called with empty diagnostics. Functionally, the end result is the same: when `show` is called with an empty diagnostics list, it just calls `hide` and then returns, which is exactly what `reset` does right now. --- runtime/lua/vim/diagnostic.lua | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/runtime/lua/vim/diagnostic.lua b/runtime/lua/vim/diagnostic.lua index 35badf8a02..c7c8c1878e 100644 --- a/runtime/lua/vim/diagnostic.lua +++ b/runtime/lua/vim/diagnostic.lua @@ -620,23 +620,22 @@ function M.set(namespace, bufnr, diagnostics, opts) } if vim.tbl_isempty(diagnostics) then - return M.reset(namespace, bufnr) + clear_diagnostic_cache(namespace, bufnr) + else + if not diagnostic_cleanup[bufnr][namespace] then + diagnostic_cleanup[bufnr][namespace] = true + + -- Clean up our data when the buffer unloads. + vim.api.nvim_buf_attach(bufnr, false, { + on_detach = function(_, b) + clear_diagnostic_cache(b, namespace) + diagnostic_cleanup[b][namespace] = nil + end + }) + end + set_diagnostic_cache(namespace, bufnr, diagnostics) end - if not diagnostic_cleanup[bufnr][namespace] then - diagnostic_cleanup[bufnr][namespace] = true - - -- Clean up our data when the buffer unloads. - vim.api.nvim_buf_attach(bufnr, false, { - on_detach = function(_, b) - clear_diagnostic_cache(b, namespace) - diagnostic_cleanup[b][namespace] = nil - end - }) - end - - set_diagnostic_cache(namespace, bufnr, diagnostics) - if vim.api.nvim_buf_is_loaded(bufnr) then M.show(namespace, bufnr, diagnostics, opts) elseif opts then