@@ -17,8 +17,13 @@ local BinaryLifecycle = {
1717 cursor = nil ,
1818 max_state_id_retention = 50 ,
1919 service_message_displayed = false ,
20+ changed_document_list = {},
21+ last_state = nil ,
22+ dust_strings = {},
2023}
2124
25+ BinaryLifecycle .HARD_SIZE_LIMIT = 10e6
26+
2227local timer = loop .new_timer ()
2328timer :start (
2429 0 ,
@@ -72,33 +77,22 @@ function BinaryLifecycle:greeting_message()
7277 loop .write (self .stdin , message ) -- fails silently
7378end
7479
80+ --- @param buffer integer
81+ --- @param file_name string
82+ --- @param event_type " text_changed" | " cursor"
7583function BinaryLifecycle :on_update (buffer , file_name , event_type )
7684 if config .ignore_filetypes [vim .bo .ft ] or vim .tbl_contains (config .ignore_filetypes , vim .bo .filetype ) then
7785 return
7886 end
7987 local buffer_text = u .get_text (buffer )
80- local updates = {
81- {
82- kind = " file_update" ,
83- path = file_name ,
84- content = buffer_text ,
85- },
86- }
87- local cursor = api .nvim_win_get_cursor (0 )
88- if cursor ~= nil then
89- local prefix = self :save_state_id (buffer , cursor , file_name )
90- if prefix == nil then
91- return
92- end
93- local offset = # prefix
94- updates [# updates + 1 ] = {
95- kind = " cursor_update" ,
96- path = file_name ,
97- offset = offset ,
98- }
88+ local file_path = vim .api .nvim_buf_get_name (buffer )
89+ if # buffer_text > self .HARD_SIZE_LIMIT then
90+ log :warn (" File is too large to send to server. Skipping..." )
91+ return
9992 end
10093
101- self :send_message (updates )
94+ self :document_changed (file_path , buffer_text )
95+ local cursor = api .nvim_win_get_cursor (0 )
10296 local completion_is_allowed = (buffer_text ~= self .last_text ) and (self .last_path == file_name )
10397 local context = {
10498 document_text = buffer_text ,
@@ -242,33 +236,19 @@ function BinaryLifecycle:on_error(err)
242236 log :error (" Error reading stdout: " .. err )
243237end
244238
239+ function BinaryLifecycle :send_json (msg )
240+ local message = vim .json .encode (msg ) .. " \n "
241+ loop .write (self .stdin , message ) -- fails silently
242+ end
243+
245244function BinaryLifecycle :send_message (updates )
246245 local state_update = {
247246 kind = " state_update" ,
248247 newId = tostring (self .current_state_id ),
249248 updates = updates ,
250249 }
251250
252- local message = vim .json .encode (state_update ) .. " \n "
253- loop .write (self .stdin , message ) -- fails silently
254- end
255-
256- function BinaryLifecycle :save_state_id (buffer , cursor , file_name )
257- self .current_state_id = self .current_state_id + 1
258- self :purge_old_states ()
259-
260- local status , prefix = pcall (u .get_cursor_prefix , buffer , cursor )
261- if not status then
262- return nil
263- end
264-
265- self .state_map [self .current_state_id ] = {
266- prefix = prefix ,
267- completion = {},
268- has_ended = false ,
269- }
270-
271- return prefix
251+ self :send_json (state_update )
272252end
273253
274254function BinaryLifecycle :purge_old_states ()
@@ -306,22 +286,48 @@ function BinaryLifecycle:poll_once()
306286 local text_split = u .get_text_before_after_cursor (cursor )
307287 local line_before_cursor = text_split .text_before_cursor
308288 local line_after_cursor = text_split .text_after_cursor
289+ if line_before_cursor == nil or line_after_cursor == nil then
290+ return
291+ end
309292 local status , prefix = pcall (u .get_cursor_prefix , buffer , cursor )
310293 if not status then
311294 return
312295 end
313- if line_before_cursor == nil or line_after_cursor == nil then
296+ local get_following_line = function (index )
297+ return u .safe_get_line (buffer , cursor [1 ] + index ) or " "
298+ end
299+ local cached_chain_info = nil -- TODO
300+ local query_state_id = self :submit_query (buffer , prefix )
301+ if query_state_id == nil then
314302 return
315303 end
316- local maybe_completion = self :check_state (prefix , line_before_cursor , line_after_cursor )
304+ local maybe_completion = self :check_state (
305+ prefix ,
306+ line_before_cursor ,
307+ line_after_cursor ,
308+ false ,
309+ get_following_line ,
310+ query_state_id ,
311+ cached_chain_info
312+ )
317313
318314 if maybe_completion == nil then
319315 preview :dispose_inlay ()
320316 return
321317 end
322318
319+ if maybe_completion .kind == " jump" then
320+ return
321+ elseif maybe_completion .kind == " delete" then
322+ return
323+ elseif maybe_completion .kind == " skip" then
324+ return
325+ end
326+
323327 self .wants_polling = maybe_completion .is_incomplete
324- if # maybe_completion .dedent > 0 and not u .ends_with (line_before_cursor , maybe_completion .dedent ) then
328+ if maybe_completion .dedent == nil or
329+ (# maybe_completion .dedent > 0 and not u .ends_with (line_before_cursor , maybe_completion .dedent ))
330+ then
325331 return
326332 end
327333
@@ -339,11 +345,37 @@ function BinaryLifecycle:poll_once()
339345 preview :render_with_inlay (buffer , prior_delete , maybe_completion .text , line_after_cursor , line_before_cursor )
340346end
341347
342- function BinaryLifecycle :check_state (prefix , line_before_cursor , line_after_cursor )
348+ --- @param prefix string
349+ --- @param line_before_cursor string
350+ --- @param line_after_cursor string
351+ --- @param can_retry boolean
352+ --- @param get_following_line fun ( line : string ): string
353+ --- @param query_state_id integer
354+ --- @param cached_chain_info ChainInfo | nil
355+ --- @return AnyCompletion | nil
356+ function BinaryLifecycle :check_state (
357+ prefix ,
358+ line_before_cursor ,
359+ line_after_cursor ,
360+ can_retry ,
361+ get_following_line ,
362+ query_state_id ,
363+ cached_chain_info
364+ )
365+ local params = {
366+ line_before_cursor = line_before_cursor ,
367+ line_after_cursor = line_after_cursor ,
368+ get_following_line = get_following_line ,
369+ dust_strings = self .dust_strings ,
370+ can_show_partial_line = true ,
371+ can_retry = can_retry ,
372+ source_state_id = query_state_id ,
373+ }
374+
343375 self :check_process ()
344376 local best_completion = {}
345377 local best_length = 0
346- local best_state_id = 0
378+ local best_state_id = - 1
347379
348380 for state_id , state in pairs (self .state_map ) do
349381 local state_prefix = state .prefix
@@ -363,13 +395,6 @@ function BinaryLifecycle:check_state(prefix, line_before_cursor, line_after_curs
363395 end
364396 end
365397
366- local params = {
367- line_before_cursor = line_before_cursor ,
368- line_after_cursor = line_after_cursor ,
369- dust_strings = self .dust_strings ,
370- can_show_partial_line = true ,
371- }
372-
373398 return textual .derive_completion (best_completion , params )
374399end
375400
@@ -383,6 +408,65 @@ function BinaryLifecycle:completion_text_length(completion)
383408 return length
384409end
385410
411+ --- @param bufnr integer
412+ --- @param prefix string
413+ --- @return integer | nil
414+ function BinaryLifecycle :submit_query (bufnr , prefix )
415+ self :purge_old_states ()
416+ local buffer_text = u .get_text (bufnr )
417+ local offset = # prefix
418+ local document_state = {
419+ kind = " file_update" ,
420+ path = vim .api .nvim_buf_get_name (bufnr ),
421+ content = buffer_text ,
422+ }
423+ local cursor_state = {
424+ kind = " cursor_update" ,
425+ path = vim .api .nvim_buf_get_name (bufnr ),
426+ offset = offset ,
427+ }
428+ if self .last_state ~= nil then
429+ if # self .changed_document_list == 0 then
430+ if self .last_state .cursor .path == cursor_state .path and self .last_state .cursor .offset == cursor_state .offset then
431+ if
432+ self .last_state .document .path == document_state .path
433+ and self .last_state .document .content == document_state .content
434+ then
435+ return self .current_state_id
436+ end
437+ end
438+ end
439+ end
440+
441+ local updates = {
442+ cursor_state ,
443+ }
444+ self :document_changed (document_state .path , buffer_text )
445+ for _ , document_value in pairs (self .changed_document_list ) do
446+ updates [# updates + 1 ] = {
447+ kind = " file_update" ,
448+ path = document_value .path ,
449+ content = document_value .content ,
450+ }
451+ end
452+ self .changed_document_list = {}
453+ self .current_state_id = self .current_state_id + 1
454+ self :send_message (updates )
455+ self .state_map [self .current_state_id ] = {
456+ prefix = prefix ,
457+ completion = {},
458+ has_ended = false ,
459+ }
460+ self .last_state = {
461+ cursor = cursor_state ,
462+ document = document_state ,
463+ }
464+ return self .current_state_id
465+ end
466+
467+ --- @param completion ResponseItem[]
468+ --- @param original_prefix string
469+ --- @return ResponseItem[] | nil
386470function BinaryLifecycle :strip_prefix (completion , original_prefix )
387471 local prefix = original_prefix
388472 local remaining_response_item = {}
@@ -402,15 +486,14 @@ function BinaryLifecycle:strip_prefix(completion, original_prefix)
402486 text = text ,
403487 })
404488 end
405- elseif response_item .kind == " del " then
489+ elseif response_item .kind == " delete " then
406490 table.insert (remaining_response_item , response_item )
407491 elseif response_item .kind == " dedent" then
408492 if # prefix > 0 then
409493 return nil
410494 end
411495 table.insert (remaining_response_item , response_item )
412496 else
413- -- barrier/del get added when prefix has been accounted for
414497 if # prefix == 0 then
415498 table.insert (remaining_response_item , response_item )
416499 end
@@ -502,4 +585,19 @@ function BinaryLifecycle:open_popup(message, include_free)
502585 self .win = win
503586end
504587
588+ --- @param full_path string
589+ --- @param buffer_text string
590+ function BinaryLifecycle :document_changed (full_path , buffer_text )
591+ self .changed_document_list [full_path ] = {
592+ path = full_path ,
593+ content = buffer_text ,
594+ cursor = api .nvim_win_get_cursor (0 ),
595+ }
596+ local outgoing_message = {
597+ kind = " inform_file_changed" ,
598+ path = full_path ,
599+ }
600+ self :send_json (outgoing_message )
601+ end
602+
505603return BinaryLifecycle
0 commit comments