@@ -92,14 +92,21 @@ function M.setup(_server)
9292 end
9393
9494 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 })
96100 end
97101
98102 if bindings .accept_word and bindings .accept_word ~= " " then
99103 vim .keymap .set (
100104 " i" ,
101105 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 ,
103110 { silent = true , expr = true , script = true , nowait = true }
104111 )
105112 end
@@ -108,7 +115,10 @@ function M.setup(_server)
108115 vim .keymap .set (
109116 " i" ,
110117 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 ,
112122 { silent = true , expr = true , script = true , nowait = true }
113123 )
114124 end
@@ -122,6 +132,18 @@ function M.setup(_server)
122132 })
123133end
124134
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+
125147function M .set_style ()
126148 if vim .fn .has (" termguicolors" ) == 1 and vim .o .termguicolors then
127149 vim .api .nvim_set_hl (0 , hlgroup , { fg = " #808080" , default = true })
@@ -136,15 +158,64 @@ function M.get_completion_text()
136158 return completion_text or " "
137159end
138160
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 )
141195
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 )
142213 if not (vim .fn .mode ():match (" ^[iR]" )) then
143- return default
214+ return
144215 end
145216
146217 if current_completion == nil then
147- return default
218+ return
148219 end
149220
150221 local range = current_completion .range
@@ -156,29 +227,24 @@ local function completion_inserter(current_completion, insert_text)
156227
157228 local text = insert_text .. suffix_text
158229 if text == " " then
159- return default
230+ return
160231 end
161232
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 )
168234
169- local insert_text = ' <C-R><C-O>=v:lua.require("codeium.virtual_text").get_completion_text()<CR>'
170235 M .completion_text = text
171236
172- local cursor_text = delta == 0 and " " or ' <C-O>:exe "go" line2byte(line("."))+col(".")+(' .. delta .. " )<CR>"
173-
174237 server .accept_completion (current_completion .completion .completionId )
238+ local lines = str_to_lines (text )
175239
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 )
177243end
178244
179245function M .accept ()
180246 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 " " )
182248end
183249
184250function M .accept_next_word ()
@@ -190,13 +256,20 @@ function M.accept_next_word()
190256 local prefix_text = completion_parts [1 ].prefix or " "
191257 local completion_text = completion_parts [1 ].text or " "
192258 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 )
194260end
195261
196262function M .accept_next_line ()
197263 local current_completion = M .get_current_completion_item ()
198264 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
200273end
201274
202275function M .get_current_completion_item ()
0 commit comments