Skip to content

Commit

Permalink
feat: resolve item before accept
Browse files Browse the repository at this point in the history
  • Loading branch information
Saghen committed Oct 28, 2024
1 parent 18f0610 commit 3927128
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 68 deletions.
90 changes: 49 additions & 41 deletions lua/blink/cmp/accept/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -6,55 +6,63 @@ local brackets_lib = require('blink.cmp.accept.brackets')
local function accept(item)
require('blink.cmp.trigger.completion').hide()

-- create an undo point
if require('blink.cmp.config').accept.create_undo_point then
vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes('<C-g>u', true, true, true), 'n', true)
end
-- start the resolve immediately since text changes can invalidate the item
-- with some LSPs (i.e. rust-analyzer) causing them to return the item as-is
-- without i.e. auto-imports
require('blink.cmp.sources.lib').resolve(item):map(function(resolved_item)
local all_text_edits =
vim.deepcopy(resolved_item and resolved_item.additionalTextEdits or item.additionalTextEdits or {})

item = vim.deepcopy(item)
item.textEdit = text_edits_lib.get_from_item(item)
-- create an undo point
if require('blink.cmp.config').accept.create_undo_point then
vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes('<C-g>u', true, true, true), 'n', true)
end

-- Add brackets to the text edit if needed
local brackets_status, text_edit_with_brackets, offset = brackets_lib.add_brackets(vim.bo.filetype, item)
item.textEdit = text_edit_with_brackets
item = vim.deepcopy(item)
item.textEdit = text_edits_lib.get_from_item(item)

-- Snippet
if item.insertTextFormat == vim.lsp.protocol.InsertTextFormat.Snippet then
-- We want to handle offset_encoding and the text edit api can do this for us
-- so we empty the newText and apply
local temp_text_edit = vim.deepcopy(item.textEdit)
temp_text_edit.newText = ''
text_edits_lib.apply_text_edits(item.client_id, { temp_text_edit })
-- Add brackets to the text edit if needed
local brackets_status, text_edit_with_brackets, offset = brackets_lib.add_brackets(vim.bo.filetype, item)
item.textEdit = text_edit_with_brackets

-- Expand the snippet
vim.snippet.expand(item.textEdit.newText)
-- Snippet
if item.insertTextFormat == vim.lsp.protocol.InsertTextFormat.Snippet then
-- We want to handle offset_encoding and the text edit api can do this for us
-- so we empty the newText and apply
local temp_text_edit = vim.deepcopy(item.textEdit)
temp_text_edit.newText = ''
table.insert(all_text_edits, temp_text_edit)
text_edits_lib.apply_text_edits(item.client_id, all_text_edits)

-- Expand the snippet
vim.snippet.expand(item.textEdit.newText)

-- OR Normal: Apply the text edit and move the cursor
else
text_edits_lib.apply_text_edits(item.client_id, { item.textEdit })
vim.api.nvim_win_set_cursor(0, {
item.textEdit.range.start.line + 1,
item.textEdit.range.start.character + #item.textEdit.newText + offset,
})
end

-- Check semantic tokens for brackets, if needed, and apply additional text edits
if brackets_status == 'check_semantic_token' then
-- todo: since we apply the additional text edits after, auto imported functions will not
-- get auto brackets. If we apply them before, we have to modify the textEdit to compensate
brackets_lib.add_brackets_via_semantic_token(vim.bo.filetype, item, function()
else
table.insert(all_text_edits, item.textEdit)
text_edits_lib.apply_text_edits(item.client_id, all_text_edits)
vim.api.nvim_win_set_cursor(0, {
item.textEdit.range.start.line + 1,
item.textEdit.range.start.character + #item.textEdit.newText + offset,
})
end

-- Check semantic tokens for brackets, if needed, and apply additional text edits
if brackets_status == 'check_semantic_token' then
-- todo: since we apply the additional text edits after, auto imported functions will not
-- get auto brackets. If we apply them before, we have to modify the textEdit to compensate
brackets_lib.add_brackets_via_semantic_token(vim.bo.filetype, item, function()
require('blink.cmp.trigger.completion').show_if_on_trigger_character()
require('blink.cmp.trigger.signature').show_if_on_trigger_character()
end)
else
require('blink.cmp.trigger.completion').show_if_on_trigger_character()
require('blink.cmp.trigger.signature').show_if_on_trigger_character()
text_edits_lib.apply_additional_text_edits(item)
end)
else
require('blink.cmp.trigger.completion').show_if_on_trigger_character()
require('blink.cmp.trigger.signature').show_if_on_trigger_character()
text_edits_lib.apply_additional_text_edits(item)
end

