Skip to content

Commit 372ed1b

Browse files
committed
feat(suggestion): support partial accept
1 parent 94abd14 commit 372ed1b

File tree

2 files changed

+75
-13
lines changed

2 files changed

+75
-13
lines changed

lua/copilot/config.lua

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ local default_config = {
2121
---@type table<'accept'|'next'|'prev'|'dismiss', false|string>
2222
keymap = {
2323
accept = "<M-l>",
24+
accept_word = false,
25+
accept_line = false,
2426
next = "<M-]>",
2527
prev = "<M-[>",
2628
dismiss = "<C-]>",

lua/copilot/suggestion.lua

Lines changed: 73 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,20 @@ local function set_keymap(keymap)
7171
})
7272
end
7373

74+
if keymap.accept_word then
75+
vim.keymap.set("i", keymap.accept_word, mod.accept_word, {
76+
desc = "[copilot] accept suggestion (word)",
77+
silent = true,
78+
})
79+
end
80+
81+
if keymap.accept_line then
82+
vim.keymap.set("i", keymap.accept_line, mod.accept_line, {
83+
desc = "[copilot] accept suggestion (line)",
84+
silent = true,
85+
})
86+
end
87+
7488
if keymap.next then
7589
vim.keymap.set("i", keymap.next, mod.next, {
7690
desc = "[copilot] next suggestion",
@@ -348,22 +362,68 @@ function mod.prev()
348362
end)
349363
end
350364

351-
function mod.accept()
365+
---@param partial? 'word'|'line'
366+
local function accept_suggestion(partial)
352367
local suggestion = get_current_suggestion()
353-
if suggestion and vim.fn.empty(suggestion.text) == 0 then
354-
reset_state()
355-
with_client(function(client)
356-
api.notify_accepted(client, { uuid = suggestion.uuid }, function() end)
357-
end)
358-
copilot.uuid = nil
359-
clear_preview()
368+
if not suggestion or vim.fn.empty(suggestion.text) == 1 then
369+
return
370+
end
371+
372+
reset_state()
373+
with_client(function(client)
374+
if partial then
375+
-- do not notify_accepted for partial accept.
376+
-- revisit if upstream copilot.vim adds this feature.
377+
return
378+
end
379+
380+
api.notify_accepted(client, { uuid = suggestion.uuid }, function() end)
381+
end)
382+
copilot.uuid = nil
383+
clear_preview()
384+
385+
local range, newText = suggestion.range, suggestion.text
360386

361-
-- Hack for 'autoindent', makes the indent persist. Check `:help 'autoindent'`.
362-
vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes("<Space><Left><Del>", true, false, true), "n", false)
363-
vim.lsp.util.apply_text_edits({ { range = suggestion.range, newText = suggestion.text } }, 0, "utf-16")
364-
-- Put cursor at the end of current line.
365-
vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes("<End>", true, false, true), "n", false)
387+
if partial then
388+
local cursor = vim.api.nvim_win_get_cursor(0)
389+
local _, character = cursor[1], cursor[2]
390+
391+
if partial == "word" then
392+
local _, char_idx = string.find(newText, "%s*%p*[^%s%p]*%s*", character + 1)
393+
if not char_idx then
394+
return
395+
end
396+
397+
newText = string.sub(newText, 1, char_idx)
398+
399+
range["end"].line = range["start"].line
400+
range["end"].character = char_idx
401+
elseif partial == "line" then
402+
local next_char = string.sub(newText, character + 1, character + 1)
403+
local _, char_idx = string.find(newText, next_char == "\n" and "\n%s*[^\n]*\n%s*" or "\n%s*", character)
404+
if char_idx then
405+
newText = string.sub(newText, 1, char_idx)
406+
end
407+
end
366408
end
409+
410+
-- Hack for 'autoindent', makes the indent persist. Check `:help 'autoindent'`.
411+
vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes("<Space><Left><Del>", true, false, true), "n", false)
412+
vim.lsp.util.apply_text_edits({ { range = range, newText = newText } }, 0, "utf-16")
413+
-- Put cursor at the end of current line.
414+
vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes("<End>", true, false, true), "n", false)
415+
end
416+
417+
function mod.accept()
418+
accept_suggestion()
419+
end
420+
421+
function mod.accept_word()
422+
accept_suggestion("word")
423+
end
424+
425+
function mod.accept_line()
426+
accept_suggestion("line")
367427
end
368428

369429
function mod.dismiss()

0 commit comments

Comments
 (0)