From 169c79fec945c4d9b7b62487ee160dd12a10bcb7 Mon Sep 17 00:00:00 2001 From: Manuel Coenen Date: Tue, 23 Nov 2021 14:41:37 +0100 Subject: [PATCH] feat(builtin.lsp): implement builtin handlers for lsp.(incoming|outgoing)_calls Fixes #863 --- README.md | 2 + doc/telescope.txt | 26 ++++++++++ lua/telescope/builtin/init.lua | 12 +++++ lua/telescope/builtin/lsp.lua | 90 +++++++++++++++++++++++++++++++++- 4 files changed, 128 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 814ca14a40..0a47cf42cd 100644 --- a/README.md +++ b/README.md @@ -299,6 +299,8 @@ Built-in functions. Ready to be bound to any key you like. | Functions | Description | |---------------------------------------------|---------------------------------------------------------------------------------------------------------------------------| | `builtin.lsp_references` | Lists LSP references for word under the cursor | +| `builtin.lsp_incoming_calls` | Lists LSP incoming calls for word under the cursor | +| `builtin.lsp_outgoing_calls` | Lists LSP outgoing calls for word under the cursor | | `builtin.lsp_document_symbols` | Lists LSP document symbols in the current buffer | | `builtin.lsp_workspace_symbols` | Lists LSP document symbols in the current workspace | | `builtin.lsp_dynamic_workspace_symbols` | Dynamically Lists LSP for all workspace symbols | diff --git a/doc/telescope.txt b/doc/telescope.txt index 7fc66e2920..302afbbef9 100644 --- a/doc/telescope.txt +++ b/doc/telescope.txt @@ -1463,6 +1463,32 @@ builtin.lsp_references({opts}) *telescope.builtin.lsp_references()* section (default: 30) +builtin.lsp_incoming_calls({opts}) *telescope.builtin.lsp_incoming_calls()* + Lists LSP incoming calls for word under the cursor, jumps to reference on + `` + + + Parameters: ~ + {opts} (table) options to pass to the picker + + Options: ~ + {show_line} (boolean) show results text (default: true) + {trim_text} (boolean) trim results text (default: false) + + +builtin.lsp_outgoing_calls({opts}) *telescope.builtin.lsp_outgoing_calls()* + Lists LSP outgoing calls for word under the cursor, jumps to reference on + `` + + + Parameters: ~ + {opts} (table) options to pass to the picker + + Options: ~ + {show_line} (boolean) show results text (default: true) + {trim_text} (boolean) trim results text (default: false) + + builtin.lsp_definitions({opts}) *telescope.builtin.lsp_definitions()* Goto the definition of the word under the cursor, if there's only one, otherwise show all options in Telescope diff --git a/lua/telescope/builtin/init.lua b/lua/telescope/builtin/init.lua index 69c83baaaf..0297d61e82 100644 --- a/lua/telescope/builtin/init.lua +++ b/lua/telescope/builtin/init.lua @@ -378,6 +378,18 @@ builtin.jumplist = require_on_exported_call("telescope.builtin.internal").jumpli ---@field fname_width number: defines the width of the filename section (default: 30) builtin.lsp_references = require_on_exported_call("telescope.builtin.lsp").references +--- Lists LSP incoming calls for word under the cursor, jumps to reference on `` +---@param opts table: options to pass to the picker +---@field show_line boolean: show results text (default: true) +---@field trim_text boolean: trim results text (default: false) +builtin.lsp_incoming_calls = require_on_exported_call("telescope.builtin.lsp").incoming_calls + +--- Lists LSP outgoing calls for word under the cursor, jumps to reference on `` +---@param opts table: options to pass to the picker +---@field show_line boolean: show results text (default: true) +---@field trim_text boolean: trim results text (default: false) +builtin.lsp_outgoing_calls = require_on_exported_call("telescope.builtin.lsp").outgoing_calls + --- Goto the definition of the word under the cursor, if there's only one, otherwise show all options in Telescope ---@param opts table: options to pass to the picker ---@field jump_type string: how to goto definition if there is only one, values: "tab", "split", "vsplit", "never" diff --git a/lua/telescope/builtin/lsp.lua b/lua/telescope/builtin/lsp.lua index 410a06807f..85fabb060b 100644 --- a/lua/telescope/builtin/lsp.lua +++ b/lua/telescope/builtin/lsp.lua @@ -52,9 +52,93 @@ lsp.references = function(opts) end) end -local function list_or_jump(action, title, opts) - opts = opts or {} +local function call_hierarchy(opts, method, title, direction, item) + vim.lsp.buf_request(opts.bufnr, method, { item = item }, function(err, result) + if err then + vim.api.nvim_err_writeln("Error handling " .. title .. ": " .. err) + return + end + + if not result or vim.tbl_isempty(result) then + return + end + + local locations = {} + for _, ch_call in pairs(result) do + local ch_item = ch_call[direction] + for _, range in pairs(ch_call.fromRanges) do + table.insert(locations, { + filename = vim.uri_to_fname(ch_item.uri), + text = ch_item.name, + lnum = range.start.line + 1, + col = range.start.character + 1, + }) + end + end + + pickers.new(opts, { + prompt_title = title, + finder = finders.new_table { + results = locations, + entry_maker = opts.entry_maker or make_entry.gen_from_quickfix(opts), + }, + previewer = conf.qflist_previewer(opts), + sorter = conf.generic_sorter(opts), + push_cursor_on_edit = true, + push_tagstack_on_edit = true, + }):find() + end) +end + +local function pick_call_hierarchy_item(call_hierarchy_items) + if not call_hierarchy_items then + return + end + if #call_hierarchy_items == 1 then + return call_hierarchy_items[1] + end + local items = {} + for i, item in pairs(call_hierarchy_items) do + local entry = item.detail or item.name + table.insert(items, string.format("%d. %s", i, entry)) + end + local choice = vim.fn.inputlist(items) + if choice < 1 or choice > #items then + return + end + return choice +end + +local function calls(opts, direction) + local params = vim.lsp.util.make_position_params() + vim.lsp.buf_request(opts.bufnr, "textDocument/prepareCallHierarchy", params, function(err, result) + if err then + vim.api.nvim_err_writeln("Error when preparing call hierarchy: " .. err) + return + end + + local call_hierarchy_item = pick_call_hierarchy_item(result) + if not call_hierarchy_item then + return + end + + if direction == "from" then + call_hierarchy(opts, "callHierarchy/incomingCalls", "LSP Incoming Calls", direction, call_hierarchy_item) + else + call_hierarchy(opts, "callHierarchy/outgoingCalls", "LSP Outgoing Calls", direction, call_hierarchy_item) + end + end) +end + +lsp.incoming_calls = function(opts) + calls(opts, "from") +end +lsp.outgoing_calls = function(opts) + calls(opts, "to") +end + +local function list_or_jump(action, title, opts) local params = vim.lsp.util.make_position_params(opts.winnr) vim.lsp.buf_request(opts.bufnr, action, params, function(err, result, ctx, _) if err then @@ -271,6 +355,8 @@ local feature_map = { ["type_definitions"] = "typeDefinitionProvider", ["implementations"] = "implementationProvider", ["workspace_symbols"] = "workspaceSymbolProvider", + ["incoming_calls"] = "callHierarchyProvider", + ["outgoing_calls"] = "callHierarchyProvider", } local function apply_checks(mod)