@@ -23,6 +23,8 @@ local Split = require("nui.split")
2323--- @field private _response_start_time number Timestamp when streaming started
2424--- @field private _max_response_length number Maximum allowed response length
2525--- @field private _headers table Table of headers for the chat
26+ --- @field private _welcome_message_applied boolean Whether the welcome message has been applied
27+ --- @field private _contexts_placeholder_line string Placeholder line for contexts in input
2628
2729local M = {}
2830M .__index = M
@@ -60,6 +62,7 @@ function M.new(id, mediator)
6062 assistant = (Config .chat and Config .chat .headers and Config .chat .headers .assistant ) or " " ,
6163 }
6264 instance ._welcome_message_applied = false
65+ instance ._contexts_placeholder_line = " "
6366
6467 require (" eca.observer" ).subscribe (" sidebar-" .. id , function (message )
6568 instance :handle_chat_content (message )
@@ -186,6 +189,7 @@ function M:reset()
186189 self ._force_welcome = false
187190 self ._current_status = " "
188191 self ._welcome_message_applied = false
192+ self ._contexts_placeholder_line = " "
189193end
190194
191195function M :new_chat ()
360364function M :_setup_container_events (container , name )
361365 -- Setup container-specific keymaps
362366 if name == " input" then
367+ self :_setup_input_events (container )
363368 self :_setup_input_keymaps (container )
364369 end
365370end
@@ -373,6 +378,58 @@ function M:_handle_container_closed(name)
373378 end
374379end
375380
381+ --- @private
382+ --- @param container NuiSplit
383+ function M :_setup_input_events (container )
384+ -- prevent contexts line or input prefix from being deleted
385+ vim .api .nvim_buf_attach (container .bufnr , false , {
386+ on_lines = function (_ , buf , _changedtick , first , _last , _new_last , _bytecount )
387+ if first ~= 0 and first ~= 1 then
388+ return
389+ end
390+
391+ local lines = vim .api .nvim_buf_get_lines (buf , 0 , - 1 , false )
392+
393+ -- restore input line if deleted
394+ if first == 1 and # lines < 2 then
395+ self :_update_input_display ()
396+ return
397+ end
398+
399+ -- first line (contexts) was changed
400+ if first == 0 then
401+ local contexts_line = lines [1 ]
402+
403+ -- if contexts line is deleted, clear all contexts
404+ if not contexts_line or contexts_line == " " then
405+ self .mediator :clear_contexts ()
406+ return
407+ end
408+
409+ -- contexts line was modified
410+ if contexts_line ~= self ._contexts_placeholder_line then
411+
412+ -- if contexts line is shorter than placeholder, a context was removed
413+ if # contexts_line < # self ._contexts_placeholder_line then
414+ local contexts = self .mediator :contexts ()
415+
416+ local row , col = unpack (vim .api .nvim_win_get_cursor (container .winid ))
417+ local context = contexts [col + 1 ]
418+
419+ if row == 1 and context then
420+ self .mediator :remove_context (context )
421+ return
422+ end
423+ end
424+
425+ self :_update_input_display ()
426+ return
427+ end
428+ end
429+ end
430+ })
431+ end
432+
376433--- @private
377434--- @param container NuiSplit
378435function M :_setup_input_keymaps (container )
@@ -561,7 +618,7 @@ function M:_set_welcome_content()
561618 self :_update_welcome_content ()
562619end
563620
564- function M :_update_input_display ()
621+ function M :_update_input_display (opts )
565622 return vim .schedule (function ()
566623 local input = self .containers .input
567624 if not input then
@@ -590,15 +647,22 @@ function M:_update_input_display()
590647 end
591648 end
592649
593- local placeholder_line = " @"
650+ local old_contexts_placeholder_line = self ._contexts_placeholder_line
651+
652+ self ._contexts_placeholder_line = " @"
594653 for _ = 1 , # contexts_name do
595- placeholder_line = placeholder_line .. " @"
654+ self . _contexts_placeholder_line = self . _contexts_placeholder_line .. " @"
596655 end
597656
598657 -- Get existing lines to preserve user input (lines after the header)
599- local existing_lines = vim .api .nvim_buf_get_lines (input .bufnr , 1 , - 1 , false )
658+ local existing_lines = vim .api .nvim_buf_get_lines (input .bufnr , 0 , - 1 , false )
659+
660+ -- If first line is the contexts placeholder, remove it from existing lines
661+ if existing_lines and # existing_lines > 1 and (existing_lines [1 ] == " " or existing_lines [1 ] == old_contexts_placeholder_line or existing_lines [1 ] == self ._contexts_placeholder_line ) then
662+ table.remove (existing_lines , 1 )
663+ end
600664
601- vim .api .nvim_buf_set_lines (input .bufnr , 0 , - 1 , false , { placeholder_line , " " })
665+ vim .api .nvim_buf_set_lines (input .bufnr , 0 , - 1 , false , { self . _contexts_placeholder_line , " " })
602666
603667 if not self .extmarks .contexts then
604668 self .extmarks .contexts = {
@@ -628,7 +692,9 @@ function M:_update_input_display()
628692 }
629693 end
630694
631- if # existing_lines > 0 then
695+ local clear = opts and opts .clear
696+
697+ if # existing_lines > 0 and not clear then
632698 vim .api .nvim_buf_set_lines (input .bufnr , 1 , 1 + # existing_lines , false , existing_lines )
633699 end
634700
@@ -640,9 +706,12 @@ function M:_update_input_display()
640706 vim .tbl_extend (" force" , { virt_text = { { prefix , " Normal" } }, virt_text_pos = " inline" , right_gravity = false }, { id = self .extmarks .prefix ._id })
641707 )
642708
643- -- Set cursor to end of prefix line
709+ -- Set cursor to end of input line
644710 if vim .api .nvim_win_is_valid (input .winid ) then
645- vim .api .nvim_win_set_cursor (input .winid , { 2 , # prefix })
711+ local row = 1 + (not clear and existing_lines and # existing_lines > 0 and # existing_lines or 1 )
712+ local col = # prefix + (not clear and existing_lines and # existing_lines > 0 and # existing_lines [# existing_lines ] or 0 )
713+
714+ vim .api .nvim_win_set_cursor (input .winid , { row , col })
646715 end
647716 end )
648717end
@@ -715,7 +784,7 @@ function M:_handle_input()
715784 self :_send_message (message )
716785
717786 -- Add new input line and focus
718- self :_update_input_display ()
787+ self :_update_input_display ({ clear = true } )
719788 self :_focus_input ()
720789end
721790
@@ -832,7 +901,7 @@ function M:_update_usage_info()
832901end
833902
834903function M :_update_welcome_content ()
835- if self ._welcome_applied then
904+ if self ._welcome_message_applied then
836905 return
837906 end
838907
@@ -858,11 +927,11 @@ function M:_update_welcome_content()
858927 end
859928 end
860929
861- self ._welcome_applied = true
930+ self ._welcome_message_applied = true
862931 end
863932
864933 table.insert (lines , " " )
865- Logger .debug (" Setting welcome content for chat (welcome applied: " .. tostring (self ._welcome_applied ) .. " )" )
934+ Logger .debug (" Setting welcome content for chat (welcome applied: " .. tostring (self ._welcome_message_applied ) .. " )" )
866935 vim .api .nvim_buf_set_lines (chat .bufnr , 0 , - 1 , false , lines )
867936end
868937
0 commit comments