1
1
local M = {}
2
+ local config = require (" copilot-lsp.config" ).config
2
3
3
4
--- @param bufnr integer
4
5
--- @param ns_id integer
10
11
--- @param ns_id integer
11
12
function M .clear_suggestion (bufnr , ns_id )
12
13
bufnr = bufnr and bufnr > 0 and bufnr or vim .api .nvim_get_current_buf ()
14
+ -- Validate buffer exists before accessing buffer-scoped variables
15
+ if not vim .api .nvim_buf_is_valid (bufnr ) then
16
+ return
17
+ end
13
18
if vim .b [bufnr ].nes_jump then
14
19
vim .b [bufnr ].nes_jump = false
15
20
return
@@ -21,7 +26,11 @@ function M.clear_suggestion(bufnr, ns_id)
21
26
return
22
27
end
23
28
29
+ -- Clear buffer variables
24
30
vim .b [bufnr ].nes_state = nil
31
+ vim .b [bufnr ].copilotlsp_nes_cursor_moves = nil
32
+ vim .b [bufnr ].copilotlsp_nes_last_line = nil
33
+ vim .b [bufnr ].copilotlsp_nes_last_col = nil
25
34
end
26
35
27
36
--- @private
@@ -159,26 +168,110 @@ end
159
168
function M ._display_next_suggestion (bufnr , ns_id , edits )
160
169
M .clear_suggestion (bufnr , ns_id )
161
170
if not edits or # edits == 0 then
162
- -- vim.notify("No suggestion available", vim.log.levels.INFO)
163
171
return
164
172
end
165
173
166
174
local suggestion = edits [1 ]
167
-
168
175
local preview = M ._calculate_preview (bufnr , suggestion )
169
176
M ._display_preview (bufnr , ns_id , preview )
170
177
171
178
vim .b [bufnr ].nes_state = suggestion
179
+ vim .b [bufnr ].copilotlsp_nes_namespace_id = ns_id
180
+ vim .b [bufnr ].copilotlsp_nes_cursor_moves = 1
172
181
173
182
vim .api .nvim_create_autocmd ({ " CursorMoved" , " CursorMovedI" }, {
174
183
buffer = bufnr ,
175
184
callback = function ()
176
- if not vim .b .nes_state then
185
+ if not vim .b [bufnr ].nes_state then
186
+ return true
187
+ end
188
+
189
+ -- Get cursor position
190
+ local cursor = vim .api .nvim_win_get_cursor (0 )
191
+ local cursor_line = cursor [1 ] - 1 -- 0-indexed
192
+ local cursor_col = cursor [2 ]
193
+ local suggestion_line = suggestion .range .start .line
194
+
195
+ -- Store previous position
196
+ local last_line = vim .b [bufnr ].copilotlsp_nes_last_line or cursor_line
197
+ local last_col = vim .b [bufnr ].copilotlsp_nes_last_col or cursor_col
198
+
199
+ -- Update stored position
200
+ vim .b [bufnr ].copilotlsp_nes_last_line = cursor_line
201
+ vim .b [bufnr ].copilotlsp_nes_last_col = cursor_col
202
+
203
+ -- Calculate distance to suggestion
204
+ local line_distance = math.abs (cursor_line - suggestion_line )
205
+ local last_line_distance = math.abs (last_line - suggestion_line )
206
+
207
+ -- Check if cursor changed position on same line
208
+ local moved_horizontally = (cursor_line == last_line ) and (cursor_col ~= last_col )
209
+
210
+ -- Get current mode
211
+ local mode = vim .api .nvim_get_mode ().mode
212
+
213
+ -- Determine if we should count this movement
214
+ local should_count = false
215
+ local first_char = mode :sub (1 , 1 )
216
+
217
+ -- In insert mode, only count cursor movements, not text changes
218
+ if first_char == " i" then
219
+ if moved_horizontally or line_distance ~= last_line_distance then
220
+ should_count = true
221
+ end
222
+ elseif first_char == " v" or first_char == " V" or mode == " \22 " then
223
+ should_count = true
224
+ -- In normal mode with horizontal movement
225
+ elseif moved_horizontally and config .nes .count_horizontal_moves then
226
+ should_count = true
227
+ -- In normal mode with line changes
228
+ elseif line_distance > last_line_distance then
229
+ should_count = true
230
+ -- Moving toward suggestion in normal mode
231
+ elseif line_distance < last_line_distance and config .nes .reset_on_approaching then
232
+ if line_distance > 1 then -- Don't reset if 0 or 1 line away
233
+ vim .b [bufnr ].copilotlsp_nes_cursor_moves = 0
234
+ end
235
+ end
236
+
237
+ -- Update counter if needed
238
+ if should_count then
239
+ vim .b [bufnr ].copilotlsp_nes_cursor_moves = (vim .b [bufnr ].copilotlsp_nes_cursor_moves or 0 ) + 1
240
+ end
241
+
242
+ -- Clear if counter threshold reached
243
+ if vim .b [bufnr ].copilotlsp_nes_cursor_moves >= config .nes .move_count_threshold then
244
+ vim .b [bufnr ].copilotlsp_nes_cursor_moves = 0
245
+ vim .schedule (function ()
246
+ M .clear_suggestion (bufnr , ns_id )
247
+ end )
177
248
return true
178
249
end
179
250
180
- M .clear_suggestion (bufnr , ns_id )
181
- return true
251
+ -- Optional: Clear on large distance
252
+ if config .nes .clear_on_large_distance and line_distance > config .nes .distance_threshold then
253
+ M .clear_suggestion (bufnr , ns_id )
254
+ return true
255
+ end
256
+
257
+ return false -- Keep the autocmd
258
+ end ,
259
+ })
260
+ -- Also clear on text changes that affect the suggestion area
261
+ vim .api .nvim_create_autocmd ({ " TextChanged" , " TextChangedI" }, {
262
+ buffer = bufnr ,
263
+ callback = function ()
264
+ if not vim .b [bufnr ].nes_state then
265
+ return true
266
+ end
267
+ -- Check if the text at the suggestion position has changed
268
+ local start_line = suggestion .range .start .line
269
+ -- If the lines are no longer in the buffer, clear the suggestion
270
+ if start_line >= vim .api .nvim_buf_line_count (bufnr ) then
271
+ M .clear_suggestion (bufnr , ns_id )
272
+ return true
273
+ end
274
+ return false -- Keep the autocmd
182
275
end ,
183
276
})
184
277
end
0 commit comments