mirror of
https://github.com/neovim/neovim.git
synced 2025-10-21 01:02:09 +00:00
feat(lsp): vim.lsp.inline_completion on_accept #35507
This commit is contained in:
@@ -11,11 +11,11 @@ local M = {}
|
||||
|
||||
local namespace = api.nvim_create_namespace('nvim.lsp.inline_completion')
|
||||
|
||||
---@class (private) vim.lsp.inline_completion.CurrentItem
|
||||
---@field index integer The index among all items form all clients.
|
||||
---@class vim.lsp.inline_completion.Item
|
||||
---@field _index integer The index among all items form all clients.
|
||||
---@field client_id integer Client ID
|
||||
---@field insert_text string|lsp.StringValue The text to be inserted, can be a snippet.
|
||||
---@field filter_text? string
|
||||
---@field _filter_text? string
|
||||
---@field range? vim.Range Which range it be applied.
|
||||
---@field command? lsp.Command Corresponding server command.
|
||||
|
||||
@@ -25,7 +25,7 @@ local namespace = api.nvim_create_namespace('nvim.lsp.inline_completion')
|
||||
---@class (private) vim.lsp.inline_completion.Completor : vim.lsp.Capability
|
||||
---@field active table<integer, vim.lsp.inline_completion.Completor?>
|
||||
---@field timer? uv.uv_timer_t Timer for debouncing automatic requests
|
||||
---@field current? vim.lsp.inline_completion.CurrentItem Currently selected item
|
||||
---@field current? vim.lsp.inline_completion.Item Currently selected item
|
||||
---@field client_state table<integer, vim.lsp.inline_completion.ClientState>
|
||||
local Completor = {
|
||||
name = 'inline_completion',
|
||||
@@ -146,11 +146,11 @@ function Completor:select(index, show_index)
|
||||
local client = assert(vim.lsp.get_client_by_id(client_id))
|
||||
local range = item.range and vim.range.lsp(self.bufnr, item.range, client.offset_encoding)
|
||||
self.current = {
|
||||
index = index,
|
||||
_index = index,
|
||||
client_id = client_id,
|
||||
insert_text = item.insertText,
|
||||
range = range,
|
||||
filter_text = item.filterText,
|
||||
_filter_text = item.filterText,
|
||||
command = item.command,
|
||||
}
|
||||
|
||||
@@ -281,19 +281,14 @@ function Completor:abort()
|
||||
self.current = nil
|
||||
end
|
||||
|
||||
--- Apply the current completion item to the buffer.
|
||||
--- Accept the current completion item to the buffer.
|
||||
---
|
||||
---@package
|
||||
function Completor:apply()
|
||||
local current = self.current
|
||||
self:abort()
|
||||
if not current then
|
||||
return
|
||||
end
|
||||
|
||||
local insert_text = current.insert_text
|
||||
---@param item vim.lsp.inline_completion.Item
|
||||
function Completor:accept(item)
|
||||
local insert_text = item.insert_text
|
||||
if type(insert_text) == 'string' then
|
||||
local range = current.range
|
||||
local range = item.range
|
||||
if range then
|
||||
local lines = vim.split(insert_text, '\n')
|
||||
api.nvim_buf_set_text(
|
||||
@@ -304,7 +299,7 @@ function Completor:apply()
|
||||
range.end_.col,
|
||||
lines
|
||||
)
|
||||
local pos = range.start:to_cursor()
|
||||
local pos = item.range.start:to_cursor()
|
||||
api.nvim_win_set_cursor(vim.fn.bufwinid(self.bufnr), {
|
||||
pos[1] + #lines - 1,
|
||||
(#lines == 1 and pos[2] or 0) + #lines[#lines],
|
||||
@@ -317,9 +312,9 @@ function Completor:apply()
|
||||
end
|
||||
|
||||
-- Execute the command *after* inserting this completion.
|
||||
if current.command then
|
||||
local client = assert(vim.lsp.get_client_by_id(current.client_id))
|
||||
client:exec_cmd(current.command, { bufnr = self.bufnr })
|
||||
if item.command then
|
||||
local client = assert(vim.lsp.get_client_by_id(item.client_id))
|
||||
client:exec_cmd(item.command, { bufnr = self.bufnr })
|
||||
end
|
||||
end
|
||||
|
||||
@@ -381,7 +376,7 @@ function M.select(opts)
|
||||
end
|
||||
|
||||
local n = completor:count_items()
|
||||
local index = current.index + count
|
||||
local index = current._index + count
|
||||
if wrap then
|
||||
index = (index - 1) % n + 1
|
||||
else
|
||||
@@ -396,10 +391,15 @@ end
|
||||
--- Buffer handle, or 0 for current.
|
||||
--- (default: 0)
|
||||
---@field bufnr? integer
|
||||
|
||||
--- Apply the currently displayed completion candidate to the buffer.
|
||||
---
|
||||
--- It returns false when no candidate can be applied,
|
||||
--- Accept handler, called with the accepted item.
|
||||
--- If not provided, the default handler is used,
|
||||
--- which applies changes to the buffer based on the completion item.
|
||||
---@field on_accept? fun(item: vim.lsp.inline_completion.Item)
|
||||
|
||||
--- Accept the currently displayed completion candidate to the buffer.
|
||||
---
|
||||
--- It returns false when no candidate can be accepted,
|
||||
--- so you can use the return value to implement a fallback:
|
||||
---
|
||||
--- ```lua
|
||||
@@ -420,11 +420,23 @@ function M.get(opts)
|
||||
opts = opts or {}
|
||||
|
||||
local bufnr = vim._resolve_bufnr(opts.bufnr)
|
||||
local on_accept = opts.on_accept
|
||||
|
||||
local completor = Completor.active[bufnr]
|
||||
if completor and completor.current then
|
||||
-- Schedule apply to allow `get()` can be mapped with `<expr>`.
|
||||
vim.schedule(function()
|
||||
completor:apply()
|
||||
local item = completor.current
|
||||
completor:abort()
|
||||
if not item then
|
||||
return
|
||||
end
|
||||
|
||||
if on_accept then
|
||||
on_accept(item)
|
||||
else
|
||||
completor:accept(item)
|
||||
end
|
||||
end)
|
||||
return true
|
||||
end
|
||||
|
Reference in New Issue
Block a user