1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
|
-- Contains object mappings for vim diagnostics.
local vim = assert(vim)
-- indw: next diagnostic warning
-- ildw: last diagnostic warning
-- inde: next diagnostic error
-- ilde: last diagnostic error
-- indi: next diagnostic info
-- ildi: last diagnostic info
-- inda: next any diagnostic
-- ilda: last any diagnostic
local M = {}
local function compare_pos(diag, pos)
if diag.lnum + 1 < pos[1] then
return -1
end
if diag.lnum + 1 > pos[1] then
return 1
end
if diag.col > pos[1] then
return 1
end
if diag.col < pos[1] then
return -1
end
return 0
end
function M.get_matching_diagnostic(last_or_next, severity)
local current_pos = vim.api.nvim_win_get_cursor(0)
local bufnr = vim.api.nvim_get_current_buf()
local all_diagnostics = vim.diagnostic.get(bufnr)
local all_matching_diagnostics = {}
for _, diag in pairs(all_diagnostics) do
if diag.severity == severity or severity == -1 then
table.insert(all_matching_diagnostics, diag)
end
end
local last_matching_diag = nil
for _, diag in ipairs(all_matching_diagnostics) do
if compare_pos(diag, current_pos) < 0 then
if (severity == -1 or diag.severity == severity) and last_or_next ~= 'next' then
last_matching_diag = diag
end
elseif compare_pos(diag, current_pos) > 0 then
if last_or_next ~= 'next' then
break
end
if (severity == -1 or diag.severity == severity) then
last_matching_diag = diag
break
end
end
end
if not last_matching_diag and #all_matching_diagnostics > 0 then
if last_or_next == 'next' then
last_matching_diag = all_matching_diagnostics[1]
else
last_matching_diag = all_matching_diagnostics[-1]
end
end
return last_matching_diag
end
local function normalize_position(diag)
local lnum = diag.lnum + 1
local elnum = math.max(diag.end_lnum + 1, lnum)
local col = math.max(diag.col, 0)
local ecol = diag.end_col
if elnum == lnum then
ecol = math.max(col, ecol)
end
return lnum, col, elnum, ecol
end
function M.highlight_matching_diagnostic(last_or_next, severity)
local diag = M.get_matching_diagnostic(last_or_next, severity)
if diag then
local l, c, el, ec = normalize_position(diag);
-- col, lnum, end_col, end_lnum
vim.api.nvim_win_set_cursor(0, { l, c })
if l == el and c == ec and vim.v.operator:match('[cd]') then
-- hack to get zero-width matches to work.
vim.cmd("normal! i ")
end
vim.cmd("normal! v")
vim.api.nvim_win_set_cursor(0, { el, ec })
else
vim.fn.feedkeys('')
end
end
return M
|