diff options
author | Josh Rahm <rahm@google.com> | 2024-03-20 13:29:08 -0600 |
---|---|---|
committer | Josh Rahm <rahm@google.com> | 2024-03-20 13:29:08 -0600 |
commit | 450e0b88edd001225a1f5520106ebdbb5ff96e89 (patch) | |
tree | 9b72974b4ef22920efcdc688247b7f35298362b4 /lua | |
parent | 23b6fe0ca1c59b02b761da2ee22ffcf82a0d7991 (diff) | |
download | fieldmarshal.vim-450e0b88edd001225a1f5520106ebdbb5ff96e89.tar.gz fieldmarshal.vim-450e0b88edd001225a1f5520106ebdbb5ff96e89.tar.bz2 fieldmarshal.vim-450e0b88edd001225a1f5520106ebdbb5ff96e89.zip |
Implement diagnostic objects.
Follows the pattern:
i[nl]d[wei] for next/last diagnostic warning/error/info.
Diffstat (limited to 'lua')
-rw-r--r-- | lua/diagnostic_objects.lua | 113 |
1 files changed, 113 insertions, 0 deletions
diff --git a/lua/diagnostic_objects.lua b/lua/diagnostic_objects.lua new file mode 100644 index 0000000..f0fbf97 --- /dev/null +++ b/lua/diagnostic_objects.lua @@ -0,0 +1,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 |