Skip to content

Commit decc8d4

Browse files
committed
feat(suggestion): support suggestion modifier for .accept
1 parent a4a37dd commit decc8d4

File tree

3 files changed

+41
-33
lines changed

3 files changed

+41
-33
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ The `copilot.suggestion` module exposes the following functions:
133133

134134
```lua
135135
require("copilot.suggestion").is_visible()
136-
require("copilot.suggestion").accept()
136+
require("copilot.suggestion").accept(modifier)
137137
require("copilot.suggestion").accept_word()
138138
require("copilot.suggestion").accept_line()
139139
require("copilot.suggestion").next()

lua/copilot/api.lua

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,8 @@ function mod.notify_shown(client, params, callback)
115115
return mod.request(client, "notifyShown", params, callback)
116116
end
117117

118-
---@alias copilot_get_completions_data { completions: { displayText: string, position: { character: integer, line: integer }, range: { ['end']: { character: integer, line: integer }, start: { character: integer, line: integer } }, text: string, uuid: string }[] }
118+
---@alias copilot_get_completions_data_completion { displayText: string, position: { character: integer, line: integer }, range: { ['end']: { character: integer, line: integer }, start: { character: integer, line: integer } }, text: string, uuid: string }
119+
---@alias copilot_get_completions_data { completions: copilot_get_completions_data_completion[] }
119120

120121
---@return any|nil err
121122
---@return copilot_get_completions_data data

lua/copilot/suggestion.lua

Lines changed: 38 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ local copilot = {
2020
cycling = nil,
2121
cycling_callbacks = nil,
2222
params = nil,
23+
---@type copilot_get_completions_data_completion[]|nil
2324
suggestions = nil,
2425
choice = nil,
2526
},
@@ -160,6 +161,7 @@ local function clear_preview()
160161
vim.api.nvim_buf_del_extmark(0, copilot.ns_id, copilot.extmark_id)
161162
end
162163

164+
---@return copilot_get_completions_data_completion|nil
163165
local function get_current_suggestion()
164166
local ok, choice = pcall(function()
165167
if
@@ -392,16 +394,16 @@ function mod.prev()
392394
end)
393395
end
394396

395-
---@param partial? 'word'|'line'
396-
local function accept_suggestion(partial)
397+
---@param modifier? (fun(suggestion: copilot_get_completions_data_completion): copilot_get_completions_data_completion)
398+
function mod.accept(modifier)
397399
local suggestion = get_current_suggestion()
398400
if not suggestion or vim.fn.empty(suggestion.text) == 1 then
399401
return
400402
end
401403

402404
reset_state()
403405
with_client(function(client)
404-
if partial then
406+
if modifier then
405407
-- do not notify_accepted for partial accept.
406408
-- revisit if upstream copilot.vim adds this feature.
407409
return
@@ -412,48 +414,53 @@ local function accept_suggestion(partial)
412414
copilot.uuid = nil
413415
clear_preview()
414416

417+
if type(modifier) == "function" then
418+
suggestion = modifier(suggestion)
419+
end
420+
415421
local range, newText = suggestion.range, suggestion.text
416422

417-
if partial then
423+
-- Hack for 'autoindent', makes the indent persist. Check `:help 'autoindent'`.
424+
vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes("<Space><Left><Del>", true, false, true), "n", false)
425+
vim.lsp.util.apply_text_edits({ { range = range, newText = newText } }, 0, "utf-16")
426+
-- Put cursor at the end of current line.
427+
vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes("<End>", true, false, true), "n", false)
428+
end
429+
430+
function mod.accept_word()
431+
mod.accept(function(suggestion)
432+
local range, text = suggestion.range, suggestion.text
433+
418434
local cursor = vim.api.nvim_win_get_cursor(0)
419435
local _, character = cursor[1], cursor[2]
420436

421-
if partial == "word" then
422-
local _, char_idx = string.find(newText, "%s*%p*[^%s%p]*%s*", character + 1)
423-
if not char_idx then
424-
return
425-
end
426-
427-
newText = string.sub(newText, 1, char_idx)
437+
local _, char_idx = string.find(text, "%s*%p*[^%s%p]*%s*", character + 1)
438+
if char_idx then
439+
suggestion.text = string.sub(text, 1, char_idx)
428440

429441
range["end"].line = range["start"].line
430442
range["end"].character = char_idx
431-
elseif partial == "line" then
432-
local next_char = string.sub(newText, character + 1, character + 1)
433-
local _, char_idx = string.find(newText, next_char == "\n" and "\n%s*[^\n]*\n%s*" or "\n%s*", character)
434-
if char_idx then
435-
newText = string.sub(newText, 1, char_idx)
436-
end
437443
end
438-
end
439444

440-
-- Hack for 'autoindent', makes the indent persist. Check `:help 'autoindent'`.
441-
vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes("<Space><Left><Del>", true, false, true), "n", false)
442-
vim.lsp.util.apply_text_edits({ { range = range, newText = newText } }, 0, "utf-16")
443-
-- Put cursor at the end of current line.
444-
vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes("<End>", true, false, true), "n", false)
445+
return suggestion
446+
end)
445447
end
446448

447-
function mod.accept()
448-
accept_suggestion()
449-
end
449+
function mod.accept_line()
450+
mod.accept(function(suggestion)
451+
local text = suggestion.text
450452

451-
function mod.accept_word()
452-
accept_suggestion("word")
453-
end
453+
local cursor = vim.api.nvim_win_get_cursor(0)
454+
local _, character = cursor[1], cursor[2]
454455

455-
function mod.accept_line()
456-
accept_suggestion("line")
456+
local next_char = string.sub(text, character + 1, character + 1)
457+
local _, char_idx = string.find(text, next_char == "\n" and "\n%s*[^\n]*\n%s*" or "\n%s*", character)
458+
if char_idx then
459+
suggestion.text = string.sub(text, 1, char_idx)
460+
end
461+
462+
return suggestion
463+
end)
457464
end
458465

459466
function mod.dismiss()

0 commit comments

Comments
 (0)