1
0
mirror of https://github.com/SpaceVim/SpaceVim.git synced 2025-01-24 02:20:03 +08:00
SpaceVim/bundle/trouble.nvim/lua/trouble/util.lua
2023-07-01 20:30:44 +08:00

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