@@ -556,7 +556,7 @@ function M.unshare()
556556
557557 state .api_client
558558 :unshare_session (state .active_session .id )
559- :and_then (function ()
559+ :and_then (function (response )
560560 vim .schedule (function ()
561561 vim .notify (' Session unshared successfully' , vim .log .levels .INFO )
562562 end )
@@ -568,21 +568,22 @@ function M.unshare()
568568 end )
569569end
570570
571- function M .undo ()
571+ --- @param messageId ? string
572+ function M .undo (messageId )
572573 if not state .active_session then
573574 vim .notify (' No active session to undo' , vim .log .levels .WARN )
574575 return
575576 end
576577
577- local last_user_message = state .last_user_message
578- if not last_user_message then
578+ local message_to_revert = messageId or state .last_user_message and state . last_user_message . info . id
579+ if not message_to_revert then
579580 vim .notify (' No user message to undo' , vim .log .levels .WARN )
580581 return
581582 end
582583
583584 state .api_client
584585 :revert_message (state .active_session .id , {
585- messageID = last_user_message . info . id ,
586+ messageID = message_to_revert ,
586587 })
587588 :and_then (function (response )
588589 vim .schedule (function ()
@@ -596,25 +597,93 @@ function M.undo()
596597 end )
597598end
598599
600+ -- Returns the ID of the next user message after the current undo point
601+ -- This is a port of the opencode tui logic
602+ -- https://github.com/sst/opencode/blob/dev/packages/tui/internal/components/chat/messages.go#L1199
603+ function find_next_message_for_redo ()
604+ if not state .active_session then
605+ return nil
606+ end
607+
608+ local revert_time = 0
609+ local revert = state .active_session .revert
610+
611+ if not revert then
612+ return nil
613+ end
614+
615+ for _ , message in ipairs (state .messages or {}) do
616+ if message .info .id == revert .messageID then
617+ revert_time = math.floor (message .info .time .created )
618+ break
619+ end
620+ if revert .partID and revert .partID ~= ' ' then
621+ for _ , part in ipairs (message .parts ) do
622+ if part .id == revert .partID and part .state and part .state .time then
623+ revert_time = math.floor (part .state .time .start )
624+ break
625+ end
626+ end
627+ end
628+ end
629+
630+ -- Find next user message after revert time
631+ local next_message_id = nil
632+ for _ , msg in ipairs (state .messages or {}) do
633+ if msg .info .role == ' user' and msg .info .time .created > revert_time then
634+ next_message_id = msg .info .id
635+ break
636+ end
637+ end
638+ return next_message_id
639+ end
640+
599641function M .redo ()
600642 if not state .active_session then
601- vim .notify (' No active session to undo ' , vim .log .levels .WARN )
643+ vim .notify (' No active session to redo ' , vim .log .levels .WARN )
602644 return
603645 end
604- ui .render_output (true )
605646
606- state .api_client
607- :unrevert_messages (state .active_session .id )
608- :and_then (function (response )
609- vim .schedule (function ()
610- vim .cmd (' checktime' )
647+ if not state .active_session .revert or state .active_session .revert .messageID == ' ' then
648+ vim .notify (' Nothing to redo' , vim .log .levels .WARN )
649+ return
650+ end
651+
652+ if not state .messages then
653+ return
654+ end
655+
656+ local next_message_id = find_next_message_for_redo ()
657+ if not next_message_id then
658+ state .api_client
659+ :unrevert_messages (state .active_session .id )
660+ :and_then (function (response )
661+ vim .schedule (function ()
662+ vim .cmd (' checktime' )
663+ end )
611664 end )
612- end )
613- : catch (function (err )
614- vim .schedule ( function ( )
615- vim . notify ( ' Failed to undo last message: ' .. vim . inspect ( err ), vim . log . levels . ERROR )
665+ : catch ( function ( err )
666+ vim . schedule (function ()
667+ vim .notify ( ' Failed to redo message: ' .. vim . inspect ( err ), vim . log . levels . ERROR )
668+ end )
616669 end )
617- end )
670+ else
671+ -- Calling revert on a "later" message is like a redo
672+ state .api_client
673+ :revert_message (state .active_session .id , {
674+ messageID = next_message_id ,
675+ })
676+ :and_then (function (response )
677+ vim .schedule (function ()
678+ vim .cmd (' checktime' )
679+ end )
680+ end )
681+ :catch (function (err )
682+ vim .schedule (function ()
683+ vim .notify (' Failed to redo message: ' .. vim .inspect (err ), vim .log .levels .ERROR )
684+ end )
685+ end )
686+ end
618687end
619688
620689--- @param answer ? ' once' | ' always' | ' reject'
0 commit comments