summaryrefslogtreecommitdiff
path: root/lua/blink/cmp/completion/accept/init.lua
diff options
context:
space:
mode:
Diffstat (limited to 'lua/blink/cmp/completion/accept/init.lua')
-rw-r--r--lua/blink/cmp/completion/accept/init.lua110
1 files changed, 110 insertions, 0 deletions
diff --git a/lua/blink/cmp/completion/accept/init.lua b/lua/blink/cmp/completion/accept/init.lua
new file mode 100644
index 0000000..c4041d3
--- /dev/null
+++ b/lua/blink/cmp/completion/accept/init.lua
@@ -0,0 +1,110 @@
+local text_edits_lib = require('blink.cmp.lib.text_edits')
+local brackets_lib = require('blink.cmp.completion.brackets')
+
+--- Applies a completion item to the current buffer
+--- @param ctx blink.cmp.Context
+--- @param item blink.cmp.CompletionItem
+--- @param callback fun()
+local function accept(ctx, item, callback)
+ local sources = require('blink.cmp.sources.lib')
+ require('blink.cmp.completion.trigger').hide()
+
+ -- 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
+ sources
+ .resolve(ctx, item)
+ :map(function(item)
+ item = vim.deepcopy(item)
+
+ -- Get additional text edits, converted to utf-8
+ local all_text_edits = vim.deepcopy(item.additionalTextEdits or {})
+ all_text_edits = vim.tbl_map(
+ function(text_edit) return text_edits_lib.to_utf_8(text_edit, text_edits_lib.offset_encoding_from_item(item)) end,
+ all_text_edits
+ )
+
+ -- TODO: it's not obvious that this is converting to utf-8
+ item.textEdit = text_edits_lib.get_from_item(item)
+
+ -- Create an undo point, if it's not a snippet, since the snippet engine should handle undo
+ if
+ ctx.mode == 'default'
+ and require('blink.cmp.config').completion.accept.create_undo_point
+ and item.insertTextFormat ~= vim.lsp.protocol.InsertTextFormat.Snippet
+ -- HACK: We check the kind here because the Luasnip source returns PlainText and handles
+ -- expansion itself. Otherwise, Luasnip will fail to enter select mode
+ -- https://github.com/Saghen/blink.cmp/commit/284dd37f9bbc632f8281d6361e877db5b45e6ff0#r150498482
+ and item.kind ~= require('blink.cmp.types').CompletionItemKind.Snippet
+ then
+ -- setting the undolevels forces neovim to create an undo point
+ vim.o.undolevels = vim.o.undolevels
+ end
+
+ -- Ignore snippets that only contain text
+ -- FIXME: doesn't handle escaped snippet placeholders "\\$1" should output "$1", not "\$1"
+ if
+ item.insertTextFormat == vim.lsp.protocol.InsertTextFormat.Snippet
+ and item.kind ~= require('blink.cmp.types').CompletionItemKind.Snippet
+ then
+ local parsed_snippet = require('blink.cmp.sources.snippets.utils').safe_parse(item.textEdit.newText)
+ if
+ parsed_snippet ~= nil
+ and #parsed_snippet.data.children == 1
+ and parsed_snippet.data.children[1].type == vim.lsp._snippet_grammar.NodeType.Text
+ then
+ item.insertTextFormat = vim.lsp.protocol.InsertTextFormat.PlainText
+ end
+ end
+
+ -- Add brackets to the text edit if needed
+ local brackets_status, text_edit_with_brackets, offset = brackets_lib.add_brackets(ctx, vim.bo.filetype, item)
+ item.textEdit = text_edit_with_brackets
+
+ -- Snippet
+ if item.insertTextFormat == vim.lsp.protocol.InsertTextFormat.Snippet then
+ assert(ctx.mode == 'default', 'Snippets are only supported in default mode')
+
+ -- 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(all_text_edits)
+
+ -- Expand the snippet
+ require('blink.cmp.config').snippets.expand(item.textEdit.newText)
+
+ -- OR Normal: Apply the text edit and move the cursor
+ else
+ table.insert(all_text_edits, item.textEdit)
+ text_edits_lib.apply(all_text_edits)
+ -- TODO: should move the cursor only by the offset since text edit handles everything else?
+ ctx.set_cursor({ ctx.get_cursor()[1], item.textEdit.range.start.character + #item.textEdit.newText + offset })
+ end
+
+ -- Let the source execute the item itself
+ sources.execute(ctx, item):map(function()
+ -- 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.completion.trigger').show_if_on_trigger_character({ is_accept = true })
+ require('blink.cmp.signature.trigger').show_if_on_trigger_character()
+ callback()
+ end)
+ else
+ require('blink.cmp.completion.trigger').show_if_on_trigger_character({ is_accept = true })
+ require('blink.cmp.signature.trigger').show_if_on_trigger_character()
+ callback()
+ end
+
+ -- Notify the rust module that the item was accessed
+ require('blink.cmp.fuzzy').access(item)
+ end)
+ end)
+ :catch(function(err) vim.notify(err, vim.log.levels.ERROR, { title = 'blink.cmp' }) end)
+end
+
+return accept