diff --git a/doc/telescope.txt b/doc/telescope.txt index a38a88f..7d3713b 100644 --- a/doc/telescope.txt +++ b/doc/telescope.txt @@ -1607,6 +1607,8 @@ builtin.lsp_references({opts}) *telescope.builtin.lsp_references()* "vsplit", "never" {show_line} (boolean) show results text (default: true) {trim_text} (boolean) trim results text (default: false) + {reuse_win} (boolean) jump to existing window if buffer is + already opened (default: false) {file_encoding} (string) file encoding for the previewer diff --git a/lua/telescope/builtin/__lsp.lua b/lua/telescope/builtin/__lsp.lua index e781d24..99144c8 100644 --- a/lua/telescope/builtin/__lsp.lua +++ b/lua/telescope/builtin/__lsp.lua @@ -97,51 +97,59 @@ lsp.outgoing_calls = function(opts) calls(opts, "to") end ----@type { [string]: fun(results: table, items: table, opts: table): table, table } -local action_handlers = { - ["textDocument/references"] = function(results, items, opts) - if not opts.include_current_line then - local retresults = {} - local retitems = {} - - for i, item in pairs(items) do - if - not ( - item.filename == vim.api.nvim_buf_get_name(opts.bufnr) - and item.lnum == vim.api.nvim_win_get_cursor(opts.winnr)[1] - ) - then - table.insert(retresults, results[i]) - table.insert(retitems, items[i]) - end - end - - return retresults, retitems - end - - return results, items - end, -} - ----@param action string ----@param locations table ----@param items table ----@param opts table ----@return table results, table items -local apply_action_handler = function(action, locations, items, opts) - local handler = action_handlers[action] - if handler then - return handler(locations, items, opts) - end - - return locations, items +--- convert `item` type back to something we can pass to `vim.lsp.util.jump_to_location` +--- stopgap for pre-nvim 0.10 - after which we can simply use the `user_data` +--- field on the items in `vim.lsp.util.locations_to_items` +---@param item vim.lsp.util.locations_to_items.ret +---@param offset_encoding string|nil utf-8|utf-16|utf-32 +---@return lsp.Location +local function item_to_location(item, offset_encoding) + local line = item.lnum - 1 + local character = vim.lsp.util._str_utfindex_enc(item.text, item.col, offset_encoding) - 1 + return { + uri = vim.uri_from_fname(item.filename), + range = { + start = { + line = line, + character = character, + }, + ["end"] = { + line = line, + character = character, + }, + }, + } end ----@param action string +---@alias telescope.lsp.list_or_jump_action +---| "textDocument/references" +---| "textDocument/definition" +---| "textDocument/typeDefinition" +---| "textDocument/implementation" + +---@param action telescope.lsp.list_or_jump_action +---@param items vim.lsp.util.locations_to_items.ret[] +---@param opts table +---@return vim.lsp.util.locations_to_items.ret[] +local apply_action_handler = function(action, items, opts) + if action == "textDocument/references" and not opts.include_current_line then + local lnum = vim.api.nvim_win_get_cursor(opts.winnr)[1] + items = vim.tbl_filter(function(v) + return not (v.filename and v.lnum == lnum) + end, items) + end + + return items +end + +---@param action telescope.lsp.list_or_jump_action ---@param title string prompt title ---@param params lsp.TextDocumentPositionParams ---@param opts table local function list_or_jump(action, title, params, opts) + opts.reuse_win = vim.F.if_nil(opts.reuse_win, false) + + local curr_filepath = vim.api.nvim_buf_get_name(opts.bufnr) vim.lsp.buf_request(opts.bufnr, action, params, function(err, result, ctx, _) if err then vim.api.nvim_err_writeln("Error when executing " .. action .. " : " .. err.message) @@ -160,19 +168,16 @@ local function list_or_jump(action, title, params, opts) local offset_encoding = vim.lsp.get_client_by_id(ctx.client_id).offset_encoding local items = vim.lsp.util.locations_to_items(locations, offset_encoding) + items = apply_action_handler(action, items, opts) - locations, items = apply_action_handler(action, locations, items, opts) - - if vim.tbl_isempty(locations) then + if vim.tbl_isempty(items) then return end - if #locations == 1 and opts.jump_type ~= "never" then - local current_uri = params.textDocument.uri - local target_uri = locations[1].uri or locations[1].targetUri - if current_uri ~= target_uri then + if #items == 1 and opts.jump_type ~= "never" then + local item = items[1] + if curr_filepath ~= item.filename then local cmd - local file_path = vim.uri_to_fname(target_uri) if opts.jump_type == "tab" then cmd = "tabedit" elseif opts.jump_type == "split" then @@ -184,11 +189,12 @@ local function list_or_jump(action, title, params, opts) end if cmd then - vim.cmd(string.format("%s %s", cmd, file_path)) + vim.cmd(string.format("%s %s", cmd, item.filename)) end end - vim.lsp.util.jump_to_location(locations[1], offset_encoding, opts.reuse_win) + local location = item_to_location(item, offset_encoding) + vim.lsp.util.jump_to_location(location, offset_encoding, opts.reuse_win) else pickers .new(opts, { @@ -208,6 +214,7 @@ local function list_or_jump(action, title, params, opts) end lsp.references = function(opts) + opts.include_current_line = vim.F.if_nil(opts.include_current_line, false) local params = vim.lsp.util.make_position_params(opts.winnr) params.context = { includeDeclaration = vim.F.if_nil(opts.include_declaration, true) } return list_or_jump("textDocument/references", "LSP References", params, opts) diff --git a/lua/telescope/builtin/init.lua b/lua/telescope/builtin/init.lua index d46ff30..031eff1 100644 --- a/lua/telescope/builtin/init.lua +++ b/lua/telescope/builtin/init.lua @@ -421,6 +421,7 @@ builtin.jumplist = require_on_exported_call("telescope.builtin.__internal").jump ---@field jump_type string: how to goto reference if there is only one and the definition file is different from the current file, values: "tab", "tab drop", "split", "vsplit", "never" ---@field show_line boolean: show results text (default: true) ---@field trim_text boolean: trim results text (default: false) +---@field reuse_win boolean: jump to existing window if buffer is already opened (default: false) ---@field file_encoding string: file encoding for the previewer builtin.lsp_references = require_on_exported_call("telescope.builtin.__lsp").references