Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
Saghen committed Dec 9, 2024
1 parent 3aebeb6 commit b8e1e5b
Show file tree
Hide file tree
Showing 9 changed files with 281 additions and 213 deletions.
10 changes: 9 additions & 1 deletion lua/blink/cmp/lib/async.lua
Original file line number Diff line number Diff line change
Expand Up @@ -151,22 +151,26 @@ end
--- utils

function task.await_all(tasks)
if #tasks == 0 then return task.empty() end

local all_task
all_task = task.new(function(resolve, reject)
local results = {}
local has_resolved = {}

local function resolve_if_completed()
-- we can't check #results directly because a table like
-- { [2] = { ... } } has a length of 2
for i = 1, #tasks do
if results[i] == nil then return end
if has_resolved[i] == nil then return end
end
resolve(results)
end

for idx, task in ipairs(tasks) do
task:on_completion(function(result)
results[idx] = result
has_resolved[idx] = true
resolve_if_completed()
end)
task:on_failure(function(err)
Expand All @@ -186,4 +190,8 @@ function task.await_all(tasks)
return all_task
end

function task.empty()
return task.new(function(resolve) resolve() end)
end

return { task = task, STATUS = STATUS }
66 changes: 0 additions & 66 deletions lua/blink/cmp/sources/lib/context.lua

This file was deleted.

36 changes: 18 additions & 18 deletions lua/blink/cmp/sources/lib/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ local async = require('blink.cmp.lib.async')
local config = require('blink.cmp.config')

--- @class blink.cmp.Sources
--- @field current_context blink.cmp.SourcesContext | nil
--- @field completions_queue blink.cmp.SourcesContext | nil
--- @field current_signature_help blink.cmp.Task | nil
--- @field sources_registered boolean
--- @field providers table<string, blink.cmp.SourceProvider>
Expand Down Expand Up @@ -35,7 +35,7 @@ local config = require('blink.cmp.config')
--- @type blink.cmp.Sources
--- @diagnostic disable-next-line: missing-fields
local sources = {
current_context = nil,
completions_queue = nil,
providers = {},
completions_emitter = require('blink.cmp.lib.event_emitter').new('source_completions', 'BlinkCmpSourceCompletions'),
}
Expand Down Expand Up @@ -96,37 +96,37 @@ function sources.get_trigger_characters()
return trigger_characters
end

function sources.emit_completions(context, responses)
local items = {}
for id, response in pairs(responses) do
if sources.providers[id]:should_show_items(context, response.items) then items[id] = response.items end
function sources.emit_completions(context, _items_by_provider)
local items_by_provider = {}
for id, items in pairs(_items_by_provider) do
if sources.providers[id]:should_show_items(context, items) then items_by_provider[id] = items end
end
sources.completions_emitter:emit({ context = context, items = items })
vim.print('emitting')
sources.completions_emitter:emit({ context = context, items = items_by_provider })
end

function sources.request_completions(context)
-- create a new context if the id changed or if we haven't created one yet
local is_new_context = sources.current_context == nil or context.id ~= sources.current_context.id
if is_new_context then
if sources.current_context ~= nil then sources.current_context:destroy() end
sources.current_context =
require('blink.cmp.sources.lib.context').new(context, sources.get_all_providers(), sources.emit_completions)
if sources.completions_queue == nil or context.id ~= sources.completions_queue.id then
if sources.completions_queue ~= nil then sources.completions_queue:destroy() end
sources.completions_queue =
require('blink.cmp.sources.lib.queue').new(context, sources.get_all_providers(), sources.emit_completions)
-- send cached completions if they exist to immediately trigger updates
elseif sources.current_context:get_cached_completions() ~= nil then
elseif sources.completions_queue:get_cached_completions() ~= nil then
sources.emit_completions(
context,
--- @diagnostic disable-next-line: param-type-mismatch
sources.current_context:get_cached_completions()
sources.completions_queue:get_cached_completions()
)
end

sources.current_context:get_completions(context)
sources.completions_queue:get_completions(context)
end

function sources.cancel_completions()
if sources.current_context ~= nil then
sources.current_context:destroy()
sources.current_context = nil
if sources.completions_queue ~= nil then
sources.completions_queue:destroy()
sources.completions_queue = nil
end
end

Expand Down
3 changes: 3 additions & 0 deletions lua/blink/cmp/sources/lib/provider/config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
--- @field module string
--- @field enabled fun(ctx: blink.cmp.Context): boolean
--- @field async fun(ctx: blink.cmp.Context): boolean
--- @field timeout_ms fun(ctx: blink.cmp.Context): number
--- @field transform_items fun(ctx: blink.cmp.Context, items: blink.cmp.CompletionItem[]): blink.cmp.CompletionItem[]
--- @field should_show_items fun(ctx: blink.cmp.Context, items: blink.cmp.CompletionItem[]): boolean
--- @field max_items? fun(ctx: blink.cmp.Context, items: blink.cmp.CompletionItem[]): number
Expand All @@ -28,6 +29,8 @@ function wrapper.new(config)
self.name = config.name
self.module = config.module
self.enabled = call_or_get(config.enabled, true)
self.async = call_or_get(config.async, false)
self.timeout_ms = call_or_get(config.timeout, 400)
self.transform_items = config.transform_items or function(_, items) return items end
self.should_show_items = call_or_get(config.should_show_items, true)
self.max_items = call_or_get(config.max_items, nil)
Expand Down
67 changes: 15 additions & 52 deletions lua/blink/cmp/sources/lib/provider/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,14 @@
--- @field name string
--- @field config blink.cmp.SourceProviderConfigWrapper
--- @field module blink.cmp.Source
--- @field last_response blink.cmp.CompletionResponse | nil
--- @field last_context blink.cmp.Context | nil
--- @field list blink.cmp.SourceProviderList | nil
--- @field resolve_tasks table<blink.cmp.CompletionItem, blink.cmp.Task>
---
--- @field new fun(id: string, config: blink.cmp.SourceProviderConfig): blink.cmp.SourceProvider
--- @field enabled fun(self: blink.cmp.SourceProvider, context: blink.cmp.Context): boolean
--- @field get_trigger_characters fun(self: blink.cmp.SourceProvider): string[]
--- @field get_completions fun(self: blink.cmp.SourceProvider, context: blink.cmp.Context): blink.cmp.Task
--- @field should_show_items fun(self: blink.cmp.SourceProvider, context: blink.cmp.Context, response: blink.cmp.CompletionResponse): boolean
--- @field get_completions fun(self: blink.cmp.SourceProvider, context: blink.cmp.Context, on_items: fun(items: blink.cmp.CompletionItem[]))
--- @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 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[] }
Expand All @@ -23,7 +22,6 @@
--- @diagnostic disable-next-line: missing-fields
local source = {}

local utils = require('blink.cmp.sources.lib.utils')
local async = require('blink.cmp.lib.async')

function source.new(id, config)
Expand All @@ -38,8 +36,7 @@ function source.new(id, config)
config.override
)
self.config = require('blink.cmp.sources.lib.provider.config').new(config)
self.last_response = nil
self.last_context = nil
self.list = nil
self.resolve_tasks = {}

