aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosh Rahm <rahm@google.com>2024-03-20 13:29:08 -0600
committerJosh Rahm <rahm@google.com>2024-03-20 13:29:08 -0600
commit450e0b88edd001225a1f5520106ebdbb5ff96e89 (patch)
tree9b72974b4ef22920efcdc688247b7f35298362b4
parent23b6fe0ca1c59b02b761da2ee22ffcf82a0d7991 (diff)
downloadfieldmarshal.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.
-rw-r--r--lua/diagnostic_objects.lua113
-rw-r--r--plugin/diagnostic_objects.vim33
2 files changed, 146 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
diff --git a/plugin/diagnostic_objects.vim b/plugin/diagnostic_objects.vim
new file mode 100644
index 0000000..f2ecf1b
--- /dev/null
+++ b/plugin/diagnostic_objects.vim
@@ -0,0 +1,33 @@
+" Contains object mappings for vim diagnostics.
+
+" 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
+
+if ! has('nvim')
+ " Must have neovim for this to work.
+ finish
+endif
+
+onoremap indw <cmd>lua require('diagnostic_objects').highlight_matching_diagnostic('next', 2)<cr>
+onoremap ildw <cmd>lua require('diagnostic_objects').highlight_matching_diagnostic('last', 2)<cr>
+onoremap inde <cmd>lua require('diagnostic_objects').highlight_matching_diagnostic('next', 1)<cr>
+onoremap ilde <cmd>lua require('diagnostic_objects').highlight_matching_diagnostic('last', 1)<cr>
+onoremap indi <cmd>lua require('diagnostic_objects').highlight_matching_diagnostic('next', 4)<cr>
+onoremap ildi <cmd>lua require('diagnostic_objects').highlight_matching_diagnostic('next', 4)<cr>
+onoremap inda <cmd>lua require('diagnostic_objects').highlight_matching_diagnostic('next', -1)<cr>
+onoremap ilda <cmd>lua require('diagnostic_objects').highlight_matching_diagnostic('next', -1)<cr>
+
+vnoremap indw <esc><cmd>lua require('diagnostic_objects').highlight_matching_diagnostic('next', 2)<cr>
+vnoremap ildw <esc><cmd>lua require('diagnostic_objects').highlight_matching_diagnostic('last', 2)<cr>
+vnoremap inde <esc><cmd>lua require('diagnostic_objects').highlight_matching_diagnostic('next', 1)<cr>
+vnoremap ilde <esc><cmd>lua require('diagnostic_objects').highlight_matching_diagnostic('last', 1)<cr>
+vnoremap indi <esc><cmd>lua require('diagnostic_objects').highlight_matching_diagnostic('next', 4)<cr>
+vnoremap ildi <esc><cmd>lua require('diagnostic_objects').highlight_matching_diagnostic('next', 4)<cr>
+vnoremap inda <esc><cmd>lua require('diagnostic_objects').highlight_matching_diagnostic('next', -1)<cr>
+vnoremap ilda <esc><cmd>lua require('diagnostic_objects').highlight_matching_diagnostic('next', -1)<cr>