diff --git a/lua/blink/cmp/accept/init.lua b/lua/blink/cmp/accept/init.lua index f0e4bdf9..1a3cd49d 100644 --- a/lua/blink/cmp/accept/init.lua +++ b/lua/blink/cmp/accept/init.lua @@ -2,14 +2,22 @@ local text_edits_lib = require('blink.cmp.accept.text-edits') local brackets_lib = require('blink.cmp.accept.brackets') --- Applies a completion item to the current buffer +--- @param ctx blink.cmp.Context --- @param item blink.cmp.CompletionItem -local function accept(item) +local function accept(ctx, item) + local sources = require('blink.cmp.sources.lib') require('blink.cmp.trigger.completion').hide() + -- let the source execute the item itself if it indicates it can + if sources.should_execute(item) then + sources.execute(ctx, item) + return + 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') + sources .resolve(item) :map(function(resolved_item) local all_text_edits = diff --git a/lua/blink/cmp/init.lua b/lua/blink/cmp/init.lua index e75697d5..1c3f67a6 100644 --- a/lua/blink/cmp/init.lua +++ b/lua/blink/cmp/init.lua @@ -152,17 +152,19 @@ cmp.accept = function() end cmp.select_and_accept = function() - if not cmp.windows.autocomplete.win:is_open() then return end + local autocomplete = require('blink.cmp.windows.autocomplete') + if not autocomplete.win:is_open() then return end vim.schedule(function() -- select an item if none is selected - if not cmp.windows.autocomplete.get_selected_item() then + if not autocomplete.get_selected_item() then -- avoid running auto_insert since we're about to accept anyway - cmp.windows.autocomplete.select_next({ skip_auto_insert = true }) + autocomplete.select_next({ skip_auto_insert = true }) end - local item = cmp.windows.autocomplete.get_selected_item() - if item ~= nil then require('blink.cmp.accept')(item) end + local ctx = autocomplete.context + local item = autocomplete.get_selected_item() + if item ~= nil and ctx ~= nil then require('blink.cmp.accept')(ctx, item) end end) return true end diff --git a/lua/blink/cmp/sources/lib/init.lua b/lua/blink/cmp/sources/lib/init.lua index 14d71950..29d082ff 100644 --- a/lua/blink/cmp/sources/lib/init.lua +++ b/lua/blink/cmp/sources/lib/init.lua @@ -16,6 +16,8 @@ local config = require('blink.cmp.config') --- @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): blink.cmp.Task +--- @field should_execute fun(item: blink.cmp.CompletionItem): boolean +--- @field execute fun(context: blink.cmp.Context, 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() @@ -167,6 +169,30 @@ function sources.resolve(item) return item_source:resolve(item):catch(function(err) vim.print('failed to resolve item with error: ' .. err) end) end +--- Execute --- + +function sources.should_execute(item) + for _, source in pairs(sources.providers) do + if source.id == item.source_id then return source:should_execute(item) end + end + return false +end + +function sources.execute(context, 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 + + return item_source + :execute(context, item) + :catch(function(err) vim.print('failed to execute item with error: ' .. err) end) +end + --- Signature help --- function sources.get_signature_help_trigger_characters() diff --git a/lua/blink/cmp/sources/lib/provider/init.lua b/lua/blink/cmp/sources/lib/provider/init.lua index fd05369d..cd4644c5 100644 --- a/lua/blink/cmp/sources/lib/provider/init.lua +++ b/lua/blink/cmp/sources/lib/provider/init.lua @@ -13,6 +13,8 @@ --- @field get_completions fun(self: blink.cmp.SourceProvider, context: blink.cmp.Context, enabled_sources: string[]): blink.cmp.Task --- @field should_show_items fun(self: blink.cmp.SourceProvider, context: blink.cmp.Context, enabled_sources: string[], response: blink.cmp.CompletionResponse): boolean --- @field resolve fun(self: blink.cmp.SourceProvider, item: blink.cmp.CompletionItem): blink.cmp.Task +--- @field should_execute fun(self: blink.cmp.SourceProvider, item: blink.cmp.CompletionItem): boolean +--- @field execute fun(self: blink.cmp.SourceProvider, context: blink.cmp.Context, item: blink.cmp.CompletionItem, callback: fun()): blink.cmp.Task --- @field get_signature_help_trigger_characters fun(self: blink.cmp.SourceProvider): string[] --- @field get_signature_help fun(self: blink.cmp.SourceProvider, context: blink.cmp.SignatureHelpContext): blink.cmp.Task --- @field reload (fun(self: blink.cmp.SourceProvider): nil) | nil @@ -134,6 +136,18 @@ function source:resolve(item) return tasks[item] end +--- Execute --- + +function source:should_execute(item) + if self.module.should_execute == nil then return self.module.execute ~= nil end + return self.module:should_execute(item) +end + +function source:execute(context, item) + if self.module.execute == nil then return async.task.new(function(resolve) resolve() end) end + return async.task.new(function(resolve) self.module:execute(context, item, resolve) end) +end + --- Signature help --- function source:get_signature_help_trigger_characters() diff --git a/lua/blink/cmp/sources/lib/types.lua b/lua/blink/cmp/sources/lib/types.lua index 3421cefe..770d2902 100644 --- a/lua/blink/cmp/sources/lib/types.lua +++ b/lua/blink/cmp/sources/lib/types.lua @@ -16,6 +16,8 @@ --- @field filter_completions? fun(self: blink.cmp.Source, response: blink.cmp.CompletionResponse): blink.cmp.CompletionItem[] --- @field should_show_completions? fun(self: blink.cmp.Source, context: blink.cmp.Context, response: blink.cmp.CompletionResponse): boolean --- @field resolve? fun(self: blink.cmp.Source, item: blink.cmp.CompletionItem, callback: fun(resolved_item?: lsp.CompletionItem)): ((fun(): nil) | nil) +--- @field should_execute? fun(self: blink.cmp.Source, item: blink.cmp.CompletionItem): boolean Optional function to check if the source should execute the specified item +--- @field execute? fun(self: blink.cmp.Source, context: blink.cmp.Context, item: blink.cmp.CompletionItem, callback: fun()): (fun(): nil) | nil --- @field get_signature_help_trigger_characters? fun(self: blink.cmp.Source): string[] --- @field get_signature_help? fun(self: blink.cmp.Source, context: blink.cmp.SignatureHelpContext, callback: fun(signature_help: lsp.SignatureHelp | nil)): (fun(): nil) | nil --- @field reload? fun(self: blink.cmp.Source): nil @@ -27,6 +29,8 @@ --- @field filter_completions? fun(self: blink.cmp.Source, response: blink.cmp.CompletionResponse): blink.cmp.CompletionItem[] --- @field should_show_completions? fun(self: blink.cmp.Source, context: blink.cmp.Context, response: blink.cmp.CompletionResponse): boolean --- @field resolve? fun(self: blink.cmp.Source, item: blink.cmp.CompletionItem, callback: fun(resolved_item: lsp.CompletionItem | nil)): ((fun(): nil) | nil) +--- @field should_execute? fun(self: blink.cmp.Source, item: blink.cmp.CompletionItem): boolean +--- @field execute? fun(self: blink.cmp.Source, context: blink.cmp.Context, item: blink.cmp.CompletionItem, callback: fun()): (fun(): nil) | nil --- @field get_signature_help_trigger_characters? fun(self: blink.cmp.Source): string[] --- @field get_signature_help? fun(self: blink.cmp.Source, context: blink.cmp.SignatureHelpContext, callback: fun(signature_help: lsp.SignatureHelp | nil)): (fun(): nil) | nil --- @field reload? fun(self: blink.cmp.Source): nil diff --git a/lua/blink/cmp/windows/autocomplete.lua b/lua/blink/cmp/windows/autocomplete.lua index 433b65f7..92aaf79f 100644 --- a/lua/blink/cmp/windows/autocomplete.lua +++ b/lua/blink/cmp/windows/autocomplete.lua @@ -193,6 +193,9 @@ end ---------- Selection/Accept ---------- function autocomplete.accept() + local context = autocomplete.context + if context == nil then return end + local selected_item = autocomplete.get_selected_item() if selected_item == nil then return end @@ -202,7 +205,7 @@ function autocomplete.accept() end -- apply - require('blink.cmp.accept')(selected_item) + require('blink.cmp.accept')(context, selected_item) return true end