@@ -92,14 +92,21 @@ function M.setup(_server)
92
92
end
93
93
94
94
if bindings .accept and bindings .accept ~= " " then
95
- vim .keymap .set (" i" , bindings .accept , M .accept , { silent = true , expr = true , script = true , nowait = true })
95
+ vim .keymap .set (" i" , bindings .accept , function ()
96
+ if not M .has_suggestions () then return bindings .accept end
97
+ M .accept_suggestion ()
98
+ end ,
99
+ { silent = true , expr = true , script = true , nowait = true })
96
100
end
97
101
98
102
if bindings .accept_word and bindings .accept_word ~= " " then
99
103
vim .keymap .set (
100
104
" i" ,
101
105
bindings .accept_word ,
102
- M .accept_next_word ,
106
+ function ()
107
+ if not M .has_suggestions () then return bindings .accept_word end
108
+ M .accept_word ()
109
+ end ,
103
110
{ silent = true , expr = true , script = true , nowait = true }
104
111
)
105
112
end
@@ -108,7 +115,10 @@ function M.setup(_server)
108
115
vim .keymap .set (
109
116
" i" ,
110
117
bindings .accept_line ,
111
- M .accept_next_line ,
118
+ function ()
119
+ if not M .has_suggestions () then return bindings .accept_line end
120
+ M .accept_line ()
121
+ end ,
112
122
{ silent = true , expr = true , script = true , nowait = true }
113
123
)
114
124
end
@@ -122,6 +132,18 @@ function M.setup(_server)
122
132
})
123
133
end
124
134
135
+ M .accept_suggestion = vim .schedule_wrap (function ()
136
+ M .accept ()
137
+ end )
138
+
139
+ M .accept_line = vim .schedule_wrap (function ()
140
+ M .accept_next_line ()
141
+ end )
142
+
143
+ M .accept_word = vim .schedule_wrap (function ()
144
+ M .accept_next_word ()
145
+ end )
146
+
125
147
function M .set_style ()
126
148
if vim .fn .has (" termguicolors" ) == 1 and vim .o .termguicolors then
127
149
vim .api .nvim_set_hl (0 , hlgroup , { fg = " #808080" , default = true })
@@ -136,15 +158,64 @@ function M.get_completion_text()
136
158
return completion_text or " "
137
159
end
138
160
139
- local function completion_inserter (current_completion , insert_text )
140
- local default = config .options .virtual_text .accept_fallback or (vim .fn .pumvisible () == 1 and " <C-N>" or " \t " )
161
+ local function str_to_lines (str )
162
+ return vim .fn .split (str , " \n " )
163
+ end
164
+
165
+ local function move_cursor (offset )
166
+ local row , col = unpack (vim .api .nvim_win_get_cursor (0 ))
167
+ local target_row , target_col = row , col + offset
168
+ while target_col < 0 and target_row > 1 do
169
+ target_row = target_row - 1
170
+ local prev_line = vim .api .nvim_buf_get_lines (0 , target_row - 1 , target_row , false )[1 ]
171
+ target_col = # prev_line + target_col + 1
172
+ end
173
+
174
+ if target_col < 0 then
175
+ target_col = 0
176
+ end
177
+
178
+ vim .api .nvim_win_set_cursor (0 , { target_row , target_col })
179
+ end
180
+
181
+
182
+ local function delete_file_range (start_offset , end_offset )
183
+ if end_offset <= start_offset then
184
+ return
185
+ end
186
+
187
+ local start_line = vim .fn .byte2line (start_offset + 1 )
188
+ local end_line = vim .fn .byte2line (end_offset )
189
+
190
+ local start_col = start_offset - vim .fn .line2byte (start_line ) + 1
191
+ local end_col = end_offset - vim .fn .line2byte (end_line ) + 1
192
+
193
+ local start_line_content = vim .fn .getline (start_line )
194
+ local updated_start_line = start_line_content :sub (1 , start_col )
141
195
196
+ local end_line_content = vim .fn .getline (end_line )
197
+ local updated_end_line = end_line_content :sub (end_col + 1 )
198
+
199
+ if start_line == end_line then
200
+ local updated_line = updated_start_line .. updated_end_line
201
+ vim .fn .setline (start_line , updated_line )
202
+ else
203
+ vim .fn .setline (start_line , updated_start_line )
204
+ vim .fn .setline (end_line , updated_end_line )
205
+ vim .api .nvim_buf_set_lines (0 , start_line , end_line - 1 , false , {})
206
+ end
207
+
208
+ vim .api .nvim_win_set_cursor (0 , { start_line , start_col })
209
+ end
210
+
211
+
212
+ local function completion_inserter (current_completion , insert_text )
142
213
if not (vim .fn .mode ():match (" ^[iR]" )) then
143
- return default
214
+ return
144
215
end
145
216
146
217
if current_completion == nil then
147
- return default
218
+ return
148
219
end
149
220
150
221
local range = current_completion .range
@@ -156,29 +227,24 @@ local function completion_inserter(current_completion, insert_text)
156
227
157
228
local text = insert_text .. suffix_text
158
229
if text == " " then
159
- return default
230
+ return
160
231
end
161
232
162
- local delete_range = " "
163
- if end_offset - start_offset > 0 then
164
- local delete_bytes = end_offset - start_offset
165
- local delete_chars = vim .fn .strchars (vim .fn .strpart (vim .fn .getline (" ." ), 0 , delete_bytes ))
166
- delete_range = ' <Esc>"_x0"_d' .. delete_chars .. " li"
167
- end
233
+ delete_file_range (start_offset , end_offset )
168
234
169
- local insert_text = ' <C-R><C-O>=v:lua.require("codeium.virtual_text").get_completion_text()<CR>'
170
235
M .completion_text = text
171
236
172
- local cursor_text = delta == 0 and " " or ' <C-O>:exe "go" line2byte(line("."))+col(".")+(' .. delta .. " )<CR>"
173
-
174
237
server .accept_completion (current_completion .completion .completionId )
238
+ local lines = str_to_lines (text )
175
239
176
- return ' <C-g>u' .. delete_range .. insert_text .. cursor_text
240
+ vim .api .nvim_put (lines , " c" , false , true )
241
+
242
+ move_cursor (delta )
177
243
end
178
244
179
245
function M .accept ()
180
246
local current_completion = M .get_current_completion_item ()
181
- return completion_inserter (current_completion , current_completion and current_completion .completion .text or " " )
247
+ completion_inserter (current_completion , current_completion and current_completion .completion .text or " " )
182
248
end
183
249
184
250
function M .accept_next_word ()
@@ -190,13 +256,20 @@ function M.accept_next_word()
190
256
local prefix_text = completion_parts [1 ].prefix or " "
191
257
local completion_text = completion_parts [1 ].text or " "
192
258
local next_word = completion_text :match (" ^%W*%w*" )
193
- return completion_inserter (current_completion , prefix_text .. next_word )
259
+ completion_inserter (current_completion , prefix_text .. next_word )
194
260
end
195
261
196
262
function M .accept_next_line ()
197
263
local current_completion = M .get_current_completion_item ()
198
264
local text = current_completion and current_completion .completion .text :gsub (" \n .*$" , " " ) or " "
199
- return completion_inserter (current_completion , text )
265
+ completion_inserter (current_completion , text )
266
+ end
267
+
268
+ function M .has_suggestions ()
269
+ local current_completion = M .get_current_completion_item ()
270
+ local suffix = current_completion and current_completion .suffix or {}
271
+ local suffix_text = suffix and suffix .text or " "
272
+ return current_completion and current_completion .completion .text .. suffix_text
200
273
end
201
274
202
275
function M .get_current_completion_item ()
0 commit comments