Skip to content

Commit b58a382

Browse files
committed
feat: hack around LSPs returning filtered items
1 parent d6bad7b commit b58a382

File tree

4 files changed

+42
-11
lines changed

4 files changed

+42
-11
lines changed

lua/blink/cmp/sources/init.lua

+3-1
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,9 @@ function sources.completions(context)
7878
-- fixme: what if we refetch due to incomplete items or a trigger_character? the context trigger id wouldnt change
7979
-- change so stale data would be returned if the source doesn't support cancellation
8080
local cursor_column = vim.api.nvim_win_get_cursor(0)[2]
81-
source.completions({ trigger = trigger_context }, function(items)
81+
local source_context = vim.fn.deepcopy(context)
82+
source_context.trigger = trigger_context
83+
source.completions(source_context, function(items)
8284
-- a new call was made or this one was cancelled
8385
if sources.in_flight_id[source_name] ~= in_flight_id then return end
8486
sources.in_flight_id[source_name] = -1

lua/blink/cmp/sources/lsp.lua

+32-4
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ function lsp.get_clients_with_capability(capability, filter)
4040
end
4141

4242
function lsp.completions(context, callback)
43+
-- todo: offset encoding is global but should be per-client
44+
-- todo: should make separate LSP requests to return results earlier, in the case of slow LSPs
45+
-- todo: should make a new call if the cursor moves backwards, before the first character of the trigger
46+
4347
-- no providers with completion support
4448
if not lsp.has_capability('completionProvider') then return callback({ isIncomplete = false, items = {} }) end
4549

@@ -52,6 +56,29 @@ function lsp.completions(context, callback)
5256
params.context.triggerCharacter = context.trigger.character
5357
end
5458

59+
-- special case, the first character of the context is a trigger character, so we adjust the position
60+
-- sent to the LSP server to be the start of the trigger character
61+
--
62+
-- some LSP do their own filtering before returning results, which we want to avoid
63+
-- since we perform fuzzy matching ourselves.
64+
--
65+
-- this also avoids having to make multiple calls to the LSP server in case characters are deleted
66+
-- for these special cases
67+
-- i.e. hello.wor| would be sent as hello.|wor
68+
-- todo: should we still make two calls to the LSP server and merge?
69+
local trigger_characters = lsp.get_trigger_characters()
70+
local trigger_character_block_list = { ' ', '\n', '\t' }
71+
local bounds = context.bounds
72+
local trigger_character_before_context = bounds.line:sub(bounds.start_col - 1, bounds.start_col - 1)
73+
if
74+
vim.tbl_contains(trigger_characters, trigger_character_before_context)
75+
and not vim.tbl_contains(trigger_character_block_list, trigger_character_before_context)
76+
then
77+
local offset_encoding = vim.lsp.get_clients({ bufnr = 0 })[1].offset_encoding
78+
params.position.character =
79+
vim.lsp.util.character_offset(0, params.position.line, bounds.start_col - 1, offset_encoding)
80+
end
81+
5582
-- request from each of the clients
5683
-- todo: refactor
5784
lsp.cancel_completions_func = vim.lsp.buf_request_all(0, 'textDocument/completion', params, function(result)
@@ -75,6 +102,7 @@ function lsp.completions(context, callback)
75102
for client_id, response in pairs(responses) do
76103
for _, item in ipairs(response.items) do
77104
-- todo: terraform lsp doesn't return a .kind in situations like `toset`, is there a default value we need to grab?
105+
-- it doesn't seem to return itemDefaults either
78106
item.kind = item.kind or vim.lsp.protocol.CompletionItemKind.Text
79107
item.client_id = client_id
80108

@@ -85,7 +113,7 @@ function lsp.completions(context, callback)
85113
end
86114

87115
-- combine responses
88-
-- todo: would be nice to pass multiple responses to the sources
116+
-- todo: ideally pass multiple responses to the sources
89117
-- so that we can do fine-grained isIncomplete
90118
local combined_response = { isIncomplete = false, items = {} }
91119
for _, response in pairs(responses) do
@@ -111,9 +139,9 @@ function lsp.resolve(item, callback)
111139
return
112140
end
113141

114-
local _, request_id = client.request('completionItem/resolve', item, function(error, result)
115-
if error or result == nil then callback(item) end
116-
callback(result)
142+
local _, request_id = client.request('completionItem/resolve', item, function(error, resolved_item)
143+
if error or resolved_item == nil then callback(item) end
144+
callback(resolved_item)
117145
end)
118146
if request_id ~= nil then return function() client.cancel_request(request_id) end end
119147
end

lua/blink/cmp/sources/types.lua

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
--- @class TriggerContext
1+
--- @class CompletionTriggerContext
22
--- @field kind number
33
--- @field character string
44
---
55
--- @class CompletionContext : ShowContext
6-
--- @field trigger TriggerContext | nil
6+
--- @field trigger CompletionTriggerContext | nil
77
---
88
--- @class CompletionResponse
99
--- @field isIncomplete boolean

lua/blink/cmp/trigger.lua

+5-4
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
-- This can be used downstream to determine if we should make new requests to the sources or not.
44

55
--- @class TriggerBounds
6-
--- @field line number
6+
--- @field line string
7+
--- @field line_number number
78
--- @field start_col number
89
--- @field end_col number
910
---
@@ -108,7 +109,7 @@ function trigger.show(opts)
108109
opts = opts or {}
109110

110111
-- update context (to update bounds and treesitter node)
111-
-- todo: this beahvior isn't obvious
112+
-- todo: this behavior isn't obvious
112113
trigger.context = trigger.get_context()
113114

114115
trigger.event_targets.on_show({
@@ -149,7 +150,7 @@ function trigger.within_query_bounds(cursor)
149150

150151
local row, col = cursor[1], cursor[2]
151152
local bounds = trigger.context.bounds
152-
return row == bounds.line and col >= bounds.start_col and col <= bounds.end_col
153+
return row == bounds.line_number and col >= bounds.start_col and col <= bounds.end_col
153154
end
154155

155156
------ Helpers ------
@@ -185,7 +186,7 @@ function helpers.get_query(regex)
185186
end_col = end_col + 1
186187
end
187188

188-
return { line = cursor_line, start_col = start_col, end_col = end_col }
189+
return { line = line, line_number = cursor_line, start_col = start_col, end_col = end_col }
189190
end
190191

191192
--- @return TSNode | nil

0 commit comments

Comments
 (0)