Skip to content

Commit 0e0630c

Browse files
LUSEDOUAntoineGS
andauthored
feat(suggestion): accept keypress Copilot bypass (#258)
Allows passing the keypress to the buffer without triggering Copilot logic when the suggestion is not visible. This will work better if trigger_on_accept is false. Co-authored-by: Antoine Gaudreau Simard <[email protected]>
1 parent 14fb80f commit 0e0630c

8 files changed

+165
-2
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ require('copilot').setup({
9393
auto_trigger = false,
9494
hide_during_completion = true,
9595
debounce = 75,
96+
trigger_on_accept = true,
9697
keymap = {
9798
accept = "<M-l>",
9899
accept_word = false,
@@ -171,6 +172,7 @@ require("copilot.panel").refresh()
171172

172173
When `auto_trigger` is `true`, copilot starts suggesting as soon as you enter insert mode.
173174
When `auto_trigger` is `false`, use the `next`, `prev` or `accept` keymap to trigger copilot suggestion.
175+
When `trigger_on_accept` is `false`, the keypress will be passed to the buffer as-is, instead of triggering completion.
174176

175177
To toggle auto trigger for the current buffer, use `require("copilot.suggestion").toggle_auto_trigger()`.
176178

lua/copilot/config/suggestion.lua

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
---@field auto_trigger boolean Whether to trigger the suggestion automatically
44
---@field hide_during_completion boolean Whether to hide the suggestion during completion
55
---@field debounce integer Debounce time in milliseconds
6+
---@field trigger_on_accept boolean To either trigger the suggestion on accept or pass the keystroke to the buffer
67
---@field keymap SuggestionKeymapConfig Keymap for the suggestion
78

89
---@class (exact) SuggestionKeymapConfig
@@ -20,6 +21,7 @@ local suggestion = {
2021
auto_trigger = false,
2122
hide_during_completion = true,
2223
debounce = 15,
24+
trigger_on_accept = true,
2325
keymap = {
2426
accept = "<M-l>",
2527
accept_word = false,
@@ -36,6 +38,7 @@ function suggestion.validate(config)
3638
vim.validate("auto_trigger", config.auto_trigger, "boolean")
3739
vim.validate("hide_during_completion", config.hide_during_completion, "boolean")
3840
vim.validate("debounce", config.debounce, { "number", "nil" })
41+
vim.validate("trigger_on_accept", config.trigger_on_accept, "boolean")
3942
vim.validate("keymap", config.keymap, "table")
4043
vim.validate("keymap.accept", config.keymap.accept, { "string", "boolean" })
4144
vim.validate("keymap.accept_word", config.keymap.accept_word, { "string", "boolean" })

lua/copilot/suggestion/init.lua

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,16 @@ end
7070

7171
local function set_keymap(keymap)
7272
if keymap.accept then
73-
vim.keymap.set("i", keymap.accept, M.accept, {
73+
vim.keymap.set("i", keymap.accept, function()
74+
local ctx = get_ctx()
75+
-- If we trigger on accept but the suggestion has not been triggered yet, we let it go through so it does
76+
if (config.suggestion.trigger_on_accept and not ctx.first) or M.is_visible() then
77+
M.accept()
78+
else
79+
local termcode = vim.api.nvim_replace_termcodes(keymap.accept, true, false, true)
80+
vim.api.nvim_feedkeys(termcode, "n", true)
81+
end
82+
end, {
7483
desc = "[copilot] accept suggestion",
7584
silent = true,
7685
})
@@ -475,7 +484,7 @@ function M.accept(modifier)
475484
logger.trace("suggestion accept", ctx)
476485

477486
-- no suggestion request yet
478-
if not ctx.first then
487+
if (not ctx.first) and config.suggestion.trigger_on_accept then
479488
logger.trace("suggestion accept, not first request", ctx)
480489
schedule(ctx)
481490
return

lua/copilot/util.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ function M.get_doc()
7777
return doc
7878
end
7979

80+
-- Used by copilot.cmp to watch out if moving it
8081
function M.get_doc_params(overrides)
8182
overrides = overrides or {}
8283

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
--|---------|-----
2+
01|123
3+
02|456
4+
03|7
5+
04|~
6+
05|~
7+
06|~
8+
07|~
9+
08|~
10+
09|<e] [+] 3,3-9
11+
10|-- INSERT --
12+
13+
--|---------|-----
14+
01|000000000000000
15+
02|000000000000000
16+
03|000000000000000
17+
04|111111111111111
18+
05|111111111111111
19+
06|111111111111111
20+
07|111111111111111
21+
08|111111111111111
22+
09|222222222222222
23+
10|333333333333444
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
--|---------|-----
2+
01|123
3+
02|456
4+
03|789
5+
04|~
6+
05|~
7+
06|~
8+
07|~
9+
08|~
10+
09|<e] [+] 3,2 All
11+
10|-- INSERT --
12+
13+
--|---------|-----
14+
01|000000000000000
15+
02|000000000000000
16+
03|011000000000000
17+
04|222222222222222
18+
05|222222222222222
19+
06|222222222222222
20+
07|222222222222222
21+
08|222222222222222
22+
09|333333333333333
23+
10|444444444444555
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
--|---------|-----
2+
01|123
3+
02|456
4+
03|7
5+
04|~
6+
05|~
7+
06|~
8+
07|~
9+
08|~
10+
09|<e] [+] 3,2 All
11+
10|-- INSERT --
12+
13+
--|---------|-----
14+
01|000000000000000
15+
02|000000000000000
16+
03|000000000000000
17+
04|111111111111111
18+
05|111111111111111
19+
06|111111111111111
20+
07|111111111111111
21+
08|111111111111111
22+
09|222222222222222
23+
10|333333333333444

tests/test_suggestion.lua

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,4 +51,83 @@ T["suggestion()"]["suggestion works"] = function()
5151
reference_screenshot(child.get_screenshot())
5252
end
5353

54+
T["suggestion()"]["auto_trigger is false, will not show ghost test"] = function()
55+
child.o.lines, child.o.columns = 10, 15
56+
child.lua([[M.setup({
57+
suggestion = {
58+
auto_trigger = false,
59+
},
60+
logger = {
61+
file_log_level = vim.log.levels.TRACE,
62+
file = "./tests/logs/test_suggestion.log",
63+
},
64+
filetypes = {
65+
["*"] = true,
66+
},
67+
})]])
68+
69+
-- look for a synchronous way to wait for engine to be up
70+
vim.loop.sleep(500)
71+
child.type_keys("i123", "<Esc>", "o456", "<Esc>", "o7")
72+
vim.loop.sleep(3000)
73+
child.lua("vim.wait(0)")
74+
75+
reference_screenshot(child.get_screenshot())
76+
end
77+
78+
T["suggestion()"]["accept keymap to trigger sugestion"] = function()
79+
child.o.lines, child.o.columns = 10, 15
80+
child.lua([[M.setup({
81+
suggestion = {
82+
auto_trigger = false,
83+
keymap = {
84+
accept = "<Tab>",
85+
},
86+
},
87+
logger = {
88+
file_log_level = vim.log.levels.TRACE,
89+
file = "./tests/logs/test_suggestion.log",
90+
},
91+
filetypes = {
92+
["*"] = true,
93+
},
94+
})]])
95+
96+
-- look for a synchronous way to wait for engine to be up
97+
vim.loop.sleep(500)
98+
child.type_keys("i123", "<Esc>", "o456", "<Esc>", "o7", "<Tab>")
99+
vim.loop.sleep(3000)
100+
child.lua("vim.wait(0)")
101+
102+
reference_screenshot(child.get_screenshot())
103+
end
104+
105+
T["suggestion()"]["accept keymap, no suggestion, execute normal keystroke"] = function()
106+
child.o.lines, child.o.columns = 10, 15
107+
child.lua([[M.setup({
108+
suggestion = {
109+
auto_trigger = false,
110+
trigger_on_accept = false,
111+
keymap = {
112+
accept = "<Tab>",
113+
},
114+
},
115+
logger = {
116+
file_log_level = vim.log.levels.TRACE,
117+
file = "./tests/logs/test_suggestion.log",
118+
},
119+
filetypes = {
120+
["*"] = true,
121+
},
122+
})]])
123+
124+
-- look for a synchronous way to wait for engine to be up
125+
vim.loop.sleep(500)
126+
child.type_keys("i123", "<Esc>", "o456", "<Esc>", "o7", "<Tab>")
127+
vim.loop.sleep(3000)
128+
child.lua("vim.wait(0)")
129+
130+
reference_screenshot(child.get_screenshot())
131+
end
132+
54133
return T

0 commit comments

Comments
 (0)