|
|
|
@ -123,18 +123,17 @@ function M.check_capabilities(feature, client_id)
|
|
|
|
|
for _, client in pairs(clients) do
|
|
|
|
|
supported_client = client.resolved_capabilities[feature]
|
|
|
|
|
if supported_client then
|
|
|
|
|
goto continue
|
|
|
|
|
break
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
::continue::
|
|
|
|
|
if supported_client then
|
|
|
|
|
return true
|
|
|
|
|
else
|
|
|
|
|
if #clients == 0 then
|
|
|
|
|
print("LSP: no client attached")
|
|
|
|
|
log("LSP: no client attached")
|
|
|
|
|
else
|
|
|
|
|
log("LSP: server does not support " .. feature)
|
|
|
|
|
trace("LSP: server does not support " .. feature)
|
|
|
|
|
end
|
|
|
|
|
return false
|
|
|
|
|
end
|
|
|
|
@ -164,6 +163,7 @@ function M.call_async(method, params, handler)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local function ts_functions(uri)
|
|
|
|
|
local unload_bufnr
|
|
|
|
|
local ts_enabled, _ = pcall(require, "nvim-treesitter.locals")
|
|
|
|
|
if not ts_enabled or not TS_analysis_enabled then
|
|
|
|
|
lerr("ts not enabled")
|
|
|
|
@ -175,7 +175,7 @@ local function ts_functions(uri)
|
|
|
|
|
trace(ts_nodes)
|
|
|
|
|
local tsnodes = ts_nodes:get(uri)
|
|
|
|
|
if tsnodes ~= nil then
|
|
|
|
|
log("get data from cache")
|
|
|
|
|
trace("get data from cache")
|
|
|
|
|
local t = ts_nodes_time:get(uri) or 0
|
|
|
|
|
local fname = vim.uri_to_fname(uri)
|
|
|
|
|
local modified = vim.fn.getftime(fname)
|
|
|
|
@ -191,28 +191,40 @@ local function ts_functions(uri)
|
|
|
|
|
if not api.nvim_buf_is_loaded(bufnr) then
|
|
|
|
|
trace("! load buf !", uri, bufnr)
|
|
|
|
|
vim.fn.bufload(bufnr)
|
|
|
|
|
-- vim.api.nvim_buf_detach(bufnr) -- if user opens the buffer later, it prevents user attach event
|
|
|
|
|
unload = true
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local funcs = ts_func(bufnr)
|
|
|
|
|
if unload then
|
|
|
|
|
local cmd = string.format("bd %d", bufnr)
|
|
|
|
|
trace(cmd)
|
|
|
|
|
-- vim.cmd(cmd) -- todo: not sure if it is needed
|
|
|
|
|
unload_bufnr = bufnr
|
|
|
|
|
end
|
|
|
|
|
ts_nodes:set(uri, funcs)
|
|
|
|
|
ts_nodes_time:set(uri, os.time())
|
|
|
|
|
trace(funcs, ts_nodes:get(uri))
|
|
|
|
|
trace(string.format("elapsed time: %.4f\n", os.clock() - x)) -- how long it tooks
|
|
|
|
|
return funcs
|
|
|
|
|
return funcs, unload_bufnr
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local function ts_defination(uri, range)
|
|
|
|
|
local function ts_definition(uri, range)
|
|
|
|
|
local unload_bufnr
|
|
|
|
|
local ts_enabled, _ = pcall(require, "nvim-treesitter.locals")
|
|
|
|
|
if not ts_enabled or not TS_analysis_enabled then
|
|
|
|
|
lerr("ts not enabled")
|
|
|
|
|
return nil
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local key = string.format('%s_%d_%d_%d', uri, range.start.line, range.start.character,
|
|
|
|
|
range['end'].line)
|
|
|
|
|
local tsnode = ts_nodes:get(key)
|
|
|
|
|
local ftime = ts_nodes_time:get(key)
|
|
|
|
|
|
|
|
|
|
local fname = vim.uri_to_fname(uri)
|
|
|
|
|
local modified = vim.fn.getftime(fname)
|
|
|
|
|
if tsnodes and modified <= ftime then
|
|
|
|
|
log('ts def from cache')
|
|
|
|
|
return tsnode
|
|
|
|
|
end
|
|
|
|
|
local ts_def = require"navigator.treesitter".find_definition
|
|
|
|
|
local bufnr = vim.uri_to_bufnr(uri)
|
|
|
|
|
local x = os.clock()
|
|
|
|
@ -224,14 +236,14 @@ local function ts_defination(uri, range)
|
|
|
|
|
unload = true
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local def_range = ts_def(range, bufnr)
|
|
|
|
|
local def_range = ts_def(range, bufnr) or {}
|
|
|
|
|
if unload then
|
|
|
|
|
local cmd = string.format("bd %d", bufnr)
|
|
|
|
|
log(cmd)
|
|
|
|
|
-- vim.cmd(cmd) -- todo: not sure if it is needed
|
|
|
|
|
unload_bufnr = bufnr
|
|
|
|
|
end
|
|
|
|
|
trace(string.format(" ts def elapsed time: %.4f\n", os.clock() - x), def_range) -- how long it takes
|
|
|
|
|
return def_range
|
|
|
|
|
ts_nodes:set(key, def_range)
|
|
|
|
|
ts_nodes_time:set(key, x)
|
|
|
|
|
return def_range, unload_bufnr
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local function find_ts_func_by_range(funcs, range)
|
|
|
|
@ -251,15 +263,7 @@ local function find_ts_func_by_range(funcs, range)
|
|
|
|
|
return result
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function M.locations_to_items(locations)
|
|
|
|
|
if not locations or vim.tbl_isempty(locations) then
|
|
|
|
|
print("list not avalible")
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
local width = 4
|
|
|
|
|
|
|
|
|
|
local items = {} -- lsp.util.locations_to_items(locations)
|
|
|
|
|
-- items and locations may not matching
|
|
|
|
|
local function order_locations(locations)
|
|
|
|
|
table.sort(locations, function(i, j)
|
|
|
|
|
if i.uri == j.uri then
|
|
|
|
|
if i.range and i.range.start then
|
|
|
|
@ -270,9 +274,63 @@ function M.locations_to_items(locations)
|
|
|
|
|
return i.uri < j.uri
|
|
|
|
|
end
|
|
|
|
|
end)
|
|
|
|
|
return locations
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local function slice_locations(locations, max_items)
|
|
|
|
|
local cut = -1
|
|
|
|
|
if #locations > max_items then
|
|
|
|
|
local uri = locations[max_items]
|
|
|
|
|
for i = max_items + 1, #locations do
|
|
|
|
|
if uri ~= locations[i] and not brk then
|
|
|
|
|
cut = i
|
|
|
|
|
break
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
local first_part, second_part = locations, {}
|
|
|
|
|
if cut > 1 and cut < #locations then
|
|
|
|
|
first_part = vim.list_slice(locations, 1, cut)
|
|
|
|
|
second_part = vim.list_slice(locations, cut + 1, #locations)
|
|
|
|
|
end
|
|
|
|
|
return first_part, second_part
|
|
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local function test_locations()
|
|
|
|
|
local locations = {
|
|
|
|
|
{uri = '1', range = {start = {line = 1}}}, {uri = '2', range = {start = {line = 2}}},
|
|
|
|
|
{uri = '2', range = {start = {line = 3}}}, {uri = '1', range = {start = {line = 3}}},
|
|
|
|
|
{uri = '1', range = {start = {line = 4}}}, {uri = '3', range = {start = {line = 4}}},
|
|
|
|
|
{uri = '3', range = {start = {line = 4}}}
|
|
|
|
|
}
|
|
|
|
|
local second_part
|
|
|
|
|
order_locations(locations)
|
|
|
|
|
local locations, second_part = slice_locations(locations, 3)
|
|
|
|
|
log(locations, second_part)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function M.locations_to_items(locations, max_items)
|
|
|
|
|
max_items = max_items or 100000 --
|
|
|
|
|
if not locations or vim.tbl_isempty(locations) then
|
|
|
|
|
print("list not avalible")
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
local width = 4
|
|
|
|
|
|
|
|
|
|
local items = {} -- lsp.util.locations_to_items(locations)
|
|
|
|
|
-- items and locations may not matching
|
|
|
|
|
|
|
|
|
|
local uri_def = {}
|
|
|
|
|
|
|
|
|
|
order_locations(locations)
|
|
|
|
|
local second_part
|
|
|
|
|
locations, second_part = slice_locations(locations, max_items)
|
|
|
|
|
trace(locations)
|
|
|
|
|
|
|
|
|
|
local cut = -1
|
|
|
|
|
|
|
|
|
|
local unload_bufnrs = {}
|
|
|
|
|
for i, loc in ipairs(locations) do
|
|
|
|
|
local funcs = nil
|
|
|
|
|
local item = lsp.util.locations_to_items({loc})[1]
|
|
|
|
@ -286,12 +344,16 @@ function M.locations_to_items(locations)
|
|
|
|
|
end
|
|
|
|
|
-- only load top 30 file.
|
|
|
|
|
local proj_file = item.uri:find(cwd) or is_win or i < 30
|
|
|
|
|
local unload, def
|
|
|
|
|
if TS_analysis_enabled and proj_file then
|
|
|
|
|
funcs = ts_functions(item.uri)
|
|
|
|
|
funcs, unload = ts_functions(item.uri)
|
|
|
|
|
|
|
|
|
|
if uri_def[item.uri] == nil or uri_def[item.uri] == {} then
|
|
|
|
|
if unload then
|
|
|
|
|
table.insert(unload_bufnrs, unload)
|
|
|
|
|
end
|
|
|
|
|
if not uri_def[item.uri] then
|
|
|
|
|
-- find def in file
|
|
|
|
|
local def = ts_defination(item.uri, item.range)
|
|
|
|
|
def, unload = ts_definition(item.uri, item.range)
|
|
|
|
|
if def and def.start then
|
|
|
|
|
uri_def[item.uri] = def
|
|
|
|
|
if def.start then -- find for the 1st time
|
|
|
|
@ -301,6 +363,16 @@ function M.locations_to_items(locations)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
if uri_def[item.uri] == false then
|
|
|
|
|
uri_def[item.uri] = {} -- no def in file, TODO: it is tricky the definition is in another file and it is the
|
|
|
|
|
-- only occurrence
|
|
|
|
|
else
|
|
|
|
|
uri_def[item.uri] = false -- no def in file
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
if unload then
|
|
|
|
|
table.insert(unload_bufnrs, unload)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
trace(uri_def[item.uri], item.range) -- set to log if need to get all in rnge
|
|
|
|
@ -325,7 +397,19 @@ function M.locations_to_items(locations)
|
|
|
|
|
table.insert(items, item)
|
|
|
|
|
end
|
|
|
|
|
trace(uri_def)
|
|
|
|
|
return items, width + 24 -- TODO handle long line?
|
|
|
|
|
|
|
|
|
|
-- defer release new open buffer
|
|
|
|
|
if #unload_bufnrs > 10 then -- load too many?
|
|
|
|
|
vim.defer_fn(function()
|
|
|
|
|
for i, bufnr_unload in ipairs(unload_bufnrs) do
|
|
|
|
|
if api.nvim_buf_is_loaded(bufnr_unload) and i > 10 then
|
|
|
|
|
api.nvim_buf_delete(bufnr_unload, {unload = true})
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end, 100)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
return items, width + 24, second_part -- TODO handle long line?
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function M.apply_action(action_chosen)
|
|
|
|
|