mirror of
https://github.com/SpaceVim/SpaceVim.git
synced 2025-01-24 02:20:03 +08:00
237 lines
6.6 KiB
Lua
237 lines
6.6 KiB
Lua
local config = require("trouble.config")
|
|
local uv = vim.loop
|
|
|
|
local M = {}
|
|
|
|
function M.jump_to_item(win, precmd, item)
|
|
-- requiring here, as otherwise we run into a circular dependency
|
|
local View = require("trouble.view")
|
|
|
|
-- save position in jump list
|
|
vim.cmd("normal! m'")
|
|
|
|
View.switch_to(win)
|
|
if precmd then
|
|
vim.cmd(precmd)
|
|
end
|
|
if not vim.bo[item.bufnr].buflisted then
|
|
vim.bo[item.bufnr].buflisted = true
|
|
end
|
|
if not vim.api.nvim_buf_is_loaded(item.bufnr) then
|
|
vim.fn.bufload(item.bufnr)
|
|
end
|
|
vim.api.nvim_set_current_buf(item.bufnr)
|
|
vim.api.nvim_win_set_cursor(win or 0, { item.start.line + 1, item.start.character })
|
|
end
|
|
|
|
function M.fix_mode(opts)
|
|
if opts.use_lsp_diagnostic_signs then
|
|
opts.use_diagnostic_signs = opts.use_lsp_diagnostic_signs
|
|
M.warn("The Trouble option use_lsp_diagnostic_signs has been renamed to use_diagnostic_signs")
|
|
end
|
|
local replace = {
|
|
lsp_workspace_diagnostics = "workspace_diagnostics",
|
|
lsp_document_diagnostics = "document_diagnostics",
|
|
workspace = "workspace_diagnostics",
|
|
document = "document_diagnostics",
|
|
}
|
|
|
|
for old, new in pairs(replace) do
|
|
if opts.mode == old then
|
|
opts.mode = new
|
|
M.warn("Using " .. old .. " for Trouble is deprecated. Please use " .. new .. " instead.")
|
|
end
|
|
end
|
|
end
|
|
|
|
function M.count(tab)
|
|
local count = 0
|
|
for _ in pairs(tab) do
|
|
count = count + 1
|
|
end
|
|
return count
|
|
end
|
|
|
|
function M.warn(msg)
|
|
vim.notify(msg, vim.log.levels.WARN, { title = "Trouble" })
|
|
end
|
|
|
|
function M.error(msg)
|
|
vim.notify(msg, vim.log.levels.ERROR, { title = "Trouble" })
|
|
end
|
|
|
|
function M.debug(msg)
|
|
if config.options.debug then
|
|
vim.notify(msg, vim.log.levels.DEBUG, { title = "Trouble" })
|
|
end
|
|
end
|
|
|
|
function M.debounce(ms, fn)
|
|
local timer = vim.loop.new_timer()
|
|
return function(...)
|
|
local argv = { ... }
|
|
timer:start(ms, 0, function()
|
|
timer:stop()
|
|
vim.schedule_wrap(fn)(unpack(argv))
|
|
end)
|
|
end
|
|
end
|
|
|
|
function M.throttle(ms, fn)
|
|
local timer = vim.loop.new_timer()
|
|
local running = false
|
|
return function(...)
|
|
if not running then
|
|
local argv = { ... }
|
|
local argc = select("#", ...)
|
|
|
|
timer:start(ms, 0, function()
|
|
running = false
|
|
pcall(vim.schedule_wrap(fn), unpack(argv, 1, argc))
|
|
end)
|
|
running = true
|
|
end
|
|
end
|
|
end
|
|
|
|
M.severity = {
|
|
[0] = "Other",
|
|
[1] = "Error",
|
|
[2] = "Warning",
|
|
[3] = "Information",
|
|
[4] = "Hint",
|
|
}
|
|
|
|
-- returns a hl or sign label for the givin severity and type
|
|
-- correctly handles new names introduced in vim.diagnostic
|
|
function M.get_severity_label(severity, type)
|
|
local label = severity
|
|
local prefix = "LspDiagnostics" .. (type or "Default")
|
|
|
|
if vim.diagnostic then
|
|
prefix = type and ("Diagnostic" .. type) or "Diagnostic"
|
|
label = ({
|
|
Warning = "Warn",
|
|
Information = "Info",
|
|
})[severity] or severity
|
|
end
|
|
|
|
return prefix .. label
|
|
end
|
|
|
|
-- based on the Telescope diagnostics code
|
|
-- see https://github.com/nvim-telescope/telescope.nvim/blob/0d6cd47990781ea760dd3db578015c140c7b9fa7/lua/telescope/utils.lua#L85
|
|
|
|
function M.process_item(item, bufnr)
|
|
bufnr = bufnr or item.bufnr
|
|
local filename = vim.api.nvim_buf_get_name(bufnr)
|
|
local uri = vim.uri_from_bufnr(bufnr)
|
|
local range = item.range or item.targetSelectionRange
|
|
|
|
local start = {
|
|
line = range and vim.tbl_get(range, "start", "line") or item.lnum,
|
|
character = range and vim.tbl_get(range, "start", "character") or item.col,
|
|
}
|
|
local finish = {
|
|
line = range and vim.tbl_get(range, "end", "line") or item.end_lnum,
|
|
character = range and vim.tbl_get(range, "end", "character") or item.end_col,
|
|
}
|
|
|
|
if start.character == nil or start.line == nil then
|
|
M.error("Found an item for Trouble without start range " .. vim.inspect(start))
|
|
end
|
|
if finish.character == nil or finish.line == nil then
|
|
M.error("Found an item for Trouble without finish range " .. vim.inspect(finish))
|
|
end
|
|
local row = start.line
|
|
local col = start.character
|
|
|
|
if not item.message and filename then
|
|
-- check if the filename is a uri
|
|
if string.match(filename, "^%w+://") ~= nil then
|
|
if not vim.api.nvim_buf_is_loaded(bufnr) then
|
|
vim.fn.bufload(bufnr)
|
|
end
|
|
local lines = vim.api.nvim_buf_get_lines(bufnr, row, row + 1, false)
|
|
item.message = lines[1] or ""
|
|
else
|
|
local fd = assert(uv.fs_open(filename, "r", 438))
|
|
local stat = assert(uv.fs_fstat(fd))
|
|
local data = assert(uv.fs_read(fd, stat.size, 0))
|
|
assert(uv.fs_close(fd))
|
|
|
|
item.message = vim.split(data, "\n", { plain = true })[row + 1] or ""
|
|
end
|
|
end
|
|
|
|
---@class Item
|
|
---@field is_file boolean
|
|
---@field fixed boolean
|
|
local ret
|
|
ret = {
|
|
bufnr = bufnr,
|
|
filename = filename,
|
|
lnum = row + 1,
|
|
col = col + 1,
|
|
start = start,
|
|
finish = finish,
|
|
sign = item.sign,
|
|
sign_hl = item.sign_hl,
|
|
-- remove line break to avoid display issues
|
|
text = vim.trim(item.message:gsub("[\n]", "")):sub(0, vim.o.columns),
|
|
full_text = vim.trim(item.message),
|
|
type = M.severity[item.severity] or M.severity[0],
|
|
code = item.code or (item.user_data and item.user_data.lsp and item.user_data.lsp.code),
|
|
source = item.source,
|
|
severity = item.severity or 0,
|
|
}
|
|
return ret
|
|
end
|
|
|
|
-- takes either a table indexed by bufnr, or an lsp result with uri
|
|
---@return Item[]
|
|
function M.locations_to_items(results, default_severity)
|
|
default_severity = default_severity or 0
|
|
local ret = {}
|
|
for bufnr, locs in pairs(results or {}) do
|
|
for _, loc in pairs(locs.result or locs) do
|
|
if not vim.tbl_isempty(loc) then
|
|
local uri = loc.uri or loc.targetUri
|
|
local buf = uri and vim.uri_to_bufnr(uri) or bufnr
|
|
loc.severity = loc.severity or default_severity
|
|
table.insert(ret, M.process_item(loc, buf))
|
|
end
|
|
end
|
|
end
|
|
return ret
|
|
end
|
|
|
|
-- @private
|
|
local function make_position_param(win, buf)
|
|
local row, col = unpack(vim.api.nvim_win_get_cursor(win))
|
|
row = row - 1
|
|
local line = vim.api.nvim_buf_get_lines(buf, row, row + 1, true)[1]
|
|
if not line then
|
|
return { line = 0, character = 0 }
|
|
end
|
|
col = vim.str_utfindex(line, col)
|
|
return { line = row, character = col }
|
|
end
|
|
|
|
function M.make_text_document_params(buf)
|
|
return { uri = vim.uri_from_bufnr(buf) }
|
|
end
|
|
|
|
--- Creates a `TextDocumentPositionParams` object for the current buffer and cursor position.
|
|
---
|
|
-- @returns `TextDocumentPositionParams` object
|
|
-- @see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentPositionParams
|
|
function M.make_position_params(win, buf)
|
|
return {
|
|
textDocument = M.make_text_document_params(buf),
|
|
position = make_position_param(win, buf),
|
|
}
|
|
end
|
|
|
|
return M
|