Skip to content

Commit

Permalink
perf: async symbol gathering
Browse files Browse the repository at this point in the history
LSPs may return different results depending on the method being
requested.

for instance gopls will return no receiver name when a call hierarchy
request is made, but will when a workspace symbol request is made.

to work around this we make a workspace symbol request for each call
hierarchy item returned when a calltree is invoked.

this proved to be very slow when done sync so this commit makes it
async using lua coroutines.

Signed-off-by: ldelossa <[email protected]>
  • Loading branch information
ldelossa committed Nov 26, 2021
1 parent db91089 commit 8a609c1
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 11 deletions.
15 changes: 15 additions & 0 deletions doc/calltree.txt
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,21 @@ The config table is described below:
-- user provided UI highlights.
-- see *calltree-ui-highlights*
hls = {}
-- some LSP's will provide symbols with different names depending on
-- the method called.
--
-- if resolve_symbols is set to true a workspace symbol request will
-- be made for any responses from LSP's, providing clearer information
-- for symbols in the calltree.
--
-- this will cause the UI to open slower, tho the symbol requests are
-- async so it will not block the editor.
-- for full context see:
-- https://github.com/golang/go/issues/49690#issuecomment-975902067
--
-- set this to false for large codebases to speed up opening
-- the calltree.
resolve_symbols = true
}

====================================================================================
Expand Down
3 changes: 2 additions & 1 deletion lua/calltree.lua
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ M.config = {
no_hls = false,
indent_guides = true,
icon_highlights = {},
hls = {}
hls = {},
resolve_symbols = true
}

function _setup_default_highlights()
Expand Down
12 changes: 10 additions & 2 deletions lua/calltree/handlers.lua
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
local tree = require('calltree.tree.tree')
local tree_node = require('calltree.tree.node')
local lsp_util = require('calltree.lsp.util')
local config = require('calltree').config
local M = {}

local direction_map = {
Expand Down Expand Up @@ -44,11 +45,18 @@ function M.calltree_expand_handler(node, linenr, direction, ui_state)
call_hierarchy_call[direction],
call_hierarchy_call.fromRanges
)
-- try to resolve the workspace symbol for child
child.symbol = lsp_util.symbol_from_node(ui_state.active_lsp_clients, child, ui_state.calltree_buf)
table.insert(children, child)
end

if config.resolve_symbols then
lsp_util.gather_symbols_async(node, children, ui_state, function()
tree.add_node(ui_state.calltree_handle, node, children)
tree.write_tree(ui_state.calltree_handle, ui_state.calltree_buf)
ui.open_calltree()
end)
return
end

tree.add_node(ui_state.calltree_handle, node, children)
tree.write_tree(ui_state.calltree_handle, ui_state.calltree_buf)
vim.api.nvim_win_set_cursor(ui_state.calltree_win, linenr)
Expand Down
20 changes: 12 additions & 8 deletions lua/calltree/lsp/handlers.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ local tree_node = require('calltree.tree.node')
local tree = require('calltree.tree.tree')
local ui = require('calltree.ui')
local lsp_util = require('calltree.lsp.util')
local config = require('calltree').config

local M = {}

Expand All @@ -23,7 +24,7 @@ M.ch_lsp_handler = function(direction)

cur_tabpage = vim.api.nvim_win_get_tabpage(cur_win)

ui_state = ui.ui_state_registry[cur_tabpage]
ui_state = ui.ui_state_registry[cur_tabpage]
if ui_state == nil then
ui_state = {}
ui.ui_state_registry[cur_tabpage] = ui_state
Expand Down Expand Up @@ -51,9 +52,6 @@ M.ch_lsp_handler = function(direction)
ctx.params.item,
nil)

-- try to resolve the workspace symbol for root.
root.symbol = lsp_util.symbol_from_node(ui_state.active_lsp_clients, root, ui_state.invoking_calltree_win)

-- create the root's children nodes via the response array.
local children = {}
for _, call_hierarchy_call in pairs(result) do
Expand All @@ -63,14 +61,20 @@ M.ch_lsp_handler = function(direction)
call_hierarchy_call[direction],
call_hierarchy_call.fromRanges
)
-- try to resolve the workspace symbol for child
child.symbol = lsp_util.symbol_from_node(ui_state.active_lsp_clients, child, ui_state.invoking_calltree_win)
table.insert(children, child)
end

-- gather symbols async
if config.resolve_symbols then
lsp_util.gather_symbols_async(root, children, ui_state, function()
tree.add_node(ui_state.calltree_handle, root, children)
ui.open_calltree()
end)
return
end
tree.add_node(ui_state.calltree_handle, root, children)
ui.open_calltree()
end
end
end

M.ws_lsp_handler = function()
Expand All @@ -89,7 +93,7 @@ M.ws_lsp_handler = function()
ui_state = ui.ui_state_registry[cur_tabpage]
if ui_state == nil then
ui_state = {}
ui.ui_state_registry[cur_tabpage] = ui_state
ui.ui_state_registry[cur_tabpage] = ui_sate
end

-- snag the lsp clients from the buffer issuing the
Expand Down
58 changes: 58 additions & 0 deletions lua/calltree/lsp/util.lua
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,64 @@ function M.symbol_from_node(clients, node, bufnr)
return nil
end

function M.gather_symbols_async_handler(node, co)
return function(err, result, _, _)
if err ~= nil then
coroutine.resume(co, nil)
return
end

local start_line, uri = "", ""
if node.call_hierarchy_item ~= nil then
start_line = node.call_hierarchy_item.range.start.line
uri = node.call_hierarchy_item.uri
elseif node.document_symbol ~= nil then
start_line = node.document_symbol.range.start.line
uri = node.uri
end

for _, res in ipairs(result) do
if
res.location.uri == uri and
res.location.range.start.line ==
start_line
then
coroutine.resume(co, res)
return
end
end
coroutine.resume(co, nil)
end
end

function M.gather_symbols_async(root, children, ui_state, callback)
local co = nil
all_nodes = {}
table.insert(all_nodes, root)
for _, child in ipairs(children) do
table.insert(all_nodes, child)
end
co = coroutine.create(function()
for _, node in ipairs(all_nodes) do
local params = {
query = node.name,
}
print(node.name)
M.multi_client_request(
ui_state.active_lsp_clients,
"workspace/symbol",
params,
-- handler will call resume for this co.
M.gather_symbols_async_handler(node, co),
ui_state.invoking_calltree_win
)
node.symbol = coroutine.yield()
end
callback()
end)
coroutine.resume(co)
end

function M.build_recursive_symbol_tree(depth, document_symbol, parent, prev_depth_table)
local node = tree_node.new(
document_symbol.name,
Expand Down

0 comments on commit 8a609c1

Please sign in to comment.