-- Notify the rust module that the item was accessed
require('blink.cmp.fuzzy').access(item)
end

-- Notify the rust module that the item was accessed
require('blink.cmp.fuzzy').access(item)
end)
end

return accept
16 changes: 0 additions & 16 deletions lua/blink/cmp/accept/text-edits.lua
Original file line number Diff line number Diff line change
Expand Up @@ -55,22 +55,6 @@ function text_edits.undo_text_edit(text_edit)
vim.lsp.util.apply_text_edits({ text_edit }, vim.api.nvim_get_current_buf(), 'utf-16')
end

--- @param item blink.cmp.CompletionItem
function text_edits.apply_additional_text_edits(item)
-- Apply additional text edits
-- LSPs can either include these in the initial response or require a resolve
-- These are used for things like auto-imports
-- todo: if the main text edit was before this text edit, do we need to compensate?
if item.additionalTextEdits ~= nil and next(item.additionalTextEdits) ~= nil then
text_edits.apply_text_edits(item.client_id, item.additionalTextEdits)
else
require('blink.cmp.sources.lib').resolve(item, function(resolved_item)
resolved_item = resolved_item or item
text_edits.apply_text_edits(resolved_item.client_id, resolved_item.additionalTextEdits or {})
end)
end
end

--- @param item blink.cmp.CompletionItem
--- todo: doesnt work when the item contains characters not included in the context regex
function text_edits.guess_text_edit(item)
Expand Down
15 changes: 4 additions & 11 deletions lua/blink/cmp/sources/lib/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ local config = require('blink.cmp.config')
--- @field cancel_completions fun()
--- @field listen_on_completions fun(callback: fun(context: blink.cmp.Context, items: blink.cmp.CompletionItem[]))
--- @field apply_max_items_for_completions fun(context: blink.cmp.Context, items: blink.cmp.CompletionItem[]): blink.cmp.CompletionItem[]
--- @field resolve fun(item: blink.cmp.CompletionItem, callback: fun(resolved_item: lsp.CompletionItem | nil)): (fun(): nil) | nil
--- @field resolve fun(item: blink.cmp.CompletionItem): blink.cmp.Task
--- @field get_signature_help_trigger_characters fun(): { trigger_characters: string[], retrigger_characters: string[] }
--- @field get_signature_help fun(context: blink.cmp.SignatureHelpContext, callback: fun(signature_help: lsp.SignatureHelp | nil)): (fun(): nil) | nil
--- @field cancel_signature_help fun()
Expand Down Expand Up @@ -143,23 +143,17 @@ end

--- Resolve ---

function sources.resolve(item, callback)
function sources.resolve(item)
local item_source = nil
for _, source in pairs(sources.providers) do
if source.id == item.source_id then
item_source = source
break
end
end
if item_source == nil then return async.task.new(function(resolve) resolve() end) end

if item_source == nil then
callback(nil)
return function() end
end
return item_source:resolve(item):map(function(resolved_item) callback(resolved_item) end):catch(function(err)
vim.print('failed to resolve item with error: ' .. err)
callback(nil)
end)
return item_source:resolve(item):catch(function(err) vim.print('failed to resolve item with error: ' .. err) end)
end

--- Signature help ---
Expand Down Expand Up @@ -239,7 +233,6 @@ function sources.get_lsp_capabilities(override, include_nvim_defaults)
'documentation',
'detail',
'additionalTextEdits',
'textEdits',
-- todo: support more properties? should test if it improves latency
},
},
Expand Down

0 comments on commit 3927128

Please sign in to comment.