Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!: implement auto-insert option #65

Merged
merged 16 commits into from
Oct 11, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,8 @@ For LazyVim/distro users, you can disable nvim-cmp via:
direction_priority = { 's', 'n' },
-- whether to preselect the first item in the completion list
preselect = true,
-- Whether to insert the completion items automatically when selecting them. Requires `preselect = false`
auto_insert = true,
-- Controls how the completion items are rendered on the popup window
-- 'simple' will render the item's kind icon the left alongside the label
-- 'reversed' will render the label on the left and the kind icon + name on the right
Expand Down
2 changes: 1 addition & 1 deletion lua/blink/cmp/accept/text-edits.lua
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ function text_edits.get_from_item(item)
-- from when the items were fetched versus the current.
-- hack: is there a better way?
if item.textEdit ~= nil then
local text_edit = utils.shallow_copy(item.textEdit)
local text_edit = vim.deepcopy(item.textEdit)
local offset = vim.api.nvim_win_get_cursor(0)[2] - item.cursor_column
text_edit.range['end'].character = text_edit.range['end'].character + offset
return text_edit
Expand Down
3 changes: 3 additions & 0 deletions lua/blink/cmp/config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@
--- @field order? "top_down" | "bottom_up"
--- @field direction_priority? ("n" | "s")[]
--- @field preselect? boolean
--- @field auto_insert? boolean
--- @field winhighlight? string
--- @field scrolloff? number
--- @field draw? 'simple' | 'reversed' | function(blink.cmp.CompletionRenderContext): blink.cmp.Component[]
Expand Down Expand Up @@ -248,6 +249,8 @@ local config = {
direction_priority = { 's', 'n' },
-- whether to preselect the first item in the completion list
preselect = true,
-- Whether to insert the completion items automatically when selecting them. Requires `preselect = false`
auto_insert = true,
-- Controls how the completion items are rendered on the popup window
-- 'simple' will render the item's kind icon the left alongside the label
-- 'reversed' will render the label on the left and the kind icon + name on the right
Expand Down
6 changes: 6 additions & 0 deletions lua/blink/cmp/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,8 @@ cmp.hide = function()
end

cmp.accept = function()
require('blink.cmp.trigger.completion').triggered_by = 'accept'

local item = cmp.windows.autocomplete.get_selected_item()
if item == nil then return end

Expand All @@ -141,12 +143,16 @@ cmp.accept = function()
end

cmp.select_prev = function()
require('blink.cmp.trigger.completion').triggered_by = 'select'

if not cmp.windows.autocomplete.win:is_open() then return end
vim.schedule(cmp.windows.autocomplete.select_prev)
return true
end

cmp.select_next = function()
require('blink.cmp.trigger.completion').triggered_by = 'select'

if not cmp.windows.autocomplete.win:is_open() then return end
vim.schedule(cmp.windows.autocomplete.select_next)
return true
Expand Down
43 changes: 26 additions & 17 deletions lua/blink/cmp/trigger/completion.lua
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ local trigger = {
--- @type fun()
on_hide = function() end,
},
--- @type "select" | "accept" | nil
triggered_by = nil,
}

function trigger.activate_autocmds()
Expand All @@ -33,14 +35,15 @@ function trigger.activate_autocmds()
-- ignore if in a special buffer
if utils.is_special_buffer() then
trigger.hide()
-- character forces a trigger according to the sources, create a fresh context
-- character forces a trigger according to the sources, create a fresh context
elseif vim.tbl_contains(sources.get_trigger_characters(), last_char) then
trigger.context = nil
trigger.triggered_by = nil
trigger.show({ trigger_character = last_char })
-- character is part of the current context OR in an existing context
-- character is part of the current context OR in an existing context
elseif last_char:match(config.keyword_regex) ~= nil then
trigger.show()
-- nothing matches so hide
-- nothing matches so hide
else
trigger.hide()
end
Expand All @@ -63,21 +66,26 @@ function trigger.activate_autocmds()
and not vim.tbl_contains(config.show_on_insert_blocked_trigger_characters, char_under_cursor)
local is_on_context_char = char_under_cursor:match(config.keyword_regex) ~= nil

if is_within_bounds then
trigger.show()
elseif
-- check if we've gone 1 char behind the context and we're still on a context char
(is_on_context_char and trigger.context ~= nil and cursor_col == trigger.context.bounds.start_col - 1)
-- or if we've moved onto a trigger character
or (is_on_trigger and trigger.context ~= nil)
then
trigger.context = nil
trigger.show()
elseif config.show_on_insert_on_trigger_character and is_on_trigger and ev.event == 'InsertEnter' then
trigger.show({ trigger_character = char_under_cursor })
else
trigger.hide()
if trigger.triggered_by ~= 'select' then
if is_within_bounds then
trigger.show()
elseif
-- check if we've gone 1 char behind the context and we're still on a context char
(is_on_context_char and trigger.context ~= nil and cursor_col == trigger.context.bounds.start_col - 1)
-- or if we've moved onto a trigger character
or (is_on_trigger and trigger.context ~= nil)
then
trigger.context = nil
trigger.triggered_by = nil
trigger.show()
elseif config.show_on_insert_on_trigger_character and is_on_trigger and ev.event == 'InsertEnter' then
trigger.show({ trigger_character = char_under_cursor })
else
trigger.hide()
end
end

trigger.triggered_by = nil
end,
})

Expand Down Expand Up @@ -128,6 +136,7 @@ function trigger.hide()
if not trigger.context then return end

trigger.context = nil
trigger.triggered_by = nil
trigger.event_targets.on_hide()
end

Expand Down
32 changes: 24 additions & 8 deletions lua/blink/cmp/windows/autocomplete.lua
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

local config = require('blink.cmp.config')
local renderer = require('blink.cmp.windows.lib.render')
local text_edits_lib = require('blink.cmp.accept.text-edits')
local autocmp_config = config.windows.autocomplete
local autocomplete = {
items = {},
Expand Down Expand Up @@ -137,6 +138,27 @@ end

---------- Selection ----------

--- @param line number
local function select(line)
local auto_insert = config.windows.autocomplete.auto_insert

autocomplete.set_has_selected(true)
vim.api.nvim_win_set_cursor(autocomplete.win:get_win(), { line, 0 })

local selected_item = autocomplete.get_selected_item()

if auto_insert then
local text_edit = text_edits_lib.get_from_item(selected_item)
text_edits_lib.apply_text_edits(selected_item.client_id, { text_edit })
vim.api.nvim_win_set_cursor(0, {
text_edit.range.start.line + 1,
text_edit.range.start.character + #text_edit.newText,
})
end

autocomplete.event_targets.on_select(selected_item, autocomplete.context)
end

function autocomplete.select_next()
if not autocomplete.win:is_open() then return end

Expand All @@ -154,10 +176,7 @@ function autocomplete.select_next()
line = line + 1
end

autocomplete.set_has_selected(true)

vim.api.nvim_win_set_cursor(autocomplete.win:get_win(), { line, 0 })
autocomplete.event_targets.on_select(autocomplete.get_selected_item(), autocomplete.context)
select(line)
end

function autocomplete.select_prev()
Expand All @@ -173,10 +192,7 @@ function autocomplete.select_prev()
line = line - 1
end

autocomplete.set_has_selected(true)

vim.api.nvim_win_set_cursor(autocomplete.win:get_win(), { line, 0 })
autocomplete.event_targets.on_select(autocomplete.get_selected_item(), autocomplete.context)
select(line)
end

function autocomplete.listen_on_select(callback) autocomplete.event_targets.on_select = callback end
Expand Down