@@ -558,7 +558,7 @@ function M.unshare()
558558
559559 state .api_client
560560 :unshare_session (state .active_session .id )
561- :and_then (function ()
561+ :and_then (function (response )
562562 vim .schedule (function ()
563563 vim .notify (' Session unshared successfully' , vim .log .levels .INFO )
564564 end )
@@ -570,21 +570,22 @@ function M.unshare()
570570 end )
571571end
572572
573- function M .undo ()
573+ --- @param messageId ? string
574+ function M .undo (messageId )
574575 if not state .active_session then
575576 vim .notify (' No active session to undo' , vim .log .levels .WARN )
576577 return
577578 end
578579
579- local last_user_message = state .last_user_message
580- if not last_user_message then
580+ local message_to_revert = messageId or state .last_user_message and state . last_user_message . info . id
581+ if not message_to_revert then
581582 vim .notify (' No user message to undo' , vim .log .levels .WARN )
582583 return
583584 end
584585
585586 state .api_client
586587 :revert_message (state .active_session .id , {
587- messageID = last_user_message . info . id ,
588+ messageID = message_to_revert ,
588589 })
589590 :and_then (function (response )
590591 vim .schedule (function ()
@@ -598,25 +599,93 @@ function M.undo()
598599 end )
599600end
600601
602+ -- Returns the ID of the next user message after the current undo point
603+ -- This is a port of the opencode tui logic
604+ -- https://github.com/sst/opencode/blob/dev/packages/tui/internal/components/chat/messages.go#L1199
605+ function find_next_message_for_redo ()
606+ if not state .active_session then
607+ return nil
608+ end
609+
610+ local revert_time = 0
611+ local revert = state .active_session .revert
612+
613+ if not revert then
614+ return nil
615+ end
616+
617+ for _ , message in ipairs (state .messages or {}) do
618+ if message .info .id == revert .messageID then
619+ revert_time = math.floor (message .info .time .created )
620+ break
621+ end
622+ if revert .partID and revert .partID ~= ' ' then
623+ for _ , part in ipairs (message .parts ) do
624+ if part .id == revert .partID and part .state and part .state .time then
625+ revert_time = math.floor (part .state .time .start )
626+ break
627+ end
628+ end
629+ end
630+ end
631+
632+ -- Find next user message after revert time
633+ local next_message_id = nil
634+ for _ , msg in ipairs (state .messages or {}) do
635+ if msg .info .role == ' user' and msg .info .time .created > revert_time then
636+ next_message_id = msg .info .id
637+ break
638+ end
639+ end
640+ return next_message_id
641+ end
642+
601643function M .redo ()
602644 if not state .active_session then
603- vim .notify (' No active session to undo ' , vim .log .levels .WARN )
645+ vim .notify (' No active session to redo ' , vim .log .levels .WARN )
604646 return
605647 end
606- ui .render_output (true )
607648
608- state .api_client
609- :unrevert_messages (state .active_session .id )
610- :and_then (function (response )
611- vim .schedule (function ()
612- vim .cmd (' checktime' )
649+ if not state .active_session .revert or state .active_session .revert .messageID == ' ' then
650+ vim .notify (' Nothing to redo' , vim .log .levels .WARN )
651+ return
652+ end
653+
654+ if not state .messages then
655+ return
656+ end
657+
658+ local next_message_id = find_next_message_for_redo ()
659+ if not next_message_id then
660+ state .api_client
661+ :unrevert_messages (state .active_session .id )
662+ :and_then (function (response )
663+ vim .schedule (function ()
664+ vim .cmd (' checktime' )
665+ end )
613666 end )
614- end )
615- : catch (function (err )
616- vim .schedule ( function ( )
617- vim . notify ( ' Failed to undo last message: ' .. vim . inspect ( err ), vim . log . levels . ERROR )
667+ : catch ( function ( err )
668+ vim . schedule (function ()
669+ vim .notify ( ' Failed to redo message: ' .. vim . inspect ( err ), vim . log . levels . ERROR )
670+ end )
618671 end )
619- end )
672+ else
673+ -- Calling revert on a "later" message is like a redo
674+ state .api_client
675+ :revert_message (state .active_session .id , {
676+ messageID = next_message_id ,
677+ })
678+ :and_then (function (response )
679+ vim .schedule (function ()
680+ vim .cmd (' checktime' )
681+ end )
682+ end )
683+ :catch (function (err )
684+ vim .schedule (function ()
685+ vim .notify (' Failed to redo message: ' .. vim .inspect (err ), vim .log .levels .ERROR )
686+ end )
687+ end )
688+ end
620689end
621690
622691--- @param answer ? ' once' | ' always' | ' reject'
0 commit comments