diff options
Diffstat (limited to 'lua/blink/cmp/sources/lsp/init.lua')
| -rw-r--r-- | lua/blink/cmp/sources/lsp/init.lua | 131 |
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 |
