Skip to content

Commit 6e15864

Browse files
committed
feat: more robust preview for auto_insert mode
closes #117
1 parent 213fd94 commit 6e15864

File tree

5 files changed

+66
-28
lines changed

5 files changed

+66
-28
lines changed

lua/blink/cmp/accept/init.lua

+5
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ local brackets_lib = require('blink.cmp.accept.brackets')
44
--- Applies a completion item to the current buffer
55
--- @param item blink.cmp.CompletionItem
66
local function accept(item)
7+
-- create an undo point
8+
if require('blink.cmp.config').accept.create_undo_point then
9+
vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes('<C-g>u', true, true, true), 'n', true)
10+
end
11+
712
item = vim.deepcopy(item)
813
item.textEdit = text_edits_lib.get_from_item(item)
914

lua/blink/cmp/accept/preview.lua

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
--- @param item blink.cmp.CompletionItem
2+
local function preview(item)
3+
local text_edits_lib = require('blink.cmp.accept.text-edits')
4+
local text_edit = text_edits_lib.get_from_item(item)
5+
6+
-- for snippets, expand them with the default property names
7+
if item.insertTextFormat == vim.lsp.protocol.InsertTextFormat.Snippet then
8+
local expanded_snippet = require('blink.cmp.sources.snippets.utils').safe_parse(text_edit.newText)
9+
text_edit.newText = expanded_snippet and tostring(expanded_snippet) or text_edit.newText
10+
end
11+
12+
text_edits_lib.apply_text_edits(item.client_id, { text_edit })
13+
vim.api.nvim_win_set_cursor(0, {
14+
text_edit.range.start.line + 1,
15+
text_edit.range.start.character + #text_edit.newText,
16+
})
17+
18+
return text_edit
19+
end
20+
21+
return preview

lua/blink/cmp/accept/text-edits.lua

+20-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
local config = require('blink.cmp.config')
22
local text_edits = {}
33

4+
--- @param item blink.cmp.CompletionItem
5+
--- @return lsp.TextEdit
46
function text_edits.get_from_item(item)
57
-- Adjust the position of the text edit to be the current cursor position
68
-- since the data might be outdated. We compare the cursor column position
@@ -17,12 +19,28 @@ function text_edits.get_from_item(item)
1719
return text_edits.guess_text_edit(item)
1820
end
1921

22+
--- @param client_id number
23+
--- @param edits lsp.TextEdit[]
2024
function text_edits.apply_text_edits(client_id, edits)
2125
local client = vim.lsp.get_client_by_id(client_id)
2226
local offset_encoding = client ~= nil and client.offset_encoding or 'utf-16'
2327
vim.lsp.util.apply_text_edits(edits, vim.api.nvim_get_current_buf(), offset_encoding)
2428
end
2529

30+
--- @param text_edit lsp.TextEdit
31+
function text_edits.undo_text_edit(text_edit)
32+
text_edit = vim.deepcopy(text_edit)
33+
local lines = vim.split(text_edit.newText, '\n')
34+
local range = text_edit.range
35+
36+
range['end'].line = range.start.line + #lines - 1
37+
range['end'].character = lines[#lines] and #lines[#lines] or 0
38+
text_edit.newText = ''
39+
40+
vim.lsp.util.apply_text_edits({ text_edit }, vim.api.nvim_get_current_buf(), 'utf-16')
41+
end
42+
43+
--- @param item blink.cmp.CompletionItem
2644
function text_edits.apply_additional_text_edits(item)
2745
-- Apply additional text edits
2846
-- LSPs can either include these in the initial response or require a resolve
@@ -38,7 +56,8 @@ function text_edits.apply_additional_text_edits(item)
3856
end
3957
end
4058

41-
-- todo: doesnt work when the item contains characters not included in the context regex
59+
--- @param item blink.cmp.CompletionItem
60+
--- todo: doesnt work when the item contains characters not included in the context regex
4261
function text_edits.guess_text_edit(item)
4362
local word = item.textEditText or item.insertText or item.label
4463

lua/blink/cmp/init.lua

+1-6
Original file line numberDiff line numberDiff line change
@@ -142,12 +142,7 @@ cmp.accept = function()
142142
local item = cmp.windows.autocomplete.get_selected_item()
143143
if item == nil then return end
144144

145-
-- create an undo point
146-
if require('blink.cmp.config').accept.create_undo_point then
147-
vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes('<C-g>u', true, true, true), 'n', true)
148-
end
149-
150-
vim.schedule(function() require('blink.cmp.accept')(item) end)
145+
vim.schedule(function() cmp.windows.autocomplete.accept() end)
151146
return true
152147
end
153148

lua/blink/cmp/windows/autocomplete.lua

+19-21
Original file line numberDiff line numberDiff line change
@@ -158,39 +158,37 @@ function autocomplete.listen_on_position_update(callback)
158158
table.insert(autocomplete.event_targets.on_position_update, callback)
159159
end
160160

161-
---------- Selection ----------
161+
---------- Selection/Accept ----------
162+
163+
function autocomplete.accept()
164+
local selected_item = autocomplete.get_selected_item()
165+
if selected_item == nil then return end
166+
167+
-- undo the preview if it exists
168+
if autocomplete.preview_text_edit ~= nil and autocomplete.preview_context_id == autocomplete.context.id then
169+
text_edits_lib.undo_text_edit(autocomplete.preview_text_edit)
170+
end
171+
172+
-- apply
173+
require('blink.cmp.accept')(selected_item)
174+
return true
175+
end
162176

163177
--- @param line number
164178
local function select(line)
165-
local prev_selected_item = autocomplete.get_selected_item()
166-
167179
autocomplete.set_has_selected(true)
168180
vim.api.nvim_win_set_cursor(autocomplete.win:get_win(), { line, 0 })
169181

170182
local selected_item = autocomplete.get_selected_item()
171183

172184
-- when auto_insert is enabled, we immediately apply the text edit
173-
-- todo: move this to the accept module
174185
if config.windows.autocomplete.selection == 'auto_insert' and selected_item ~= nil then
175186
require('blink.cmp.trigger.completion').suppress_events_for_callback(function()
176-
local text_edit = text_edits_lib.get_from_item(selected_item)
177-
178-
if selected_item.insertTextFormat == vim.lsp.protocol.InsertTextFormat.Snippet then
179-
text_edit.newText = selected_item.label
180-
end
181-
182-
if
183-
prev_selected_item ~= nil and prev_selected_item.insertTextFormat == vim.lsp.protocol.InsertTextFormat.Snippet
184-
then
185-
local current_col = vim.api.nvim_win_get_cursor(0)[2]
186-
text_edit.range.start.character = current_col - #prev_selected_item.label
187+
if autocomplete.preview_text_edit ~= nil and autocomplete.preview_context_id == autocomplete.context.id then
188+
text_edits_lib.undo_text_edit(autocomplete.preview_text_edit)
187189
end
188-
189-
text_edits_lib.apply_text_edits(selected_item.client_id, { text_edit })
190-
vim.api.nvim_win_set_cursor(0, {
191-
text_edit.range.start.line + 1,
192-
text_edit.range.start.character + #text_edit.newText,
193-
})
190+
autocomplete.preview_text_edit = require('blink.cmp.accept.preview')(selected_item)
191+
autocomplete.preview_context_id = autocomplete.context.id
194192
end)
195193
end
196194

0 commit comments

Comments
 (0)