Public Access
Compare commits
2
Commits
b1714279ff
...
a0341ca1c7
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a0341ca1c7 | ||
|
|
ebf5a0e8eb |
@@ -101,7 +101,7 @@ Diagnostics:
|
|||||||
- `]g`, `[g` jump to warning or error
|
- `]g`, `[g` jump to warning or error
|
||||||
- `<leader>ti` toggle inline diagnostics
|
- `<leader>ti` toggle inline diagnostics
|
||||||
- `<leader>tv` toggle virtual diagnostics
|
- `<leader>tv` toggle virtual diagnostics
|
||||||
- `<leader>xx` toggle project warnings and errors
|
- `<leader>xx`, `:ProjectDiagnostics` check the current Dart or TypeScript package and show warnings and errors in Trouble. Save modified package files first. Other languages show available LSP diagnostics; project coverage depends on the language server.
|
||||||
|
|
||||||
## Tree-sitter
|
## Tree-sitter
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ local ac = vim.api.nvim_create_autocmd
|
|||||||
local aug = vim.api.nvim_create_augroup
|
local aug = vim.api.nvim_create_augroup
|
||||||
|
|
||||||
uc("W", "w|e", { desc = "write file then refresh buffer" })
|
uc("W", "w|e", { desc = "write file then refresh buffer" })
|
||||||
|
uc("ProjectDiagnostics", require("romanzy.custom.project_diagnostics").run, { desc = "check project warnings and errors" })
|
||||||
|
|
||||||
ac("TextYankPost", {
|
ac("TextYankPost", {
|
||||||
desc = "Highlight when yanking text",
|
desc = "Highlight when yanking text",
|
||||||
|
|||||||
@@ -0,0 +1,184 @@
|
|||||||
|
local M = {}
|
||||||
|
|
||||||
|
local run_id = 0
|
||||||
|
local severities = { error = "E", warning = "W" }
|
||||||
|
local extensions = {
|
||||||
|
dart = "dart",
|
||||||
|
ts = "typescript",
|
||||||
|
tsx = "typescript",
|
||||||
|
mts = "typescript",
|
||||||
|
cts = "typescript",
|
||||||
|
js = "typescript",
|
||||||
|
jsx = "typescript",
|
||||||
|
mjs = "typescript",
|
||||||
|
cjs = "typescript",
|
||||||
|
}
|
||||||
|
|
||||||
|
local function absolute_path(root, path)
|
||||||
|
if path:sub(1, 1) == "/" then
|
||||||
|
return vim.fs.normalize(path)
|
||||||
|
end
|
||||||
|
return vim.fs.normalize(vim.fs.joinpath(root, path))
|
||||||
|
end
|
||||||
|
|
||||||
|
local function parse_output(kind, output, root)
|
||||||
|
local items = {}
|
||||||
|
for line in output:gmatch("[^\r\n]+") do
|
||||||
|
local path, row, col, level, message, code
|
||||||
|
if kind == "dart" then
|
||||||
|
level, path, row, col, message, code = line:match("^%s*(%a+)%s+%-%s+(.+):(%d+):(%d+)%s+%-%s+(.+)%s+%-%s+([%w_]+)%s*$")
|
||||||
|
else
|
||||||
|
path, row, col, level, code, message = line:match("^(.+)%((%d+),(%d+)%)%:%s*(%a+)%s+TS(%d+):%s*(.+)$")
|
||||||
|
if not path then
|
||||||
|
level, code, message = line:match("^(%a+)%s+TS(%d+):%s*(.+)$")
|
||||||
|
if level then
|
||||||
|
path, row, col = "tsconfig.json", 1, 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if path and severities[level] then
|
||||||
|
table.insert(items, {
|
||||||
|
filename = absolute_path(root, path),
|
||||||
|
lnum = tonumber(row),
|
||||||
|
col = tonumber(col),
|
||||||
|
text = message,
|
||||||
|
type = severities[level],
|
||||||
|
nr = code and tonumber(code) or nil,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return items
|
||||||
|
end
|
||||||
|
|
||||||
|
local function add_lsp_diagnostics(items, root)
|
||||||
|
local seen = {}
|
||||||
|
for _, item in ipairs(items) do
|
||||||
|
seen[table.concat({ item.filename, item.lnum, item.col, item.type, item.text }, "\0")] = true
|
||||||
|
end
|
||||||
|
local prefix = root .. "/"
|
||||||
|
for _, diagnostic in ipairs(vim.diagnostic.get()) do
|
||||||
|
local path = vim.api.nvim_buf_get_name(diagnostic.bufnr)
|
||||||
|
local kind = diagnostic.severity == vim.diagnostic.severity.ERROR and "E"
|
||||||
|
or diagnostic.severity == vim.diagnostic.severity.WARN and "W"
|
||||||
|
if kind and path:sub(1, #prefix) == prefix then
|
||||||
|
local item = {
|
||||||
|
filename = path,
|
||||||
|
lnum = diagnostic.lnum + 1,
|
||||||
|
col = diagnostic.col + 1,
|
||||||
|
text = diagnostic.message,
|
||||||
|
type = kind,
|
||||||
|
}
|
||||||
|
local key = table.concat({ item.filename, item.lnum, item.col, item.type, item.text }, "\0")
|
||||||
|
if not seen[key] then
|
||||||
|
table.insert(items, item)
|
||||||
|
seen[key] = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function show_lsp_diagnostics(bufnr)
|
||||||
|
local clients = vim.lsp.get_clients({ bufnr = bufnr })
|
||||||
|
local supported = false
|
||||||
|
for _, client in ipairs(clients) do
|
||||||
|
if client:supports_method("workspace/diagnostic") then
|
||||||
|
supported = true
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if supported then
|
||||||
|
vim.lsp.buf.workspace_diagnostics()
|
||||||
|
elseif #clients == 0 then
|
||||||
|
vim.notify("Project diagnostics: no language server is attached; showing available diagnostics", vim.log.levels.WARN)
|
||||||
|
else
|
||||||
|
vim.notify("Project diagnostics: this language server may only report opened files", vim.log.levels.WARN)
|
||||||
|
end
|
||||||
|
require("trouble").close({ mode = "qflist" })
|
||||||
|
require("trouble").open({
|
||||||
|
mode = "diagnostics",
|
||||||
|
filter = { severity = { vim.diagnostic.severity.ERROR, vim.diagnostic.severity.WARN } },
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
local function has_modified_buffers(root)
|
||||||
|
local prefix = root .. "/"
|
||||||
|
for _, bufnr in ipairs(vim.api.nvim_list_bufs()) do
|
||||||
|
local path = vim.api.nvim_buf_get_name(bufnr)
|
||||||
|
if vim.bo[bufnr].modified and path:sub(1, #prefix) == prefix then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
local function checker_for(path)
|
||||||
|
local extension = path:match("%.([^./]+)$")
|
||||||
|
local kind = extensions[extension]
|
||||||
|
if not kind then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
local marker = kind == "dart" and "pubspec.yaml" or "tsconfig.json"
|
||||||
|
local found = vim.fs.find(marker, { path = vim.fs.dirname(path), upward = true })[1]
|
||||||
|
if not found then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
local root = vim.fs.dirname(found)
|
||||||
|
if kind == "dart" then
|
||||||
|
local has_fvm = vim.fs.find({ ".fvmrc", ".fvm" }, { path = root, upward = true })[1]
|
||||||
|
local executable = has_fvm and "fvm" or "dart"
|
||||||
|
local command = has_fvm and { "fvm", "dart", "analyze" } or { "dart", "analyze" }
|
||||||
|
return kind, root, executable, command
|
||||||
|
end
|
||||||
|
local config = table.concat(vim.fn.readfile(found), "\n")
|
||||||
|
if config:find('"references"%s*:') then
|
||||||
|
return kind, root, "pnpm", { "pnpm", "exec", "tsc", "--build", "tsconfig.json", "--noEmit", "--pretty", "false" }
|
||||||
|
end
|
||||||
|
return kind, root, "pnpm", { "pnpm", "exec", "tsc", "--noEmit", "--pretty", "false", "--project", "tsconfig.json" }
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.run()
|
||||||
|
run_id = run_id + 1
|
||||||
|
local current_run = run_id
|
||||||
|
local bufnr = vim.api.nvim_get_current_buf()
|
||||||
|
local path = vim.api.nvim_buf_get_name(bufnr)
|
||||||
|
local kind, root, executable, command = checker_for(path)
|
||||||
|
if not kind then
|
||||||
|
show_lsp_diagnostics(bufnr)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
require("trouble").close({ mode = "qflist" })
|
||||||
|
if has_modified_buffers(root) then
|
||||||
|
vim.notify("Project diagnostics: save modified package files before checking", vim.log.levels.WARN)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if vim.fn.executable(executable) ~= 1 then
|
||||||
|
vim.notify("Project diagnostics: " .. executable .. " is unavailable", vim.log.levels.ERROR)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
vim.notify("Checking " .. root .. "…", vim.log.levels.INFO)
|
||||||
|
vim.system(command, { cwd = root, text = true }, function(result)
|
||||||
|
vim.schedule(function()
|
||||||
|
if current_run ~= run_id then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local output = (result.stdout or "") .. "\n" .. (result.stderr or "")
|
||||||
|
local items = parse_output(kind, output, root)
|
||||||
|
if result.code ~= 0 and #items == 0 then
|
||||||
|
vim.notify("Project diagnostics failed:\n" .. vim.trim(output), vim.log.levels.ERROR)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
add_lsp_diagnostics(items, root)
|
||||||
|
vim.fn.setqflist({}, "r", { title = "Project diagnostics: " .. root, items = items })
|
||||||
|
if #items == 0 then
|
||||||
|
require("trouble").close({ mode = "qflist" })
|
||||||
|
vim.notify("Project diagnostics: no warnings or errors", vim.log.levels.INFO)
|
||||||
|
else
|
||||||
|
require("trouble").close({ mode = "diagnostics" })
|
||||||
|
require("trouble").open({ mode = "qflist" })
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
return M
|
||||||
@@ -138,17 +138,7 @@ vim.api.nvim_create_autocmd("LspAttach", {
|
|||||||
})
|
})
|
||||||
|
|
||||||
-- diagnostics
|
-- diagnostics
|
||||||
map("n", "<leader>xx", function()
|
map("n", "<leader>xx", require("romanzy.custom.project_diagnostics").run, { desc = "check project warnings and errors" })
|
||||||
require("trouble").toggle({
|
|
||||||
mode = "diagnostics",
|
|
||||||
filter = {
|
|
||||||
severity = {
|
|
||||||
vim.diagnostic.severity.ERROR,
|
|
||||||
vim.diagnostic.severity.WARN,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
end, { desc = "toggle project warnings and errors" })
|
|
||||||
map("n", "g.", vim.diagnostic.open_float, { desc = "line diagnostics" })
|
map("n", "g.", vim.diagnostic.open_float, { desc = "line diagnostics" })
|
||||||
map("n", "gl", vim.diagnostic.setloclist, { desc = "diagnostic list" })
|
map("n", "gl", vim.diagnostic.setloclist, { desc = "diagnostic list" })
|
||||||
|
|
||||||
|
|||||||
@@ -148,9 +148,7 @@ ai.setup({})
|
|||||||
|
|
||||||
notify.setup({
|
notify.setup({
|
||||||
lsp_progress = {
|
lsp_progress = {
|
||||||
-- the message "lua_ls: processing completion..." and
|
enable = false,
|
||||||
-- "lua_ls: Diagnosing" is very annoying
|
|
||||||
-- enable = true,
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
vim.notify = notify.make_notify()
|
vim.notify = notify.make_notify()
|
||||||
|
|||||||
Reference in New Issue
Block a user