feature: lsp_incoming_calls and lsp_outgoing_calls support for Snacks.picker
Did you check the docs?
- [X] I have read all the snacks.nvim docs
Is your feature request related to a problem? Please describe.
fzf-lua and telescope both have lsp_incoming_calls and lsp_outgoing_calls, would be great if Snacks.picker supports it as well
Describe the solution you'd like
Support lsp_incoming_calls and lsp_outgoing_calls
Describe alternatives you've considered
Just using lsp_references
Additional context
No response
This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 7 days.
This issue was closed because it has been stalled for 7 days with no activity.
DanWlker, you should probably reopen this? I dunno if @folke is interested in doing something like this though.
I am not
I'll give this a shot! 🤞
In the meantime, here is something people can add to their user config...
vim.keymap.set("n", "<leader>lc", function()
require("snacks").picker.pick {
title = "LSP Incoming Calls",
finder = function(opts, ctx)
local lsp = require "snacks.picker.source.lsp"
local Async = require "snacks.picker.util.async"
local win = ctx.filter.current_win
local buf = ctx.filter.current_buf
local bufmap = lsp.bufmap()
---@async
---@param cb async fun(item: snacks.picker.finder.Item)
return function(cb)
local async = Async.running()
local cancel = {} ---@type fun()[]
async:on(
"abort",
vim.schedule_wrap(function()
vim.tbl_map(pcall, cancel)
cancel = {}
end)
)
vim.schedule(function()
-- First prepare the call hierarchy
local clients = lsp.get_clients(buf, "textDocument/prepareCallHierarchy")
if vim.tbl_isempty(clients) then return async:resume() end
local remaining = #clients
for _, client in ipairs(clients) do
local params = vim.lsp.util.make_position_params(win, client.offset_encoding)
local status, request_id = client:request("textDocument/prepareCallHierarchy", params, function(_, result)
if result and not vim.tbl_isempty(result) then
-- Then get incoming calls for each item
local call_remaining = #result
if call_remaining == 0 then
remaining = remaining - 1
if remaining == 0 then async:resume() end
return
end
for _, item in ipairs(result) do
local call_params = { item = item }
local call_status, call_request_id = client:request(
"callHierarchy/incomingCalls",
call_params,
function(_, calls)
if calls then
for _, call in ipairs(calls) do
---@type snacks.picker.finder.Item
local item = {
text = call.from.name .. " " .. call.from.detail,
kind = lsp.symbol_kind(call.from.kind),
line = " " .. call.from.detail,
}
local loc = {
uri = call.from.uri,
range = call.from.range,
}
lsp.add_loc(item, loc, client)
item.buf = bufmap[item.file]
item.text = item.file .. " " .. call.from.detail
---@diagnostic disable-next-line: await-in-sync
cb(item)
end
end
call_remaining = call_remaining - 1
if call_remaining == 0 then
remaining = remaining - 1
if remaining == 0 then async:resume() end
end
end
)
if call_status and call_request_id then
table.insert(cancel, function() client:cancel_request(call_request_id) end)
end
end
else
remaining = remaining - 1
if remaining == 0 then async:resume() end
end
end)
if status and request_id then table.insert(cancel, function() client:cancel_request(request_id) end) end
end
end)
async:suspend()
cancel = {}
async = Async.nop()
end
end,
}
end, { desc = "LSP incoming function calls" })
This is literally the last picker I am missing. I used to use the incoming calls picker from Telescope so often, and I would love this one to be part of the Snacks collection.