return self
Expand All @@ -61,20 +58,13 @@ function source:get_trigger_characters()
return self.module:get_trigger_characters()
end

function source:get_completions(context)
-- Return the previous successful completions if the context is the same
function source:get_completions(context, on_items)
-- return the previous successful completions if the context is the same
-- and the data doesn't need to be updated
if self.last_response ~= nil and self.last_context ~= nil and self.last_context.id == context.id then
if utils.should_run_request(context, self.last_context, self.last_response) == false then
return async.task.new(
function(resolve)
resolve({
cached = true,
response = self.last_response,
})
end
)
end
if self.list ~= nil and self.list:is_valid_for_context(context) then
self.list:set_on_items(on_items)
self.list:emit()
return
end

-- the source indicates we should refetch when this character is typed
Expand All @@ -87,46 +77,19 @@ function source:get_completions(context)
and { kind = vim.lsp.protocol.CompletionTriggerKind.TriggerCharacter, character = context.trigger.character }
or { kind = vim.lsp.protocol.CompletionTriggerKind.Invoked }

return async.task
.new(function(resolve)
if self.module.get_completions == nil then return resolve() end
return self.module:get_completions(source_context, resolve)
end)
:map(function(response)
if response == nil then response = { is_incomplete_forward = true, is_incomplete_backward = true, items = {} } end

-- add non-lsp metadata
local source_score_offset = self.config.score_offset(context) or 0
for _, item in ipairs(response.items) do
item.score_offset = (item.score_offset or 0) + source_score_offset
item.cursor_column = context.cursor[2]
item.source_id = self.id
item.source_name = self.name
end

-- if the user provided a transform_items function, run it
if self.config.transform_items ~= nil then
response.items = self.config.transform_items(context, response.items)
end

self.last_response = response
self.last_context = context
return { cached = false, response = response }
end)
:catch(function(err)
vim.print('failed to get completions with error: ' .. err)
return { cached = false, { is_incomplete_forward = false, is_incomplete_backward = false, items = {} } }
end)
-- TODO: error handling
if self.list ~= nil then self.list:destroy() end
self.list = require('blink.cmp.sources.lib.provider.list').new(self, context, on_items)
end

function source:should_show_items(context, response)
function source:should_show_items(context, items)
-- if keyword length is configured, check if the context is long enough
local min_keyword_length = self.config.min_keyword_length(context)
local current_keyword_length = context.bounds.length
if current_keyword_length < min_keyword_length then return false end

if self.config.should_show_items == nil then return true end
return self.config.should_show_items(context, response.items)
return self.config.should_show_items(context, items)
end

--- Resolve ---
Expand Down
Loading

0 comments on commit b8e1e5b

Please sign in to comment.