5757--- @param callback fun ( opt )
5858local function handle_sse_events (cmd , callback )
5959 local job
60+ local tmp = " "
6061 job = vim .fn .jobstart (cmd , {
6162 on_stdout = function (_ , data , _ )
6263 for _ , value in ipairs (data ) do
63- if vim .startswith (value , " data:" ) then
64- local _ , _ , text = string.find (value , " data: (.+) " )
64+ if vim .startswith (value , " data: " ) then
65+ local text = string.sub (value , 7 , - 1 )
6566 if text == " [DONE]" then
67+ tmp = " "
6668 callback ({
6769 data = text ,
6870 done = true ,
@@ -71,6 +73,7 @@ local function handle_sse_events(cmd, callback)
7173 else
7274 local ok , resp_json = pcall (vim .fn .json_decode , text )
7375 if ok then
76+ tmp = " "
7477 if resp_json .usage ~= nil and M .config .show_usage then
7578 callback ({
7679 data = " \n " ,
@@ -94,9 +97,16 @@ local function handle_sse_events(cmd, callback)
9497 })
9598 end
9699 else
100+ tmp = text
101+ end
102+ end
103+ else
104+ if tmp ~= " " then
105+ tmp = tmp .. value
106+ local ok , resp_json = pcall (vim .fn .json_decode , tmp )
107+ if ok then
97108 callback ({
98- err = 1 ,
99- data = text ,
109+ data = resp_json .choices [1 ].delta .content ,
100110 job = job ,
101111 })
102112 end
@@ -222,11 +232,13 @@ M.translate_float = function(request)
222232end
223233
224234---- -------------- chat ------------------
225- local charwin = nil
226- local charbuf = nil
235+ local chatwin = nil
236+ local chatbuf = nil
227237local codebuf = nil
228238local chatclosed = false
239+ local cursormoved = false
229240local chatruning = false
241+ local winleave = false
230242local chat_request_json = {
231243 messages = {
232244 {
@@ -267,10 +279,10 @@ M.chat_config = {
267279}
268280local close_gpt_win = function ()
269281 chatruning = false
270- if charwin then
271- pcall (vim .api .nvim_win_close , charwin , true )
272- charwin = nil
273- charbuf = nil
282+ if chatwin then
283+ pcall (vim .api .nvim_win_close , chatwin , true )
284+ chatwin = nil
285+ chatbuf = nil
274286 codebuf = nil
275287 chat_request_json .messages = {
276288 {
@@ -284,58 +296,82 @@ end
284296local function create_gpt_win ()
285297 codebuf = vim .api .nvim_get_current_buf ()
286298 vim .cmd (" belowright new" )
287- charwin = vim .api .nvim_get_current_win ()
288- charbuf = vim .api .nvim_get_current_buf ()
289- vim .bo [charbuf ].buftype = " nofile"
290- vim .bo [charbuf ].bufhidden = " wipe"
291- vim .bo [charbuf ].buflisted = false
292- vim .bo [charbuf ].swapfile = false
293- vim .bo [charbuf ].filetype = " markdown"
299+ chatwin = vim .api .nvim_get_current_win ()
300+ chatbuf = vim .api .nvim_get_current_buf ()
301+ vim .bo [chatbuf ].buftype = " nofile"
302+ vim .bo [chatbuf ].bufhidden = " wipe"
303+ vim .bo [chatbuf ].buflisted = false
304+ vim .bo [chatbuf ].swapfile = false
305+ vim .bo [chatbuf ].filetype = " markdown"
294306 vim .api .nvim_put ({ M .chat_config .user_title , " " }, " c" , true , true )
295307 chatclosed = false
296308
297309 vim .keymap .set (" n" , " q" , function ()
298310 chatclosed = true
299311 close_gpt_win ()
300- end , { noremap = true , silent = true , buffer = charbuf })
312+ end , { noremap = true , silent = true , buffer = chatbuf })
301313 vim .keymap .set (" n" , " <A-k>" , function ()
302314 M .gpt_chat ()
303- end , { noremap = true , silent = true , buffer = charbuf })
315+ end , { noremap = true , silent = true , buffer = chatbuf })
304316 vim .keymap .set (" i" , " <A-k>" , function ()
305317 vim .cmd (" stopinsert" )
306318 M .gpt_chat ()
307- end , { noremap = true , silent = true , buffer = charbuf })
319+ end , { noremap = true , silent = true , buffer = chatbuf })
308320
309- vim .api .nvim_buf_create_user_command (charbuf , " GptSend" , function ()
321+ vim .api .nvim_buf_create_user_command (chatbuf , " GptSend" , function ()
310322 M .gpt_chat ()
311323 end , { desc = " Gpt Send" })
312324
325+ vim .api .nvim_create_autocmd (" BufWipeout" , {
326+ buffer = chatbuf ,
327+ callback = close_gpt_win ,
328+ })
329+
313330 vim .api .nvim_create_autocmd (" WinClosed" , {
314- buffer = charbuf ,
331+ buffer = chatbuf ,
315332 callback = close_gpt_win ,
316333 })
334+ vim .api .nvim_create_autocmd (" WinLeave" , {
335+ buffer = chatbuf ,
336+ callback = function ()
337+ winleave = true
338+ end ,
339+ })
340+
341+ vim .api .nvim_create_autocmd (" CursorMoved" , {
342+ buffer = chatbuf ,
343+ callback = function ()
344+ cursormoved = true
345+ end ,
346+ })
317347end
318348
319349local function code_question (selection )
320350 if not selection then
321351 return
322352 end
323-
324- local filetype = vim .bo [codebuf ].filetype or " txt"
325- local filename = vim .fn .fnamemodify (vim .fn .bufname (codebuf ), " :." )
326- local qs = {
327- " 请解释`" .. filename .. " `文件中的这段代码" ,
328- " ```" .. filetype ,
329- }
353+ local qs
354+ --- @diagnostic disable-next-line : param-type-mismatch
355+ if vim .api .nvim_buf_is_valid (codebuf ) then
356+ local filetype = vim .bo [codebuf ].filetype or " text"
357+ local filename = vim .fn .fnamemodify (vim .fn .bufname (codebuf ), " :." )
358+ qs = {
359+ " 请解释`" .. filename .. " `文件中的这段代码" ,
360+ " ```" .. filetype ,
361+ }
362+ else
363+ qs = {
364+ " 请解释这段代码" ,
365+ " ```" ,
366+ }
367+ end
330368 vim .list_extend (qs , selection )
331369 table.insert (qs , " ```" )
332- table.insert (qs , " " )
333- vim .cmd (" normal! G" )
334370 vim .api .nvim_put (qs , " c" , true , true )
335371end
336372
337373M .toggle_gpt = function (selection )
338- if charwin then
374+ if chatwin then
339375 close_gpt_win ()
340376 else
341377 create_gpt_win ()
@@ -344,7 +380,7 @@ M.toggle_gpt = function(selection)
344380end
345381
346382M .gpt_chat = function ()
347- if charwin == nil then
383+ if chatwin == nil then
348384 create_gpt_win ()
349385 end
350386 if chatruning then
@@ -353,7 +389,8 @@ M.gpt_chat = function()
353389 return
354390 end
355391 chatruning = true
356- local list = vim .api .nvim_buf_get_lines (charbuf , 0 , - 1 , false )
392+ --- @diagnostic disable-next-line : param-type-mismatch
393+ local list = vim .api .nvim_buf_get_lines (chatbuf , 0 , - 1 , false )
357394 local json = chat_request_json
358395 json .messages [1 ].content = M .chat_config .system_prompt
359396 -- 1 user, 2 assistant
@@ -378,7 +415,7 @@ M.gpt_chat = function()
378415 end
379416 end
380417 -- 跳转到最后一行
381- vim .cmd (" normal! G" )
418+ vim .cmd (" normal! G$ " )
382419 vim .api .nvim_put ({ " " , M .chat_config .system_title , " " }, " l" , true , true )
383420
384421 local callback = function (opt )
@@ -388,12 +425,26 @@ M.gpt_chat = function()
388425 vim .fn .jobstop (opt .job )
389426 return
390427 end
428+ if opt .err == 1 then
429+ vim .notify (" AI respond Error: " .. opt .data , vim .log .levels .WARN )
430+ return
431+ end
432+ if winleave then
433+ -- 防止回答问题时光标已经移动走了
434+ vim .api .nvim_set_current_win (chatwin )
435+ winleave = false
436+ end
437+ if cursormoved then
438+ -- 防止光标移动打乱回答顺序, 总是移动到最后一行
439+ vim .cmd (" normal! G$" )
440+ cursormoved = false
441+ end
391442 if done then
392443 vim .api .nvim_put ({ " " , " " , M .chat_config .user_title , " " }, " c" , true , true )
393444 chatruning = false
394445 return
395446 end
396- if charbuf and vim .api .nvim_buf_is_valid (charbuf ) then
447+ if chatbuf and vim .api .nvim_buf_is_valid (chatbuf ) then
397448 if data :match (" \n " ) then
398449 local ln = vim .split (data , " \n " )
399450 vim .api .nvim_put (ln , " c" , true , true )
0 commit comments