diff --git a/lua/blink/cmp/completion/accept/init.lua b/lua/blink/cmp/completion/accept/init.lua index bbbfa2a5..8352fe10 100644 --- a/lua/blink/cmp/completion/accept/init.lua +++ b/lua/blink/cmp/completion/accept/init.lua @@ -13,7 +13,7 @@ local function accept(ctx, item, callback) -- with some LSPs (i.e. rust-analyzer) causing them to return the item as-is -- without i.e. auto-imports sources - .resolve(item) + .resolve(ctx, item) :map(function(item) item = vim.deepcopy(item) diff --git a/lua/blink/cmp/completion/init.lua b/lua/blink/cmp/completion/init.lua index c1476202..d504e7db 100644 --- a/lua/blink/cmp/completion/init.lua +++ b/lua/blink/cmp/completion/init.lua @@ -63,7 +63,7 @@ function completion.setup() list.hide_emitter:on(function() require('blink.cmp.completion.windows.menu').close() end) list.select_emitter:on(function(event) require('blink.cmp.completion.windows.menu').set_selected_item_idx(event.idx) - require('blink.cmp.completion.windows.documentation').auto_show_item(event.item) + require('blink.cmp.completion.windows.documentation').auto_show_item(event.context, event.item) end) end diff --git a/lua/blink/cmp/completion/prefetch.lua b/lua/blink/cmp/completion/prefetch.lua index 2e07c7a1..c722a300 100644 --- a/lua/blink/cmp/completion/prefetch.lua +++ b/lua/blink/cmp/completion/prefetch.lua @@ -12,7 +12,7 @@ local function prefetch_resolve(context, item) local resolve = vim.schedule_wrap(function() if last_request ~= nil then last_request:cancel() end - last_request = require('blink.cmp.sources.lib').resolve(item) + last_request = require('blink.cmp.sources.lib').resolve(context, item) end) -- immediately resolve if the context has changed diff --git a/lua/blink/cmp/completion/windows/documentation.lua b/lua/blink/cmp/completion/windows/documentation.lua index f9ca2eb3..fd4014eb 100644 --- a/lua/blink/cmp/completion/windows/documentation.lua +++ b/lua/blink/cmp/completion/windows/documentation.lua @@ -4,8 +4,8 @@ --- @field auto_show_timer uv_timer_t --- @field shown_item? blink.cmp.CompletionItem --- ---- @field auto_show_item fun(item: blink.cmp.CompletionItem) ---- @field show_item fun(item: blink.cmp.CompletionItem) +--- @field auto_show_item fun(context: blink.cmp.Context, item: blink.cmp.CompletionItem) +--- @field show_item fun(context: blink.cmp.Context, item: blink.cmp.CompletionItem) --- @field update_position fun() --- @field scroll_up fun(amount: number) --- @field scroll_down fun(amount: number) @@ -41,27 +41,27 @@ menu.close_emitter:on(function() docs.auto_show_timer:stop() end) -function docs.auto_show_item(item) +function docs.auto_show_item(context, item) docs.auto_show_timer:stop() if docs.win:is_open() then docs.auto_show_timer:start(config.update_delay_ms, 0, function() - vim.schedule(function() docs.show_item(item) end) + vim.schedule(function() docs.show_item(context, item) end) end) elseif config.auto_show then docs.auto_show_timer:start(config.auto_show_delay_ms, 0, function() - vim.schedule(function() docs.show_item(item) end) + vim.schedule(function() docs.show_item(context, item) end) end) end end -function docs.show_item(item) +function docs.show_item(context, item) docs.auto_show_timer:stop() if item == nil or not menu.win:is_open() then return docs.win:close() end -- TODO: cancellation -- TODO: only resolve if documentation does not exist sources - .resolve(item) + .resolve(context, item) :map(function(item) if item.documentation == nil and item.detail == nil then docs.win:close() diff --git a/lua/blink/cmp/init.lua b/lua/blink/cmp/init.lua index c1c4779b..4dbc775b 100644 --- a/lua/blink/cmp/init.lua +++ b/lua/blink/cmp/init.lua @@ -99,10 +99,11 @@ function cmp.show_documentation() local documentation = require('blink.cmp.completion.windows.documentation') if documentation.win:is_open() or not menu.win:is_open() then return end + local context = require('blink.cmp.completion.list').context local item = require('blink.cmp.completion.list').get_selected_item() - if not item then return end + if not item or not context then return end - vim.schedule(function() documentation.show_item(item) end) + vim.schedule(function() documentation.show_item(context, item) end) return true end diff --git a/lua/blink/cmp/sources/lib/init.lua b/lua/blink/cmp/sources/lib/init.lua index fa9bc0d3..826ae829 100644 --- a/lua/blink/cmp/sources/lib/init.lua +++ b/lua/blink/cmp/sources/lib/init.lua @@ -19,7 +19,7 @@ local config = require('blink.cmp.config') --- @field cancel_completions fun() --- @field apply_max_items_for_completions fun(context: blink.cmp.Context, items: blink.cmp.CompletionItem[]): blink.cmp.CompletionItem[] --- @field listen_on_completions fun(callback: fun(context: blink.cmp.Context, items: blink.cmp.CompletionItem[])) ---- @field resolve fun(item: blink.cmp.CompletionItem): blink.cmp.Task +--- @field resolve fun(context: blink.cmp.Context, item: blink.cmp.CompletionItem): blink.cmp.Task --- @field execute fun(context: blink.cmp.Context, item: blink.cmp.CompletionItem): blink.cmp.Task --- --- @field get_signature_help_trigger_characters fun(mode: blink.cmp.Mode): { trigger_characters: string[], retrigger_characters: string[] } @@ -159,7 +159,7 @@ end --- Resolve --- -function sources.resolve(item) +function sources.resolve(context, item) --- @type blink.cmp.SourceProvider? local item_source = nil for _, source in pairs(sources.providers) do @@ -168,9 +168,13 @@ function sources.resolve(item) break end end - if item_source == nil then return async.task.new(function(resolve) resolve(item) end) end + if item_source == nil then + return async.task.new(function(resolve) resolve(item) end) + end - return item_source:resolve(item):catch(function(err) vim.print('failed to resolve item with error: ' .. err) end) + return item_source + :resolve(context, item) + :catch(function(err) vim.print('failed to resolve item with error: ' .. err) end) end --- Execute --- @@ -183,7 +187,9 @@ function sources.execute(context, item) break end end - if item_source == nil then return async.task.new(function(resolve) resolve() end) end + if item_source == nil then + return async.task.new(function(resolve) resolve() end) + end return item_source :execute(context, item) diff --git a/lua/blink/cmp/sources/lib/provider/init.lua b/lua/blink/cmp/sources/lib/provider/init.lua index 881bfbc3..2e0b5c3d 100644 --- a/lua/blink/cmp/sources/lib/provider/init.lua +++ b/lua/blink/cmp/sources/lib/provider/init.lua @@ -12,7 +12,8 @@ --- @field get_trigger_characters fun(self: blink.cmp.SourceProvider): string[] --- @field get_completions fun(self: blink.cmp.SourceProvider, context: blink.cmp.Context, on_items: fun(items: blink.cmp.CompletionItem[], is_cached: boolean)) --- @field should_show_items fun(self: blink.cmp.SourceProvider, context: blink.cmp.Context, items: blink.cmp.CompletionItem[]): boolean ---- @field resolve fun(self: blink.cmp.SourceProvider, item: blink.cmp.CompletionItem): blink.cmp.Task +--- @field transform_items fun(self: blink.cmp.SourceProvider, context: blink.cmp.Context, items: blink.cmp.CompletionItem[]): blink.cmp.CompletionItem[] +--- @field resolve fun(self: blink.cmp.SourceProvider, context: blink.cmp.Context, item: blink.cmp.CompletionItem): blink.cmp.Task --- @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): { trigger_characters: string[], retrigger_characters: string[] } --- @field get_signature_help fun(self: blink.cmp.SourceProvider, context: blink.cmp.SignatureHelpContext): blink.cmp.Task @@ -109,24 +110,25 @@ function source:should_show_items(context, items) return self.config.should_show_items(context, items) end +function source:transform_items(context, items) + if self.config.transform_items ~= nil then items = self.config.transform_items(context, items) end + items = require('blink.cmp.config').sources.transform_items(context, items) + return items +end + --- Resolve --- ---- @param item blink.cmp.CompletionItem ---- @return blink.cmp.Task -function source:resolve(item) +function source:resolve(context, item) local tasks = self.resolve_tasks if tasks[item] == nil or tasks[item].status == async.STATUS.CANCELLED then tasks[item] = async.task.new(function(resolve) if self.module.resolve == nil then return resolve(item) end + return self.module:resolve(item, function(resolved_item) - -- use the item's existing documentation and detail if the LSP didn't return it - -- TODO: do we need this? this would be for java but never checked if it's needed - if resolved_item ~= nil and resolved_item.documentation == nil then - resolved_item.documentation = item.documentation - end - if resolved_item ~= nil and resolved_item.detail == nil then resolved_item.detail = item.detail end - - vim.schedule(function() resolve(vim.tbl_deep_extend('force', item, resolved_item or {})) end) + -- HACK: it's out of spec to update keys not in resolveSupport.properties but some LSPs do it anyway + local merged_item = vim.tbl_deep_extend('force', item, resolved_item or {}) + local transformed_item = self:transform_items(context, { merged_item })[1] or merged_item + vim.schedule(function() resolve(transformed_item) end) end) end) end diff --git a/lua/blink/cmp/sources/lib/provider/list.lua b/lua/blink/cmp/sources/lib/provider/list.lua index cf88f8af..5da940ac 100644 --- a/lua/blink/cmp/sources/lib/provider/list.lua +++ b/lua/blink/cmp/sources/lib/provider/list.lua @@ -90,10 +90,7 @@ function list:append(response) self.items = new_items -- run provider-local and global transform_items functions - if self.provider.config.transform_items ~= nil then - self.items = self.provider.config.transform_items(self.context, self.items) - self.items = require('blink.cmp.config').sources.transform_items(self.context, self.items) - end + self.items = self.provider:transform_items(self.context, self.items) self:emit() end