feat(lsp): option to reuse_win for jump actions (#18577)

This commit is contained in:
Lewis Russell 2022-05-18 20:03:24 +01:00 committed by GitHub
parent 03a8269e3a
commit 3eea66d65a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 73 additions and 20 deletions

View File

@ -1051,15 +1051,25 @@ completion({context}) *vim.lsp.buf.completion()*
See also: ~ See also: ~
|vim.lsp.protocol.constants.CompletionTriggerKind| |vim.lsp.protocol.constants.CompletionTriggerKind|
declaration() *vim.lsp.buf.declaration()* declaration({options}) *vim.lsp.buf.declaration()*
Jumps to the declaration of the symbol under the cursor. Jumps to the declaration of the symbol under the cursor.
Note: Note:
Many servers do not implement this method. Generally, see Many servers do not implement this method. Generally, see
|vim.lsp.buf.definition()| instead. |vim.lsp.buf.definition()| instead.
definition() *vim.lsp.buf.definition()* Parameters: ~
{options} (table|nil) additional options
• reuse_win: (boolean) Jump to existing window
if buffer is already open.
definition({options}) *vim.lsp.buf.definition()*
Jumps to the definition of the symbol under the cursor. Jumps to the definition of the symbol under the cursor.
Parameters: ~
{options} (table|nil) additional options
• reuse_win: (boolean) Jump to existing window
if buffer is already open.
document_highlight() *vim.lsp.buf.document_highlight()* document_highlight() *vim.lsp.buf.document_highlight()*
Send request to the server to resolve document highlights for Send request to the server to resolve document highlights for
the current text document position. This request can be the current text document position. This request can be
@ -1286,10 +1296,15 @@ signature_help() *vim.lsp.buf.signature_help()*
Displays signature information about the symbol under the Displays signature information about the symbol under the
cursor in a floating window. cursor in a floating window.
type_definition() *vim.lsp.buf.type_definition()* type_definition({options}) *vim.lsp.buf.type_definition()*
Jumps to the definition of the type of the symbol under the Jumps to the definition of the type of the symbol under the
cursor. cursor.
Parameters: ~
{options} (table|nil) additional options
• reuse_win: (boolean) Jump to existing window
if buffer is already open.
workspace_symbol({query}) *vim.lsp.buf.workspace_symbol()* workspace_symbol({query}) *vim.lsp.buf.workspace_symbol()*
Lists all symbols in the current workspace in the quickfix Lists all symbols in the current workspace in the quickfix
window. window.
@ -1575,12 +1590,14 @@ get_effective_tabstop({bufnr}) *vim.lsp.util.get_effective_tabstop()*
|shiftwidth| |shiftwidth|
*vim.lsp.util.jump_to_location()* *vim.lsp.util.jump_to_location()*
jump_to_location({location}, {offset_encoding}) jump_to_location({location}, {offset_encoding}, {reuse_win})
Jumps to a location. Jumps to a location.
Parameters: ~ Parameters: ~
{location} (table) (`Location`|`LocationLink`) {location} (table) (`Location`|`LocationLink`)
{offset_encoding} (string) utf-8|utf-16|utf-32 (required) {offset_encoding} (string) utf-8|utf-16|utf-32 (required)
{reuse_win} (boolean) Jump to existing window if
buffer is already opened.
Return: ~ Return: ~
`true` if the jump succeeded `true` if the jump succeeded

View File

@ -63,26 +63,45 @@ function M.hover()
request('textDocument/hover', params) request('textDocument/hover', params)
end end
---@private
local function request_with_options(name, params, options)
local req_handler
if options then
req_handler = function(err, result, ctx, config)
local client = vim.lsp.get_client_by_id(ctx.client_id)
local handler = client.handlers[name] or vim.lsp.handlers[name]
handler(err, result, ctx, vim.tbl_extend('force', config or {}, options))
end
end
request(name, params, req_handler)
end
--- Jumps to the declaration of the symbol under the cursor. --- Jumps to the declaration of the symbol under the cursor.
---@note Many servers do not implement this method. Generally, see |vim.lsp.buf.definition()| instead. ---@note Many servers do not implement this method. Generally, see |vim.lsp.buf.definition()| instead.
--- ---
function M.declaration() ---@param options table|nil additional options
--- - reuse_win: (boolean) Jump to existing window if buffer is already open.
function M.declaration(options)
local params = util.make_position_params() local params = util.make_position_params()
request('textDocument/declaration', params) request_with_options('textDocument/declaration', params, options)
end end
--- Jumps to the definition of the symbol under the cursor. --- Jumps to the definition of the symbol under the cursor.
--- ---
function M.definition() ---@param options table|nil additional options
--- - reuse_win: (boolean) Jump to existing window if buffer is already open.
function M.definition(options)
local params = util.make_position_params() local params = util.make_position_params()
request('textDocument/definition', params) request_with_options('textDocument/definition', params, options)
end end
--- Jumps to the definition of the type of the symbol under the cursor. --- Jumps to the definition of the type of the symbol under the cursor.
--- ---
function M.type_definition() ---@param options table|nil additional options
--- - reuse_win: (boolean) Jump to existing window if buffer is already open.
function M.type_definition(options)
local params = util.make_position_params() local params = util.make_position_params()
request('textDocument/typeDefinition', params) request_with_options('textDocument/typeDefinition', params, options)
end end
--- Lists all the implementations for the symbol under the cursor in the --- Lists all the implementations for the symbol under the cursor in the

View File

@ -327,18 +327,20 @@ M['textDocument/hover'] = M.hover
---@param result (table) result of LSP method; a location or a list of locations. ---@param result (table) result of LSP method; a location or a list of locations.
---@param ctx (table) table containing the context of the request, including the method ---@param ctx (table) table containing the context of the request, including the method
---(`textDocument/definition` can return `Location` or `Location[]` ---(`textDocument/definition` can return `Location` or `Location[]`
local function location_handler(_, result, ctx, _) local function location_handler(_, result, ctx, config)
if result == nil or vim.tbl_isempty(result) then if result == nil or vim.tbl_isempty(result) then
local _ = log.info() and log.info(ctx.method, 'No location found') local _ = log.info() and log.info(ctx.method, 'No location found')
return nil return nil
end end
local client = vim.lsp.get_client_by_id(ctx.client_id) local client = vim.lsp.get_client_by_id(ctx.client_id)
config = config or {}
-- textDocument/definition can return Location or Location[] -- textDocument/definition can return Location or Location[]
-- https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_definition -- https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_definition
if vim.tbl_islist(result) then if vim.tbl_islist(result) then
util.jump_to_location(result[1], client.offset_encoding) util.jump_to_location(result[1], client.offset_encoding, config.reuse_win)
if #result > 1 then if #result > 1 then
vim.fn.setqflist({}, ' ', { vim.fn.setqflist({}, ' ', {
@ -348,7 +350,7 @@ local function location_handler(_, result, ctx, _)
api.nvim_command('botright copen') api.nvim_command('botright copen')
end end
else else
util.jump_to_location(result, client.offset_encoding) util.jump_to_location(result, client.offset_encoding, config.reuse_win)
end end
end end

View File

@ -684,6 +684,16 @@ function M.text_document_completion_list_to_complete_items(result, prefix)
return matches return matches
end end
---@private
--- Like vim.fn.bufwinid except it works across tabpages.
local function bufwinid(bufnr)
for _, win in ipairs(api.nvim_list_wins()) do
if api.nvim_win_get_buf(win) == bufnr then
return win
end
end
end
--- Rename old_fname to new_fname --- Rename old_fname to new_fname
--- ---
---@param opts (table) ---@param opts (table)
@ -708,10 +718,9 @@ function M.rename(old_fname, new_fname, opts)
assert(ok, err) assert(ok, err)
local newbuf = vim.fn.bufadd(new_fname) local newbuf = vim.fn.bufadd(new_fname)
for _, win in pairs(api.nvim_list_wins()) do local win = bufwinid(oldbuf)
if api.nvim_win_get_buf(win) == oldbuf then if win then
api.nvim_win_set_buf(win, newbuf) api.nvim_win_set_buf(win, newbuf)
end
end end
api.nvim_buf_delete(oldbuf, { force = true }) api.nvim_buf_delete(oldbuf, { force = true })
end end
@ -1004,8 +1013,9 @@ end
--- ---
---@param location table (`Location`|`LocationLink`) ---@param location table (`Location`|`LocationLink`)
---@param offset_encoding string utf-8|utf-16|utf-32 (required) ---@param offset_encoding string utf-8|utf-16|utf-32 (required)
---@param reuse_win boolean Jump to existing window if buffer is already opened.
---@returns `true` if the jump succeeded ---@returns `true` if the jump succeeded
function M.jump_to_location(location, offset_encoding) function M.jump_to_location(location, offset_encoding, reuse_win)
-- location may be Location or LocationLink -- location may be Location or LocationLink
local uri = location.uri or location.targetUri local uri = location.uri or location.targetUri
if uri == nil then if uri == nil then
@ -1024,8 +1034,13 @@ function M.jump_to_location(location, offset_encoding)
vim.fn.settagstack(vim.fn.win_getid(), { items = items }, 't') vim.fn.settagstack(vim.fn.win_getid(), { items = items }, 't')
--- Jump to new location (adjusting for UTF-16 encoding of characters) --- Jump to new location (adjusting for UTF-16 encoding of characters)
api.nvim_set_current_buf(bufnr) local win = reuse_win and bufwinid(bufnr)
api.nvim_buf_set_option(bufnr, 'buflisted', true) if win then
api.nvim_set_current_win(win)
else
api.nvim_set_current_buf(bufnr)
api.nvim_buf_set_option(bufnr, 'buflisted', true)
end
local range = location.range or location.targetSelectionRange local range = location.range or location.targetSelectionRange
local row = range.start.line local row = range.start.line
local col = get_line_byte_from_position(bufnr, range.start, offset_encoding) local col = get_line_byte_from_position(bufnr, range.start, offset_encoding)