Skip to content

Commit 8a609c1

Browse files
committed
perf: async symbol gathering
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 <louis.delos@gmail.com>
1 parent db91089 commit 8a609c1

File tree

5 files changed

+97
-11
lines changed

5 files changed

+97
-11
lines changed

doc/calltree.txt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,21 @@ The config table is described below:
204204
-- user provided UI highlights.
205205
-- see *calltree-ui-highlights*
206206
hls = {}
207+
-- some LSP's will provide symbols with different names depending on
208+
-- the method called.
209+
--
210+
-- if resolve_symbols is set to true a workspace symbol request will
211+
-- be made for any responses from LSP's, providing clearer information
212+
-- for symbols in the calltree.
213+
--
214+
-- this will cause the UI to open slower, tho the symbol requests are
215+
-- async so it will not block the editor.
216+
-- for full context see:
217+
-- https://github.com/golang/go/issues/49690#issuecomment-975902067
218+
--
219+
-- set this to false for large codebases to speed up opening
220+
-- the calltree.
221+
resolve_symbols = true
207222
}
208223

209224
====================================================================================

lua/calltree.lua

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ M.config = {
1010
no_hls = false,
1111
indent_guides = true,
1212
icon_highlights = {},
13-
hls = {}
13+
hls = {},
14+
resolve_symbols = true
1415
}
1516

1617
function _setup_default_highlights()

lua/calltree/handlers.lua

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
local tree = require('calltree.tree.tree')
22
local tree_node = require('calltree.tree.node')
33
local lsp_util = require('calltree.lsp.util')
4+
local config = require('calltree').config
45
local M = {}
56

67
local direction_map = {
@@ -44,11 +45,18 @@ function M.calltree_expand_handler(node, linenr, direction, ui_state)
4445
call_hierarchy_call[direction],
4546
call_hierarchy_call.fromRanges
4647
)
47-
-- try to resolve the workspace symbol for child
48-
child.symbol = lsp_util.symbol_from_node(ui_state.active_lsp_clients, child, ui_state.calltree_buf)
4948
table.insert(children, child)
5049
end
5150

51+
if config.resolve_symbols then
52+
lsp_util.gather_symbols_async(node, children, ui_state, function()
53+
tree.add_node(ui_state.calltree_handle, node, children)
54+
tree.write_tree(ui_state.calltree_handle, ui_state.calltree_buf)
55+
ui.open_calltree()
56+
end)
57+
return
58+
end
59+
5260
tree.add_node(ui_state.calltree_handle, node, children)
5361
tree.write_tree(ui_state.calltree_handle, ui_state.calltree_buf)
5462
vim.api.nvim_win_set_cursor(ui_state.calltree_win, linenr)

lua/calltree/lsp/handlers.lua

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ local tree_node = require('calltree.tree.node')
22
local tree = require('calltree.tree.tree')
33
local ui = require('calltree.ui')
44
local lsp_util = require('calltree.lsp.util')
5+
local config = require('calltree').config
56

67
local M = {}
78

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

2425
cur_tabpage = vim.api.nvim_win_get_tabpage(cur_win)
2526

26-
ui_state = ui.ui_state_registry[cur_tabpage]
27+
ui_state = ui.ui_state_registry[cur_tabpage]
2728
if ui_state == nil then
2829
ui_state = {}
2930
ui.ui_state_registry[cur_tabpage] = ui_state
@@ -51,9 +52,6 @@ M.ch_lsp_handler = function(direction)
5152
ctx.params.item,
5253
nil)
5354

54-
-- try to resolve the workspace symbol for root.
55-
root.symbol = lsp_util.symbol_from_node(ui_state.active_lsp_clients, root, ui_state.invoking_calltree_win)
56-
5755
-- create the root's children nodes via the response array.
5856
local children = {}
5957
for _, call_hierarchy_call in pairs(result) do
@@ -63,14 +61,20 @@ M.ch_lsp_handler = function(direction)
6361
call_hierarchy_call[direction],
6462
call_hierarchy_call.fromRanges
6563
)
66-
-- try to resolve the workspace symbol for child
67-
child.symbol = lsp_util.symbol_from_node(ui_state.active_lsp_clients, child, ui_state.invoking_calltree_win)
6864
table.insert(children, child)
6965
end
7066

67+
-- gather symbols async
68+
if config.resolve_symbols then
69+
lsp_util.gather_symbols_async(root, children, ui_state, function()
70+
tree.add_node(ui_state.calltree_handle, root, children)
71+
ui.open_calltree()
72+
end)
73+
return
74+
end
7175
tree.add_node(ui_state.calltree_handle, root, children)
7276
ui.open_calltree()
73-
end
77+
end
7478
end
7579

7680
M.ws_lsp_handler = function()
@@ -89,7 +93,7 @@ M.ws_lsp_handler = function()
8993
ui_state = ui.ui_state_registry[cur_tabpage]
9094
if ui_state == nil then
9195
ui_state = {}
92-
ui.ui_state_registry[cur_tabpage] = ui_state
96+
ui.ui_state_registry[cur_tabpage] = ui_sate
9397
end
9498

9599
-- snag the lsp clients from the buffer issuing the

lua/calltree/lsp/util.lua

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,64 @@ function M.symbol_from_node(clients, node, bufnr)
157157
return nil
158158
end
159159

160+
function M.gather_symbols_async_handler(node, co)
161+
return function(err, result, _, _)
162+
if err ~= nil then
163+
coroutine.resume(co, nil)
164+
return
165+
end
166+
167+
local start_line, uri = "", ""
168+
if node.call_hierarchy_item ~= nil then
169+
start_line = node.call_hierarchy_item.range.start.line
170+
uri = node.call_hierarchy_item.uri
171+
elseif node.document_symbol ~= nil then
172+
start_line = node.document_symbol.range.start.line
173+
uri = node.uri
174+
end
175+
176+
for _, res in ipairs(result) do
177+
if
178+
res.location.uri == uri and
179+
res.location.range.start.line ==
180+
start_line
181+
then
182+
coroutine.resume(co, res)
183+
return
184+
end
185+
end
186+
coroutine.resume(co, nil)
187+
end
188+
end
189+
190+
function M.gather_symbols_async(root, children, ui_state, callback)
191+
local co = nil
192+
all_nodes = {}
193+
table.insert(all_nodes, root)
194+
for _, child in ipairs(children) do
195+
table.insert(all_nodes, child)
196+
end
197+
co = coroutine.create(function()
198+
for _, node in ipairs(all_nodes) do
199+
local params = {
200+
query = node.name,
201+
}
202+
print(node.name)
203+
M.multi_client_request(
204+
ui_state.active_lsp_clients,
205+
"workspace/symbol",
206+
params,
207+
-- handler will call resume for this co.
208+
M.gather_symbols_async_handler(node, co),
209+
ui_state.invoking_calltree_win
210+
)
211+
node.symbol = coroutine.yield()
212+
end
213+
callback()
214+
end)
215+
coroutine.resume(co)
216+
end
217+
160218
function M.build_recursive_symbol_tree(depth, document_symbol, parent, prev_depth_table)
161219
local node = tree_node.new(
162220
document_symbol.name,

0 commit comments

Comments
 (0)