diff options
-rw-r--r-- | runtime/doc/lsp.txt | 24 | ||||
-rw-r--r-- | runtime/lua/vim/lsp/diagnostic.lua | 72 | ||||
-rw-r--r-- | runtime/lua/vim/lsp/util.lua | 44 | ||||
-rw-r--r-- | test/functional/plugin/lsp/diagnostic_spec.lua | 33 |
4 files changed, 119 insertions, 54 deletions
diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt index dd52fcf22a..531374620a 100644 --- a/runtime/doc/lsp.txt +++ b/runtime/doc/lsp.txt @@ -1196,11 +1196,16 @@ get({bufnr}, {client_id}) *vim.lsp.diagnostic.get()* diagnostics. Else, return just the diagnostics associated with the client_id. -get_all() *vim.lsp.diagnostic.get_all()* - Get all diagnostics for all clients +get_all({client_id}) *vim.lsp.diagnostic.get_all()* + Get all diagnostics for clients + + Parameters: ~ + {client_id} number Restrict included diagnostics to the + client If nil, diagnostics of all clients are + included. Return: ~ - {bufnr:Diagnostic[]} + table with diagnostics grouped by bufnr (bufnr:Diagnostic[]) *vim.lsp.diagnostic.get_count()* get_count({bufnr}, {severity}, {client_id}) @@ -1725,6 +1730,19 @@ create_file({change}) *vim.lsp.util.create_file()* delete_file({change}) *vim.lsp.util.delete_file()* TODO: Documentation + *vim.lsp.util.diagnostics_to_items()* +diagnostics_to_items({diagnostics_by_bufnr}, {predicate}) + Convert diagnostics grouped by bufnr to a list of items for + use in the quickfix or location list. + + Parameters: ~ + {diagnostics_by_bufnr} table bufnr -> Diagnostic [] + {predicate} an optional function to filter the + diagnostics. + + Return: ~ + table (A list of items) + *vim.lsp.util.extract_completion_items()* extract_completion_items({result}) Can be used to extract the completion items from a `textDocument/completion` request, which may return one of `CompletionItem[]` , `CompletionList` or null. diff --git a/runtime/lua/vim/lsp/diagnostic.lua b/runtime/lua/vim/lsp/diagnostic.lua index 06f2babde4..dabe400e0d 100644 --- a/runtime/lua/vim/lsp/diagnostic.lua +++ b/runtime/lua/vim/lsp/diagnostic.lua @@ -330,15 +330,19 @@ end -- Diagnostic Retrieval {{{ ---- Get all diagnostics for all clients +--- Get all diagnostics for clients --- ----@return {bufnr: Diagnostic[]} -function M.get_all() +---@param client_id number Restrict included diagnostics to the client +--- If nil, diagnostics of all clients are included. +---@return table with diagnostics grouped by bufnr (bufnr: Diagnostic[]) +function M.get_all(client_id) local diagnostics_by_bufnr = {} for bufnr, buf_diagnostics in pairs(diagnostic_cache) do diagnostics_by_bufnr[bufnr] = {} - for _, client_diagnostics in pairs(buf_diagnostics) do - vim.list_extend(diagnostics_by_bufnr[bufnr], client_diagnostics) + for cid, client_diagnostics in pairs(buf_diagnostics) do + if client_id == nil or cid == client_id then + vim.list_extend(diagnostics_by_bufnr[bufnr], client_diagnostics) + end end end return diagnostics_by_bufnr @@ -1162,13 +1166,6 @@ function M.show_line_diagnostics(opts, bufnr, line_nr, client_id) return popup_bufnr, winnr end -local loclist_type_map = { - [DiagnosticSeverity.Error] = 'E', - [DiagnosticSeverity.Warning] = 'W', - [DiagnosticSeverity.Information] = 'I', - [DiagnosticSeverity.Hint] = 'I', -} - --- Clear diagnotics and diagnostic cache --- @@ -1201,51 +1198,24 @@ end --- - Set the list with workspace diagnostics function M.set_loclist(opts) opts = opts or {} - local open_loclist = if_nil(opts.open_loclist, true) - - local win_id = vim.api.nvim_get_current_win() - local current_bufnr = vim.api.nvim_get_current_buf() - local diags = opts.workspace and M.get_all() or { + local current_bufnr = api.nvim_get_current_buf() + local diags = opts.workspace and M.get_all(opts.client_id) or { [current_bufnr] = M.get(current_bufnr, opts.client_id) } - - local items = {} - local insert_diag = function(bufnr, diag) - local pos = diag.range.start - local row = pos.line - - local col = util.character_offset(bufnr, row, pos.character) or 0 - - table.insert(items, { - bufnr = bufnr, - lnum = row + 1, - col = col + 1, - text = diag.message, - type = loclist_type_map[diag.severity or DiagnosticSeverity.Error] or 'E', - }) - end - - for bufnr, diagnostic in pairs(diags) do - if opts.severity then - diagnostic = filter_to_severity_limit(opts.severity, diagnostic) - elseif opts.severity_limit then - diagnostic = filter_by_severity_limit(opts.severity_limit, diagnostic) + local predicate = function(d) + local severity = to_severity(opts.severity) + if severity then + return d.severity == severity end - - for _, diag in ipairs(diagnostic) do - insert_diag(bufnr, diag) + severity = to_severity(opts.severity_limit) + if severity then + return d.severity == severity end + return true end - - table.sort(items, function(a, b) - if a.bufnr == b.bufnr then - return a.lnum < b.lnum - else - return a.bufnr < b.bufnr - end - end) - + local items = util.diagnostics_to_items(diags, predicate) + local win_id = vim.api.nvim_get_current_win() util.set_loclist(items, win_id) if open_loclist then vim.cmd [[lopen]] diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index d421a10011..cb9a7cbed5 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -30,6 +30,16 @@ local default_border = { {" ", "NormalFloat"}, } + +local DiagnosticSeverity = protocol.DiagnosticSeverity +local loclist_type_map = { + [DiagnosticSeverity.Error] = 'E', + [DiagnosticSeverity.Warning] = 'W', + [DiagnosticSeverity.Information] = 'I', + [DiagnosticSeverity.Hint] = 'I', +} + + --@private -- Check the border given by opts or the default border for the additional -- size it adds to a float. @@ -1878,6 +1888,40 @@ function M.lookup_section(settings, section) return settings end + +--- Convert diagnostics grouped by bufnr to a list of items for use in the +--- quickfix or location list. +--- +--@param diagnostics_by_bufnr table bufnr -> Diagnostic[] +--@param predicate an optional function to filter the diagnostics. +-- If present, only diagnostic items matching will be included. +--@return table (A list of items) +function M.diagnostics_to_items(diagnostics_by_bufnr, predicate) + local items = {} + for bufnr, diagnostics in pairs(diagnostics_by_bufnr or {}) do + for _, d in pairs(diagnostics) do + if not predicate or predicate(d) then + table.insert(items, { + bufnr = bufnr, + lnum = d.range.start.line + 1, + col = d.range.start.character + 1, + text = d.message, + type = loclist_type_map[d.severity or DiagnosticSeverity.Error] or 'E' + }) + end + end + end + table.sort(items, function(a, b) + if a.bufnr == b.bufnr then + return a.lnum < b.lnum + else + return a.bufnr < b.bufnr + end + end) + return items +end + + M._get_line_byte_from_position = get_line_byte_from_position M._warn_once = warn_once diff --git a/test/functional/plugin/lsp/diagnostic_spec.lua b/test/functional/plugin/lsp/diagnostic_spec.lua index 8c91c4ab2c..962028e7e1 100644 --- a/test/functional/plugin/lsp/diagnostic_spec.lua +++ b/test/functional/plugin/lsp/diagnostic_spec.lua @@ -86,6 +86,39 @@ describe('vim.lsp.diagnostic', function() eq(2, #result[1]) eq('Diagnostic #1', result[1][1].message) end) + it('Can convert diagnostic to quickfix items format', function() + local bufnr = exec_lua([[ + local fake_uri = ... + return vim.uri_to_bufnr(fake_uri) + ]], fake_uri) + local result = exec_lua([[ + local bufnr = ... + vim.lsp.diagnostic.save( + { + make_error('Diagnostic #1', 1, 1, 1, 1), + make_error('Diagnostic #2', 2, 1, 2, 1), + }, bufnr, 1 + ) + return vim.lsp.util.diagnostics_to_items(vim.lsp.diagnostic.get_all()) + ]], bufnr) + local expected = { + { + bufnr = bufnr, + col = 2, + lnum = 2, + text = 'Diagnostic #1', + type = 'E' + }, + { + bufnr = bufnr, + col = 2, + lnum = 3, + text = 'Diagnostic #2', + type = 'E' + }, + } + eq(expected, result) + end) it('should be able to save and count a single client error', function() eq(1, exec_lua [[ vim.lsp.diagnostic.save( |