Skip to content

Commit 1749e32

Browse files
authored
feat: added a preselect option to the cmp menu (#24)
* feat: Added a preselect option to the cmp menu * fix: implement requested changes * fix: silly not * fix: Completion select on the second line Squash me! * Add default config to the readme * Fix: duplicated field in default config
1 parent dbcda96 commit 1749e32

File tree

4 files changed

+52
-30
lines changed

4 files changed

+52
-30
lines changed

README.md

+5
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,11 @@ For LazyVim/distro users, you can disable nvim-cmp via:
156156
-- when true, will show the signature help window when the cursor comes after a trigger character when entering insert mode
157157
show_on_insert_on_trigger_character = true,
158158
},
159+
cycle = {
160+
from_bottom = true,
161+
from_top = true,
162+
},
163+
preselect = true,
159164
},
160165

161166
fuzzy = {

lua/blink/cmp/config.lua

+1-1
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ local config = {
246246
-- which directions to show the window,
247247
-- falling back to the next direction when there's not enough space
248248
direction_priority = { 's', 'n' },
249-
-- todo: implement
249+
-- done: :)
250250
preselect = true,
251251
-- Controls how the completion items are rendered on the popup window
252252
-- 'simple' will render the item's kind icon the left alongside the label

lua/blink/cmp/windows/autocomplete.lua

+42-29
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ local renderer = require('blink.cmp.windows.lib.render')
1010
local autocmp_config = config.windows.autocomplete
1111
local autocomplete = {
1212
items = {},
13+
has_selected = nil,
1314
context = nil,
1415
event_targets = {
1516
on_position_update = {},
@@ -25,7 +26,7 @@ function autocomplete.setup()
2526
max_height = autocmp_config.max_height,
2627
border = autocmp_config.border,
2728
winhighlight = autocmp_config.winhighlight,
28-
cursorline = true,
29+
cursorline = false,
2930
scrolloff = autocmp_config.scrolloff,
3031
})
3132

@@ -64,6 +65,7 @@ function autocomplete.open_with_items(context, items)
6465

6566
autocomplete.context = context
6667
autocomplete.update_position(context)
68+
autocomplete.set_has_selected(autocmp_config.preselect)
6769

6870
-- todo: some logic to maintain the selection if the user moved the cursor?
6971
vim.api.nvim_win_set_cursor(autocomplete.win:get_win(), { 1, 0 })
@@ -73,11 +75,13 @@ end
7375
function autocomplete.open()
7476
if autocomplete.win:is_open() then return end
7577
autocomplete.win:open()
78+
autocomplete.set_has_selected(autocmp_config.preselect)
7679
end
7780

7881
function autocomplete.close()
7982
if not autocomplete.win:is_open() then return end
8083
autocomplete.win:close()
84+
autocomplete.has_selected = autocmp_config.preselect
8185
autocomplete.event_targets.on_close()
8286
end
8387
function autocomplete.listen_on_close(callback) autocomplete.event_targets.on_close = callback end
@@ -136,49 +140,57 @@ end
136140
function autocomplete.select_next()
137141
if not autocomplete.win:is_open() then return end
138142

139-
local current_line = vim.api.nvim_win_get_cursor(autocomplete.win:get_win())[1]
140-
local line_count = vim.api.nvim_buf_line_count(autocomplete.win:get_buf())
141143
local cycle_from_bottom = config.windows.autocomplete.cycle.from_bottom
142-
local is_last_completion = current_line == line_count
143-
144-
-- at the end of completion list and the config is not enabled: do nothing
145-
if is_last_completion and not cycle_from_bottom then return end
146-
if is_last_completion then
147-
-- at the end of completion list and the config is enabled: cycle back to first completion
148-
vim.api.nvim_win_set_cursor(autocomplete.win:get_win(), { 1, 0 })
149-
autocomplete.event_targets.on_select(autocomplete.get_selected_item(), autocomplete.context)
144+
local l = #autocomplete.items
145+
local line = vim.api.nvim_win_get_cursor(autocomplete.win:get_win())[1]
146+
-- We need to ajust the disconnect between the line position
147+
-- on the window and the selected item
148+
if not autocomplete.has_selected then line = line - 1 end
149+
if line == l then
150+
-- at the end of completion list and the config is not enabled: do nothing
151+
if not cycle_from_bottom then return end
152+
line = 1
150153
else
151-
-- select next completion
152-
vim.api.nvim_win_set_cursor(autocomplete.win:get_win(), { current_line + 1, 0 })
153-
autocomplete.event_targets.on_select(autocomplete.get_selected_item(), autocomplete.context)
154+
line = line + 1
154155
end
156+
157+
autocomplete.set_has_selected(true)
158+
159+
autocomplete.win:set_option_values('cursorline', true)
160+
vim.api.nvim_win_set_cursor(autocomplete.win:get_win(), { line, 0 })
161+
autocomplete.event_targets.on_select(autocomplete.get_selected_item(), autocomplete.context)
155162
end
156163

157164
function autocomplete.select_prev()
158165
if not autocomplete.win:is_open() then return end
159166

160-
local current_line = vim.api.nvim_win_get_cursor(autocomplete.win:get_win())[1]
161-
local line_count = vim.api.nvim_buf_line_count(autocomplete.win:get_buf())
162167
local cycle_from_top = config.windows.autocomplete.cycle.from_top
163-
local is_first_completion = current_line == 1
164-
165-
-- at the beginning of completion list and the config is not enabled: do nothing
166-
if is_first_completion and not cycle_from_top then return end
167-
if is_first_completion then
168-
-- at the beginning of completion list and the config is enabled: cycle back to last completion
169-
vim.api.nvim_win_set_cursor(autocomplete.win:get_win(), { line_count, 0 })
170-
autocomplete.event_targets.on_select(autocomplete.get_selected_item(), autocomplete.context)
168+
local l = #autocomplete.items
169+
local line = vim.api.nvim_win_get_cursor(autocomplete.win:get_win())[1]
170+
if line <= 1 then
171+
if not cycle_from_top then return end
172+
line = l
171173
else
172-
-- select previous completion
173-
vim.api.nvim_win_set_cursor(autocomplete.win:get_win(), { math.max(current_line - 1, 1), 0 })
174-
autocomplete.event_targets.on_select(autocomplete.get_selected_item(), autocomplete.context)
174+
line = line - 1
175175
end
176+
177+
autocomplete.set_has_selected(true)
178+
179+
autocomplete.win:set_option_values('cursorline', true)
180+
vim.api.nvim_win_set_cursor(autocomplete.win:get_win(), { line, 0 })
181+
autocomplete.event_targets.on_select(autocomplete.get_selected_item(), autocomplete.context)
176182
end
177183

178184
function autocomplete.listen_on_select(callback) autocomplete.event_targets.on_select = callback end
179185

180186
---------- Rendering ----------
181187

188+
function autocomplete.set_has_selected(selected)
189+
if not autocomplete.win:is_open() then return end
190+
autocomplete.has_selected = selected
191+
autocomplete.win:set_option_values('cursorline', selected)
192+
end
193+
182194
function autocomplete.draw()
183195
local draw_fn = autocomplete.get_draw_fn()
184196
local icon_gap = config.nerd_font_variant == 'mono' and ' ' or ' '
@@ -247,8 +259,9 @@ end
247259

248260
function autocomplete.get_selected_item()
249261
if not autocomplete.win:is_open() then return end
250-
local current_line = vim.api.nvim_win_get_cursor(autocomplete.win:get_win())[1]
251-
return autocomplete.items[current_line]
262+
if not autocomplete.has_selected then return end
263+
local line = vim.api.nvim_win_get_cursor(autocomplete.win:get_win())[1]
264+
return autocomplete.items[line]
252265
end
253266

254267
return autocomplete

lua/blink/cmp/windows/lib/init.lua

+4
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,10 @@ function win:open()
8181
vim.api.nvim_set_option_value('scrolloff', self.config.scrolloff, { win = self.id })
8282
end
8383

84+
function win:set_option_values(option, value)
85+
vim.api.nvim_set_option_value(option, value, { win = self.id })
86+
end
87+
8488
function win:close()
8589
if self.id ~= nil then
8690
vim.api.nvim_win_close(self.id, true)

0 commit comments

Comments
 (0)