claw-code/.guardrails/ide/neovim-plugin/lua/guardrail/diagnostics.lua

123 lines
3.2 KiB
Lua

local validation = require("guardrail.validation")
local config = {}
local M = {}
local namespace = vim.api.nvim_create_namespace("guardrail")
function M.setup(cfg)
config = cfg
if config.validate_on_save then
vim.api.nvim_create_autocmd("BufWritePost", {
group = vim.api.nvim_create_augroup("Guardrail", { clear = true }),
callback = function(args)
M.validate_buffer(args.buf)
end,
})
end
end
function M.validate_buffer(bufnr)
bufnr = bufnr or vim.api.nvim_get_current_buf()
local bufname = vim.api.nvim_buf_get_name(bufnr)
if bufname == "" then
return
end
local lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, false)
local content = table.concat(lines, "\n")
local language = vim.bo[bufnr].filetype
validation.validate_file(bufname, content, language, function(result)
vim.schedule(function()
M.clear_diagnostics(bufnr)
if result.error then
vim.notify("Guardrail validation error: " .. result.error, vim.log.levels.ERROR)
return
end
local diagnostics = {}
for _, violation in ipairs(result.violations or {}) do
if M.should_report(violation.severity) then
table.insert(diagnostics, M.to_diagnostic(violation))
end
end
vim.diagnostic.set(namespace, bufnr, diagnostics)
local count = #diagnostics
if count > 0 then
vim.notify(string.format("Guardrail: Found %d violation(s)", count), vim.log.levels.WARN)
end
end)
end)
end
function M.validate_selection()
local bufnr = vim.api.nvim_get_current_buf()
local mode = vim.fn.mode()
if mode ~= "v" and mode ~= "V" then
vim.notify("No visual selection", vim.log.levels.WARN)
return
end
vim.cmd('normal! "vy')
local code = vim.fn.getreg("v")
local language = vim.bo[bufnr].filetype
validation.validate_selection(code, language, function(result)
vim.schedule(function()
if result.error then
vim.notify("Guardrail validation error: " .. result.error, vim.log.levels.ERROR)
return
end
local violations = result.violations or {}
if #violations == 0 then
vim.notify("Selection is valid", vim.log.levels.INFO)
else
local messages = {}
for _, v in ipairs(violations) do
table.insert(messages, string.format("- %s", v.message))
end
vim.notify(
string.format("Found %d violation(s):\n%s", #violations, table.concat(messages, "\n")),
vim.log.levels.WARN
)
end
end)
end)
end
function M.clear_diagnostics(bufnr)
bufnr = bufnr or vim.api.nvim_get_current_buf()
vim.diagnostic.reset(namespace, bufnr)
end
function M.to_diagnostic(violation)
local severity_map = {
error = vim.diagnostic.severity.ERROR,
warning = vim.diagnostic.severity.WARN,
info = vim.diagnostic.severity.INFO,
}
return {
lnum = violation.line - 1,
col = violation.column - 1,
message = violation.message,
severity = severity_map[violation.severity] or vim.diagnostic.severity.WARN,
source = "Guardrail",
code = violation.rule_id,
}
end
function M.should_report(severity)
local levels = { info = 1, warning = 2, error = 3 }
return (levels[severity] or 0) >= (levels[config.severity_threshold] or 1)
end
return M