mirror of
https://github.com/neovim/neovim.git
synced 2026-04-01 13:22:08 +00:00
feat(lsp): respect 'switchbuf' for jump commands, drop reuse_win #38510
Problem: LSP jump operations such as `buf.definition`/`buf.type_definition` do not follow the 'switchbuf' option. Instead their behavior is controlled by `vim.lsp.LocationOpts.reuse_win`. When `reuse_win=true`, the effect is very similar to `set switchbuf=useopen`. Note that functions like `buf.definition` open the quickfix window when there are multiple results, and jumping between quickfix entries already follows 'switchbuf', so unifying the behavior is more intuitive. Solution: Follow the 'switchbuf' option and drop `reuse_win`. We can achieve this behavior by using :cfirst when the quickfix list has only one item, rather than customizing the jump logic as before.
This commit is contained in:
@@ -1329,10 +1329,10 @@ the current buffer.
|
||||
*vim.lsp.ListOpts*
|
||||
|
||||
Fields: ~
|
||||
• {on_list}? (`fun(t: vim.lsp.LocationOpts.OnList)`) list-handler
|
||||
replacing the default handler. Called for any non-empty
|
||||
result. This table can be used with |setqflist()| or
|
||||
|setloclist()|. E.g.: >lua
|
||||
• {on_list}? (`fun(t: vim.lsp.ListOpts.OnList)`) list-handler replacing
|
||||
the default handler. Called for any non-empty result. This
|
||||
table can be used with |setqflist()| or |setloclist()|.
|
||||
E.g.: >lua
|
||||
local function on_list(options)
|
||||
vim.fn.setqflist({}, ' ', options)
|
||||
vim.cmd.cfirst()
|
||||
@@ -1347,15 +1347,7 @@ the current buffer.
|
||||
vim.lsp.buf.references(nil, { loclist = false })
|
||||
<
|
||||
|
||||
*vim.lsp.LocationOpts*
|
||||
Extends: |vim.lsp.ListOpts|
|
||||
|
||||
|
||||
Fields: ~
|
||||
• {reuse_win}? (`boolean`) Jump to existing window if buffer is already
|
||||
open.
|
||||
|
||||
*vim.lsp.LocationOpts.OnList*
|
||||
*vim.lsp.ListOpts.OnList*
|
||||
|
||||
Fields: ~
|
||||
• {items} (`vim.quickfix.entry[]`) See |setqflist-what|
|
||||
@@ -1429,13 +1421,13 @@ declaration({opts}) *vim.lsp.buf.declaration()*
|
||||
|vim.lsp.buf.definition()| instead.
|
||||
|
||||
Parameters: ~
|
||||
• {opts} (`vim.lsp.LocationOpts?`) See |vim.lsp.LocationOpts|.
|
||||
• {opts} (`vim.lsp.ListOpts?`) See |vim.lsp.ListOpts|.
|
||||
|
||||
definition({opts}) *vim.lsp.buf.definition()*
|
||||
Jumps to the definition of the symbol under the cursor.
|
||||
|
||||
Parameters: ~
|
||||
• {opts} (`vim.lsp.LocationOpts?`) See |vim.lsp.LocationOpts|.
|
||||
• {opts} (`vim.lsp.ListOpts?`) See |vim.lsp.ListOpts|.
|
||||
|
||||
document_highlight() *vim.lsp.buf.document_highlight()*
|
||||
Send request to the server to resolve document highlights for the current
|
||||
@@ -1521,7 +1513,7 @@ implementation({opts}) *vim.lsp.buf.implementation()*
|
||||
quickfix window.
|
||||
|
||||
Parameters: ~
|
||||
• {opts} (`vim.lsp.LocationOpts?`) See |vim.lsp.LocationOpts|.
|
||||
• {opts} (`vim.lsp.ListOpts?`) See |vim.lsp.ListOpts|.
|
||||
|
||||
incoming_calls() *vim.lsp.buf.incoming_calls()*
|
||||
Lists all the call sites of the symbol under the cursor in the |quickfix|
|
||||
@@ -1598,7 +1590,7 @@ type_definition({opts}) *vim.lsp.buf.type_definition()*
|
||||
Jumps to the definition of the type of the symbol under the cursor.
|
||||
|
||||
Parameters: ~
|
||||
• {opts} (`vim.lsp.LocationOpts?`) See |vim.lsp.LocationOpts|.
|
||||
• {opts} (`vim.lsp.ListOpts?`) See |vim.lsp.ListOpts|.
|
||||
|
||||
typehierarchy({kind}) *vim.lsp.buf.typehierarchy()*
|
||||
Lists all the subtypes or supertypes of the symbol under the cursor in the
|
||||
|
||||
@@ -58,7 +58,8 @@ The following new features were added.
|
||||
|
||||
API
|
||||
|
||||
• todo
|
||||
• |vim.lsp.buf.declaration()|, |vim.lsp.buf.definition()|, |vim.lsp.buf.definition()|,
|
||||
and |vim.lsp.buf.implementation()| now follows 'switchbuf'.
|
||||
|
||||
BUILD
|
||||
|
||||
@@ -145,7 +146,8 @@ REMOVED FEATURES *news-removed*
|
||||
|
||||
These deprecated features were removed.
|
||||
|
||||
• todo
|
||||
• |vim.lsp.buf.declaration()|, |vim.lsp.buf.definition()|, |vim.lsp.buf.definition()|,
|
||||
and |vim.lsp.buf.implementation()| no longer accept the `reuse_win` option.
|
||||
|
||||
==============================================================================
|
||||
DEPRECATIONS *news-deprecations*
|
||||
|
||||
@@ -184,9 +184,18 @@ local function request_with_opts(name, params, opts)
|
||||
end
|
||||
|
||||
---@param method vim.lsp.protocol.Method.ClientToServer.Request
|
||||
---@param opts? vim.lsp.LocationOpts
|
||||
---@param opts? vim.lsp.ListOpts
|
||||
local function get_locations(method, opts)
|
||||
opts = opts or {}
|
||||
---@diagnostic disable-next-line: undefined-field
|
||||
if opts.reuse_win then
|
||||
vim.deprecate(
|
||||
'vim.lsp.buf.<method>({ reuse_win = true })',
|
||||
"vim.lsp.buf.<method>() and the value of 'switchbuf' of preference",
|
||||
'0.13'
|
||||
)
|
||||
end
|
||||
|
||||
local bufnr = api.nvim_get_current_buf()
|
||||
local win = api.nvim_get_current_win()
|
||||
|
||||
@@ -232,39 +241,24 @@ local function get_locations(method, opts)
|
||||
return
|
||||
end
|
||||
|
||||
if #all_items == 1 then
|
||||
local item = all_items[1]
|
||||
local b = item.bufnr or vim.fn.bufadd(item.filename)
|
||||
|
||||
-- Save position in jumplist
|
||||
vim.cmd("normal! m'")
|
||||
-- Push a new item into tagstack
|
||||
local tagstack = { { tagname = tagname, from = from } }
|
||||
vim.fn.settagstack(vim.fn.win_getid(win), { items = tagstack }, 't')
|
||||
|
||||
vim.bo[b].buflisted = true
|
||||
local w = win
|
||||
if opts.reuse_win and api.nvim_win_get_buf(w) ~= b then
|
||||
w = vim.fn.bufwinid(b)
|
||||
w = w >= 0 and w or vim.fn.win_findbuf(b)[1] or win
|
||||
if w ~= win then
|
||||
api.nvim_set_current_win(w)
|
||||
end
|
||||
end
|
||||
api.nvim_win_set_buf(w, b)
|
||||
api.nvim_win_set_cursor(w, { item.lnum, item.col - 1 })
|
||||
vim._with({ win = w }, function()
|
||||
-- Open folds under the cursor
|
||||
vim.cmd('normal! zv')
|
||||
end)
|
||||
return
|
||||
end
|
||||
if opts.loclist then
|
||||
vim.fn.setloclist(0, {}, ' ', { title = title, items = all_items })
|
||||
vim.cmd.lopen()
|
||||
if #all_items == 1 then
|
||||
local tagstack = { { tagname = tagname, from = from } }
|
||||
vim.fn.settagstack(vim.fn.win_getid(win), { items = tagstack }, 't')
|
||||
vim.cmd('lfirst')
|
||||
else
|
||||
vim.cmd.lopen()
|
||||
end
|
||||
else
|
||||
vim.fn.setqflist({}, ' ', { title = title, items = all_items })
|
||||
vim.cmd('botright copen')
|
||||
if #all_items == 1 then
|
||||
local tagstack = { { tagname = tagname, from = from } }
|
||||
vim.fn.settagstack(vim.fn.win_getid(win), { items = tagstack }, 't')
|
||||
vim.cmd('cfirst')
|
||||
else
|
||||
vim.cmd('botright copen')
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
@@ -283,7 +277,7 @@ end
|
||||
--- vim.lsp.buf.definition({ on_list = on_list })
|
||||
--- vim.lsp.buf.references(nil, { on_list = on_list })
|
||||
--- ```
|
||||
--- @field on_list? fun(t: vim.lsp.LocationOpts.OnList)
|
||||
--- @field on_list? fun(t: vim.lsp.ListOpts.OnList)
|
||||
---
|
||||
--- Whether to use the |location-list| or the |quickfix| list in the default handler.
|
||||
--- ```lua
|
||||
@@ -292,33 +286,28 @@ end
|
||||
--- ```
|
||||
--- @field loclist? boolean
|
||||
|
||||
--- @class vim.lsp.LocationOpts.OnList
|
||||
--- @class vim.lsp.ListOpts.OnList
|
||||
--- @field items vim.quickfix.entry[] See |setqflist-what|
|
||||
--- @field title? string Title for the list.
|
||||
--- @field context? { bufnr: integer, method: string } Subset of `ctx` from |lsp-handler|.
|
||||
|
||||
--- @class vim.lsp.LocationOpts: vim.lsp.ListOpts
|
||||
---
|
||||
--- Jump to existing window if buffer is already open.
|
||||
--- @field reuse_win? boolean
|
||||
|
||||
--- 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.
|
||||
--- @param opts? vim.lsp.LocationOpts
|
||||
--- @param opts? vim.lsp.ListOpts
|
||||
function M.declaration(opts)
|
||||
validate('opts', opts, 'table', true)
|
||||
get_locations('textDocument/declaration', opts)
|
||||
end
|
||||
|
||||
--- Jumps to the definition of the symbol under the cursor.
|
||||
--- @param opts? vim.lsp.LocationOpts
|
||||
--- @param opts? vim.lsp.ListOpts
|
||||
function M.definition(opts)
|
||||
validate('opts', opts, 'table', true)
|
||||
get_locations('textDocument/definition', opts)
|
||||
end
|
||||
|
||||
--- Jumps to the definition of the type of the symbol under the cursor.
|
||||
--- @param opts? vim.lsp.LocationOpts
|
||||
--- @param opts? vim.lsp.ListOpts
|
||||
function M.type_definition(opts)
|
||||
validate('opts', opts, 'table', true)
|
||||
get_locations('textDocument/typeDefinition', opts)
|
||||
@@ -326,7 +315,7 @@ end
|
||||
|
||||
--- Lists all the implementations for the symbol under the cursor in the
|
||||
--- quickfix window.
|
||||
--- @param opts? vim.lsp.LocationOpts
|
||||
--- @param opts? vim.lsp.ListOpts
|
||||
function M.implementation(opts)
|
||||
validate('opts', opts, 'table', true)
|
||||
get_locations('textDocument/implementation', opts)
|
||||
|
||||
@@ -5326,7 +5326,8 @@ describe('LSP', function()
|
||||
n.feed(':vnew<CR>')
|
||||
api.nvim_win_set_buf(0, result.bufnr)
|
||||
api.nvim_win_set_cursor(0, { 3, 6 })
|
||||
n.feed(':=vim.lsp.buf.definition({ reuse_win = true })<CR>')
|
||||
n.feed(':set switchbuf=usetab<CR>')
|
||||
n.feed(':=vim.lsp.buf.definition()<CR>')
|
||||
eq(displayed_result_win, api.nvim_get_current_win())
|
||||
exec_lua(function()
|
||||
vim.lsp.get_client_by_id(result.client_id):stop()
|
||||
|
||||
Reference in New Issue
Block a user