summaryrefslogtreecommitdiff
path: root/lua/blink/cmp/sources/lsp/init.lua
diff options
context:
space:
mode:
Diffstat (limited to 'lua/blink/cmp/sources/lsp/init.lua')
-rw-r--r--lua/blink/cmp/sources/lsp/init.lua131
1 files changed, 131 insertions, 0 deletions
diff --git a/lua/blink/cmp/sources/lsp/init.lua b/lua/blink/cmp/sources/lsp/init.lua
new file mode 100644
index 0000000..4dbfd8f
--- /dev/null
+++ b/lua/blink/cmp/sources/lsp/init.lua
@@ -0,0 +1,131 @@
+local async = require('blink.cmp.lib.async')
+
+--- @type blink.cmp.Source
+--- @diagnostic disable-next-line: missing-fields
+local lsp = {}
+
+function lsp.new() return setmetatable({}, { __index = lsp }) end
+
+--- Completion ---
+
+function lsp:get_trigger_characters()
+ local clients = vim.lsp.get_clients({ bufnr = 0 })
+ local trigger_characters = {}
+
+ for _, client in pairs(clients) do
+ local completion_provider = client.server_capabilities.completionProvider
+ if completion_provider and completion_provider.triggerCharacters then
+ for _, trigger_character in pairs(completion_provider.triggerCharacters) do
+ table.insert(trigger_characters, trigger_character)
+ end
+ end
+ end
+
+ return trigger_characters
+end
+
+function lsp:get_completions(context, callback)
+ local completion_lib = require('blink.cmp.sources.lsp.completion')
+ local clients = vim.tbl_filter(
+ function(client) return client.server_capabilities and client.server_capabilities.completionProvider end,
+ vim.lsp.get_clients({ bufnr = 0, method = 'textDocument/completion' })
+ )
+
+ -- TODO: implement a timeout before returning the menu as-is. In the future, it would be neat
+ -- to detect slow LSPs and consistently run them async
+ local task = async.task
+ .await_all(vim.tbl_map(function(client) return completion_lib.get_completion_for_client(context, client) end, clients))
+ :map(function(responses)
+ local final = { is_incomplete_forward = false, is_incomplete_backward = false, items = {} }
+ for _, response in ipairs(responses) do
+ final.is_incomplete_forward = final.is_incomplete_forward or response.is_incomplete_forward
+ final.is_incomplete_backward = final.is_incomplete_backward or response.is_incomplete_backward
+ vim.list_extend(final.items, response.items)
+ end
+ callback(final)
+ end)
+ return function() task:cancel() end
+end
+
+--- Resolve ---
+
+function lsp:resolve(item, callback)
+ local client = vim.lsp.get_client_by_id(item.client_id)
+ if client == nil or not client.server_capabilities.completionProvider.resolveProvider then
+ callback(item)
+ return
+ end
+
+ -- strip blink specific fields to avoid decoding errors on some LSPs
+ item = require('blink.cmp.sources.lib.utils').blink_item_to_lsp_item(item)
+
+ local success, request_id = client.request('completionItem/resolve', item, function(error, resolved_item)
+ if error or resolved_item == nil then callback(item) end
+ callback(resolved_item)
+ end)
+ if not success then callback(item) end
+ if request_id ~= nil then
+ return function() client.cancel_request(request_id) end
+ end
+end
+
+--- Signature help ---
+
+function lsp:get_signature_help_trigger_characters()
+ local clients = vim.lsp.get_clients({ bufnr = 0 })
+ local trigger_characters = {}
+ local retrigger_characters = {}
+
+ for _, client in pairs(clients) do
+ local signature_help_provider = client.server_capabilities.signatureHelpProvider
+ if signature_help_provider and signature_help_provider.triggerCharacters then
+ for _, trigger_character in pairs(signature_help_provider.triggerCharacters) do
+ table.insert(trigger_characters, trigger_character)
+ end
+ end
+ if signature_help_provider and signature_help_provider.retriggerCharacters then
+ for _, retrigger_character in pairs(signature_help_provider.retriggerCharacters) do
+ table.insert(retrigger_characters, retrigger_character)
+ end
+ end
+ end
+
+ return { trigger_characters = trigger_characters, retrigger_characters = retrigger_characters }
+end
+
+function lsp:get_signature_help(context, callback)
+ -- no providers with signature help support
+ if #vim.lsp.get_clients({ bufnr = 0, method = 'textDocument/signatureHelp' }) == 0 then
+ callback(nil)
+ return function() end
+ end
+
+ -- TODO: offset encoding is global but should be per-client
+ local first_client = vim.lsp.get_clients({ bufnr = 0 })[1]
+ local offset_encoding = first_client and first_client.offset_encoding or 'utf-16'
+
+ local params = vim.lsp.util.make_position_params(nil, offset_encoding)
+ params.context = {
+ triggerKind = context.trigger.kind,
+ triggerCharacter = context.trigger.character,
+ isRetrigger = context.is_retrigger,
+ activeSignatureHelp = context.active_signature_help,
+ }
+
+ -- otherwise, we call all clients
+ -- TODO: some LSPs never response (typescript-tools.nvim)
+ return vim.lsp.buf_request_all(0, 'textDocument/signatureHelp', params, function(result)
+ local signature_helps = {}
+ for client_id, res in pairs(result) do
+ local signature_help = res.result
+ if signature_help ~= nil then
+ signature_help.client_id = client_id
+ table.insert(signature_helps, signature_help)
+ end
+ end
+ -- todo: pick intelligently
+ callback(signature_helps[1])
+ end)
+end
+
+return lsp