Skip to content

Commit fae11d1

Browse files
committed
fix: trigger, docs, so much stuff
1 parent 04d5647 commit fae11d1

File tree

5 files changed

+72
-54
lines changed

5 files changed

+72
-54
lines changed

lua/blink/cmp/sources/init.lua

+20-12
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,15 @@ local sources = {
44
buffer = require('blink.cmp.sources.buffer'),
55
snippets = require('blink.cmp.sources.snippets'),
66
},
7-
in_flight = {
8-
lsp = false,
9-
buffer = false,
10-
snippets = false,
7+
8+
-- hack: sweet mother of all hacks
9+
last_in_flight_id = -1,
10+
in_flight_id = {
11+
lsp = -1,
12+
buffer = -1,
13+
snippets = -1,
1114
},
15+
1216
sources_items = {},
1317
current_context_id = -1,
1418
on_completions_callback = function(_) end,
@@ -49,12 +53,16 @@ function sources.completions(context)
4953
local previous_incomplete = sources.sources_items[source_name] ~= nil
5054
and sources.sources_items[source_name].isIncomplete
5155
-- check if we have no data and no calls are in flight
52-
local no_data = sources.sources_items[source_name] == nil and sources.in_flight[source_name] == false
56+
local no_data = sources.sources_items[source_name] == nil and sources.in_flight_id[source_name] == -1
5357

5458
-- if none of these are true, we can use the existing cached results
5559
if is_new_context or trigger_character or previous_incomplete or no_data then
5660
if source.cancel_completions ~= nil then source.cancel_completions() end
57-
sources.in_flight[source_name] = true
61+
62+
-- register the call
63+
sources.last_in_flight_id = sources.last_in_flight_id + 1
64+
local in_flight_id = sources.last_in_flight_id
65+
sources.in_flight_id[source_name] = sources.last_in_flight_id
5866

5967
-- get the reason for the trigger
6068
local trigger_context = trigger_character
@@ -68,10 +76,10 @@ function sources.completions(context)
6876
local cursor_column = vim.api.nvim_win_get_cursor(0)[2]
6977
vim.schedule(function()
7078
source.completions({ trigger = trigger_context }, function(items)
71-
-- context id changing indicates our current data is out of date
72-
if sources.current_context_id ~= context.id then return end
79+
-- a new call was made or this one was cancelled
80+
if sources.in_flight_id[source_name] ~= in_flight_id then return end
81+
sources.in_flight_id[source_name] = -1
7382

74-
sources.in_flight[source_name] = false
7583
sources.add_source_completions(source_name, items, cursor_column)
7684
if not sources.some_in_flight() then sources.send_completions() end
7785
end)
@@ -94,8 +102,8 @@ function sources.add_source_completions(source_name, source_items, cursor_column
94102
end
95103

96104
function sources.some_in_flight()
97-
for _, in_flight in pairs(sources.in_flight) do
98-
if in_flight == true then return true end
105+
for _, in_flight in pairs(sources.in_flight_id) do
106+
if in_flight ~= -1 then return true end
99107
end
100108
return false
101109
end
@@ -122,7 +130,7 @@ end
122130

123131
function sources.cancel_completions()
124132
for source_name, source in pairs(sources.registered) do
125-
sources.in_flight[source_name] = false
133+
sources.in_flight_id[source_name] = -1
126134
if source.cancel_completions ~= nil then source.cancel_completions() end
127135
end
128136
end

lua/blink/cmp/trigger.lua

+16-5
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,14 @@ function trigger.activate_autocmds()
2626
vim.api.nvim_create_autocmd('TextChangedI', {
2727
callback = function()
2828
-- character deleted so let cursormoved handle it
29-
if last_char == '' then
30-
return
29+
if last_char == '' then return end
30+
3131
-- ignore if in a special buffer
32-
elseif helpers.is_special_buffer() then
32+
if helpers.is_special_buffer() then
3333
trigger.hide()
34-
-- character forces a trigger according to the sources
34+
-- character forces a trigger according to the sources, create a fresh context
3535
elseif vim.tbl_contains(sources.get_trigger_characters(), last_char) then
36+
trigger.context = nil
3637
trigger.show({ trigger_character = last_char })
3738
-- character is part of the current context OR in an existing context
3839
elseif last_char:match(trigger.context_regex) ~= nil then
@@ -52,7 +53,13 @@ function trigger.activate_autocmds()
5253
-- text changed so let textchanged handle it
5354
if last_char ~= '' then return end
5455

55-
if trigger.within_query_bounds(vim.api.nvim_win_get_cursor(0)) then
56+
local is_within_bounds = trigger.within_query_bounds(vim.api.nvim_win_get_cursor(0))
57+
58+
local cursor_col = vim.api.nvim_win_get_cursor(0)[2]
59+
local char_under_cursor = vim.api.nvim_get_current_line():sub(cursor_col, cursor_col + 1)
60+
local is_on_trigger = vim.tbl_contains(sources.get_trigger_characters(), char_under_cursor)
61+
62+
if is_within_bounds or (is_on_trigger and trigger.context ~= nil) then
5663
trigger.show()
5764
else
5865
trigger.hide()
@@ -66,6 +73,10 @@ function trigger.activate_autocmds()
6673
return trigger
6774
end
6875

76+
--- @class TriggerOptions
77+
--- @field trigger_character string|nil
78+
---
79+
--- @param opts TriggerOptions|nil
6980
function trigger.show(opts)
7081
opts = opts or {}
7182

lua/blink/cmp/windows/autocomplete.lua

+17-12
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ local config = require('blink.cmp.config')
44
local autocomplete = {
55
items = {},
66
event_targets = {
7+
on_position_update = function() end,
78
on_select = function() end,
8-
on_open = function() end,
99
on_close = function() end,
1010
},
1111
}
@@ -47,6 +47,13 @@ function autocomplete.setup()
4747
end,
4848
})
4949

50+
vim.api.nvim_create_autocmd('CursorMovedI', {
51+
callback = function()
52+
autocomplete.win:update_position('cursor')
53+
autocomplete.event_targets.on_position_update()
54+
end,
55+
})
56+
5057
return autocomplete
5158
end
5259

@@ -56,28 +63,26 @@ function autocomplete.open_with_items(items)
5663
autocomplete.items = items
5764
autocomplete.draw()
5865

59-
if autocomplete.win:is_open() then
60-
-- todo: make a separate function for updating width/height
61-
autocomplete.win:update_position()
62-
else
63-
autocomplete.win:open()
64-
end
66+
autocomplete.win:open()
67+
autocomplete.win:update_position('cursor')
68+
autocomplete.event_targets.on_position_update()
6569

6670
-- todo: some logic to maintain the selection if the user moved the cursor?
6771
vim.api.nvim_win_set_cursor(autocomplete.win:get_win(), { 1, 0 })
72+
autocomplete.event_targets.on_select(autocomplete.get_selected_item())
6873
end
6974

75+
function autocomplete.listen_on_position_update(callback) autocomplete.event_targets.on_position_update = callback end
76+
7077
function autocomplete.open()
7178
if autocomplete.win:is_open() then return end
7279
autocomplete.win:open()
73-
autocomplete.on_open_callback(autocomplete.win:get_win())
7480
end
75-
function autocomplete.listen_on_open(callback) autocomplete.event_targets.on_open = callback end
7681

7782
function autocomplete.close()
7883
if not autocomplete.win:is_open() then return end
7984
autocomplete.win:close()
80-
autocomplete.on_close_callback()
85+
autocomplete.event_targets.on_close()
8186
end
8287
function autocomplete.listen_on_close(callback) autocomplete.event_targets.on_close = callback end
8388

@@ -91,7 +96,7 @@ function autocomplete.select_next()
9196
if current_line == line_count then return end
9297

9398
vim.api.nvim_win_set_cursor(autocomplete.win:get_win(), { current_line + 1, 0 })
94-
autocomplete.on_select_callback(autocomplete.get_selected_item())
99+
autocomplete.event_targets.on_select(autocomplete.get_selected_item())
95100
end
96101

97102
function autocomplete.select_prev()
@@ -101,7 +106,7 @@ function autocomplete.select_prev()
101106
if current_line == 1 then return end
102107

103108
vim.api.nvim_win_set_cursor(autocomplete.win:get_win(), { math.max(current_line - 1, 1), 0 })
104-
autocomplete.on_select_callback(autocomplete.get_selected_item())
109+
autocomplete.event_targets.on_select(autocomplete.get_selected_item())
105110
end
106111

107112
function autocomplete.listen_on_select(callback) autocomplete.event_targets.on_select = callback end

lua/blink/cmp/windows/documentation.lua

+11-8
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,34 @@
11
-- todo: track cmp_win position
22

33
local sources = require('blink.cmp.sources')
4-
local cmp_win = require('blink.cmp.windows.autocomplete')
4+
local autocomplete = require('blink.cmp.windows.autocomplete')
55
local docs = {}
66

77
function docs.setup()
88
docs.win = require('blink.cmp.windows.lib').new({
99
width = 60,
1010
max_height = 20,
11-
relative = cmp_win.win:get_win(),
1211
wrap = true,
1312
-- todo: should be able to use the markdown stuff now?
1413
-- filetype = 'typescript', -- todo: set dynamically
1514
padding = true,
1615
})
1716

18-
cmp_win.on_select_callback = function(item) docs.set_item(item) end
19-
cmp_win.on_open_callback = function() docs.set_item(cmp_win.get_selected_item()) end
20-
cmp_win.on_close_callback = function() docs.win:close() end
17+
autocomplete.listen_on_position_update(function()
18+
if autocomplete.win:get_win() then docs.win:update_position(autocomplete.win:get_win()) end
19+
end)
20+
autocomplete.listen_on_select(function(item) docs.show_item(item) end)
21+
autocomplete.listen_on_close(function() docs.win:close() end)
2122

2223
return docs
2324
end
2425

2526
-- todo: debounce and only update if the item changed
26-
function docs.set_item(item)
27+
function docs.show_item(item)
2728
if item == nil then
2829
docs.win:close()
2930
return
3031
end
31-
if not cmp_win.win:is_open() then return end
3232

3333
sources.resolve(item, function(resolved_item)
3434
if resolved_item.detail == nil then
@@ -43,7 +43,10 @@ function docs.set_item(item)
4343
vim.api.nvim_buf_set_lines(docs.win:get_buf(), 0, -1, true, doc_lines)
4444
vim.api.nvim_set_option_value('modified', false, { buf = docs.win:get_buf() })
4545

46-
docs.win:open()
46+
if autocomplete.win:get_win() then
47+
docs.win:open()
48+
docs.win:update_position(autocomplete.win:get_win())
49+
end
4750
end)
4851
end
4952

lua/blink/cmp/windows/lib.lua

+8-17
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,13 @@ function win.new(config)
77
self.config = {
88
width = config.width or 40,
99
max_height = config.max_height or 10,
10-
relative = config.relative or 'cursor',
1110
cursorline = config.cursorline or false,
1211
wrap = config.wrap or false,
1312
filetype = config.filetype or 'cmp_menu',
1413
winhighlight = config.winhighlight or 'Normal:NormalFloat,FloatBorder:NormalFloat',
1514
padding = config.padding,
1615
}
1716

18-
if self.config.relative == 'cursor' then
19-
vim.api.nvim_create_autocmd('CursorMovedI', {
20-
callback = function() self:update_position() end,
21-
})
22-
end
23-
2417
return self
2518
end
2619

@@ -65,8 +58,6 @@ function win:open()
6558
vim.api.nvim_set_option_value('concealcursor', 'n', { win = self.id })
6659
vim.api.nvim_set_option_value('cursorlineopt', 'line', { win = self.id })
6760
vim.api.nvim_set_option_value('cursorline', self.config.cursorline, { win = self.id })
68-
69-
self:update_position()
7061
end
7162

7263
function win:close()
@@ -77,7 +68,7 @@ function win:close()
7768
end
7869

7970
-- todo: dynamic width
80-
function win:update_position()
71+
function win:update_position(relative_to)
8172
if not self:is_open() then return end
8273
local winnr = self:get_win()
8374
local config = self.config
@@ -94,7 +85,7 @@ function win:update_position()
9485
vim.api.nvim_win_set_height(winnr, height)
9586

9687
-- relative to cursor
97-
if config.relative == 'cursor' then
88+
if relative_to == 'cursor' then
9889
local is_space_below = screen_height - cursor_row > height
9990

10091
if is_space_below then
@@ -104,27 +95,27 @@ function win:update_position()
10495
end
10596

10697
-- relative to window
107-
elseif config.relative.id ~= nil then
108-
local relative_win_config = vim.api.nvim_win_get_config(config.relative.id)
98+
elseif type(relative_to) == 'number' then
99+
local relative_win_config = vim.api.nvim_win_get_config(relative_to)
109100

110-
-- todo: why is there a -5 here?
111-
local max_width_right = screen_width - cursor_col - relative_win_config.width - 5
101+
-- todo: why is there a -7 here? probably the signcolumn stuff?
102+
local max_width_right = screen_width - cursor_col - relative_win_config.width - 7
112103
local max_width_left = cursor_col
113104

114105
local width = math.min(math.max(max_width_left, max_width_right), config.width)
115106

116107
if max_width_right >= config.width or max_width_right >= max_width_left then
117108
vim.api.nvim_win_set_config(winnr, {
118109
relative = 'win',
119-
win = config.relative.id,
110+
win = relative_to,
120111
row = 0,
121112
col = relative_win_config.width,
122113
width = width,
123114
})
124115
else
125116
vim.api.nvim_win_set_config(winnr, {
126117
relative = 'win',
127-
win = config.relative.id,
118+
win = relative_to,
128119
row = 0,
129120
col = -width,
130121
width = width,

0 commit comments

Comments
 (0)