Skip to content
This repository was archived by the owner on Jul 7, 2022. It is now read-only.

Commit ce5d038

Browse files
committed
feat: Add workspace diagnostics
1 parent 25951ac commit ce5d038

File tree

2 files changed

+191
-0
lines changed

2 files changed

+191
-0
lines changed

README.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ Plug 'nvim-lua/lsp_extensions.nvim'
2020
- [Closing Labels](#closing-labels-dartls)
2121
- [Outline](#outline-dartls)
2222

23+
#### Diagnostics
24+
- [Diagnostics](#workspace-diagnostics)
25+
26+
2327
## Inlay Hints (rust-analyzer)
2428

2529
![Customized](https://i.imgur.com/FRRas1c.png)
@@ -87,6 +91,33 @@ Rendering in telescope:
8791

8892
Check out the [example file](examples/dart/outline.lua) for setup
8993

94+
## Workspace Diagnostics
95+
96+
To enable workspace diagnostics, you'll want do something like this:
97+
98+
```lua
99+
-- use the same configuration you would use for `vim.lsp.diagnostic.on_publish_diagnostics`.
100+
vim.lsp.handlers["textDocument/publishDiagnostics"] = vim.lsp.with(
101+
require('lsp_extensions.workspace.diagnostic').handler, {
102+
signs = {
103+
severity_limit = "Error",
104+
}
105+
}
106+
)
107+
```
108+
109+
To use workspace diagnostics, you can do some of the following:
110+
111+
```lua
112+
-- Get the counts from your curreent workspace:
113+
local ws_errors = require('lsp_extensions.workspace.diagnostic').get_count(0, 'Error')
114+
local ws_hints = require('lsp_extensions.workspace.diagnostic').get_count(0, 'Hint')
115+
116+
-- Set the qflist for the current workspace
117+
-- For more information, see `:help vim.lsp.diagnostic.set_loc_list()`, since this has some of the same configuration.
118+
require('lsp_extensions.workspace.diagnostic').set_qf_list()
119+
```
120+
90121
## Clips
91122

92123
- Showing Line Diagnostics: https://clips.twitch.tv/ProductiveBoxyPastaCoolStoryBro
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
local protocol = vim.lsp.protocol
2+
local if_nil = vim.F.if_nil
3+
4+
local DiagnosticSeverity = protocol.DiagnosticSeverity
5+
6+
local loclist_type_map = {
7+
[DiagnosticSeverity.Error] = 'E',
8+
[DiagnosticSeverity.Warning] = 'W',
9+
[DiagnosticSeverity.Information] = 'I',
10+
[DiagnosticSeverity.Hint] = 'I',
11+
}
12+
13+
local to_severity = function(severity)
14+
if not severity then return nil end
15+
return type(severity) == 'string' and DiagnosticSeverity[severity] or severity
16+
end
17+
18+
local filter_to_severity_limit = function(severity, diagnostics)
19+
local filter_level = to_severity(severity)
20+
if not filter_level then
21+
return diagnostics
22+
end
23+
24+
return vim.tbl_filter(function(t) return t.severity == filter_level end, diagnostics)
25+
end
26+
27+
local filter_by_severity_limit = function(severity_limit, diagnostics)
28+
local filter_level = to_severity(severity_limit)
29+
if not filter_level then
30+
return diagnostics
31+
end
32+
33+
return vim.tbl_filter(function(t) return t.severity <= filter_level end, diagnostics)
34+
end
35+
36+
-- Keep it as a global so it stays between reloads, caches and exposed to view.
37+
_LspExtensionsWorkspaceCache = _LspExtensionsWorkspaceCache or {}
38+
39+
local M = {}
40+
41+
-- { client: stuff }
42+
M.diagnostic_cache = _LspExtensionsWorkspaceCache
43+
44+
M.handler = function(err, method, result, client_id, bufnr, config)
45+
vim.lsp.diagnostic.on_publish_diagnostics(err, method, result, client_id, bufnr, config)
46+
47+
if not result then return end
48+
49+
bufnr = bufnr or vim.uri_to_bufnr(result.uri)
50+
51+
if not M.diagnostic_cache[client_id] then
52+
M.diagnostic_cache[client_id] = {}
53+
end
54+
55+
local diagnostics = result.diagnostics
56+
57+
local counts = {}
58+
for _, severity in ipairs(DiagnosticSeverity) do
59+
counts[to_severity(severity)] = vim.lsp.diagnostic.get_count(bufnr, severity, client_id)
60+
end
61+
62+
63+
M.diagnostic_cache[client_id][bufnr] = {
64+
diagnostics = diagnostics,
65+
counts = counts,
66+
}
67+
end
68+
69+
M.get_count = function(bufnr, severity)
70+
if bufnr == 0 or not bufnr then
71+
bufnr = vim.api.nvim_get_current_buf()
72+
end
73+
74+
severity = to_severity(severity)
75+
76+
local count = 0
77+
local clients = vim.lsp.buf_get_clients(bufnr)
78+
79+
for client_id, _ in pairs(clients) do
80+
for _, diagnostic_cache in pairs(M.diagnostic_cache[client_id] or {}) do
81+
if diagnostic_cache.counts then
82+
count = count + diagnostic_cache.counts[severity]
83+
end
84+
end
85+
end
86+
87+
return count
88+
end
89+
90+
M.set_qf_list = function(opts)
91+
opts = opts or {}
92+
93+
local open_qflist = if_nil(opts.open_qflist, true)
94+
95+
local bufnr = vim.api.nvim_get_current_buf()
96+
local diags_by_buffer = M.get(bufnr)
97+
98+
for diag_bufnr, diags in pairs(diags_by_buffer) do
99+
if opts.severity then
100+
diags_by_buffer[diag_bufnr] = filter_to_severity_limit(opts.severity, diags)
101+
elseif opts.severity_limit then
102+
diags_by_buffer[diag_bufnr] = filter_by_severity_limit(opts.severity_limit, diags)
103+
end
104+
end
105+
106+
-- P(diags_by_buffer)
107+
-- if true then return end
108+
109+
local item_list = {}
110+
111+
local insert_diag = function(diag_bufnr, diag)
112+
local pos = diag.range.start
113+
local row = pos.line
114+
115+
local col_ok, col = pcall(vim.lsp.util.character_offset, bufnr, row, pos.character)
116+
if not col_ok then
117+
col = pos.character
118+
end
119+
120+
local line = (vim.api.nvim_buf_get_lines(bufnr, row, row + 1, false) or {""})[1] or ""
121+
122+
table.insert(item_list, {
123+
bufnr = diag_bufnr,
124+
lnum = row + 1,
125+
col = col + 1,
126+
text = line .. " | " .. diag.message,
127+
type = loclist_type_map[diag.severity or DiagnosticSeverity.Error] or 'E',
128+
})
129+
end
130+
131+
for diag_bufnr, diags in pairs(diags_by_buffer) do
132+
for _, v in ipairs(diags) do
133+
insert_diag(diag_bufnr, v)
134+
end
135+
end
136+
137+
vim.fn.setqflist({}, 'r', { title = 'LSP Diagnostics'; items = item_list; })
138+
139+
if open_qflist then
140+
vim.cmd [[copen]]
141+
end
142+
end
143+
144+
function M.get(bufnr)
145+
local result = {}
146+
147+
for client_id, _ in pairs(vim.lsp.buf_get_clients(bufnr)) do
148+
for diag_bufnr, diag_cache in pairs(M.diagnostic_cache[client_id] or {}) do
149+
if not result[diag_bufnr] then
150+
result[diag_bufnr] = {}
151+
end
152+
153+
vim.list_extend(result[diag_bufnr], diag_cache.diagnostics or {})
154+
end
155+
end
156+
157+
return result
158+
end
159+
160+
return M

0 commit comments

Comments
 (0)