@@ -7,13 +7,115 @@ local M = {}
77M ._animation = {
88 frames = nil ,
99 text = ' Thinking... ' ,
10+ status_data = nil ,
1011 current_frame = 1 ,
1112 timer = nil ,
1213 fps = 10 ,
1314 extmark_id = nil ,
1415 ns_id = vim .api .nvim_create_namespace (' opencode_loading_animation' ),
16+ status_event_manager = nil ,
1517}
1618
19+ --- @param status table | nil
20+ --- @return string | nil
21+ function M ._format_status_text (status )
22+ if type (status ) ~= ' table' then
23+ return nil
24+ end
25+
26+ local status_type = status .type
27+
28+ if status_type == ' busy' then
29+ return M ._animation .text
30+ end
31+
32+ if status_type == ' idle' then
33+ return nil
34+ end
35+
36+ if status_type == ' retry' then
37+ local message = status .message or ' Retrying request'
38+ local details = {}
39+
40+ if type (status .attempt ) == ' number' then
41+ table.insert (details , ' retry ' .. status .attempt )
42+ end
43+
44+ if type (status .next ) == ' number' then
45+ local now_ms = os.time () * 1000
46+ local seconds = math.max (0 , math.ceil ((status .next - now_ms ) / 1000 ))
47+ table.insert (details , ' in ' .. seconds .. ' s' )
48+ end
49+
50+ if # details > 0 then
51+ return string.format (' %s (%s)... ' , message , table.concat (details , ' , ' ))
52+ end
53+
54+ return message .. ' ... '
55+ end
56+
57+ if type (status .message ) == ' string' and status .message ~= ' ' then
58+ return status .message .. ' ... '
59+ end
60+
61+ return M ._animation .text
62+ end
63+
64+ local function unsubscribe_session_status_event (manager )
65+ if manager and M ._animation .status_event_manager == manager then
66+ manager :unsubscribe (' session.status' , M .on_session_status )
67+ M ._animation .status_event_manager = nil
68+ end
69+ end
70+
71+ local function subscribe_session_status_event (manager )
72+ if not manager then
73+ return
74+ end
75+
76+ if M ._animation .status_event_manager and M ._animation .status_event_manager ~= manager then
77+ unsubscribe_session_status_event (M ._animation .status_event_manager )
78+ end
79+
80+ if M ._animation .status_event_manager == manager then
81+ return
82+ end
83+
84+ manager :subscribe (' session.status' , M .on_session_status )
85+ M ._animation .status_event_manager = manager
86+ end
87+
88+ function M .on_session_status (properties )
89+ if not properties or type (properties ) ~= ' table' then
90+ return
91+ end
92+
93+ local active_session = state .active_session
94+ if active_session and active_session .id and properties .sessionID ~= active_session .id then
95+ return
96+ end
97+
98+ M ._animation .status_data = properties .status
99+ M .render (state .windows )
100+ end
101+
102+ local function on_active_session_change (_ , new_session , old_session )
103+ local new_id = new_session and new_session .id
104+ local old_id = old_session and old_session .id
105+ if new_id ~= old_id then
106+ M ._animation .status_data = nil
107+ end
108+ end
109+
110+ local function on_event_manager_change (_ , new_manager , old_manager )
111+ unsubscribe_session_status_event (old_manager )
112+ subscribe_session_status_event (new_manager )
113+ end
114+
115+ function M ._get_display_text ()
116+ return M ._format_status_text (M ._animation .status_data ) or M ._animation .text
117+ end
118+
17119function M ._get_frames ()
18120 if M ._animation .frames then
19121 return M ._animation .frames
@@ -41,7 +143,7 @@ M.render = vim.schedule_wrap(function(windows)
41143 return false
42144 end
43145
44- local loading_text = M ._animation . text .. M ._get_frames ()[M ._animation .current_frame ]
146+ local loading_text = M ._get_display_text () .. M ._get_frames ()[M ._animation .current_frame ]
45147
46148 M ._animation .extmark_id = vim .api .nvim_buf_set_extmark (windows .footer_buf , M ._animation .ns_id , 0 , 0 , {
47149 id = M ._animation .extmark_id or nil ,
97199function M .stop ()
98200 M ._clear_animation_timer ()
99201 M ._animation .current_frame = 1
202+ M ._animation .status_data = nil
100203 if state .windows and state .windows .footer_buf and vim .api .nvim_buf_is_valid (state .windows .footer_buf ) then
101204 pcall (vim .api .nvim_buf_clear_namespace , state .windows .footer_buf , M ._animation .ns_id , 0 , - 1 )
102205 end
@@ -120,10 +223,17 @@ end
120223
121224function M .setup ()
122225 state .subscribe (' job_count' , on_running_change )
226+ state .subscribe (' active_session' , on_active_session_change )
227+ state .subscribe (' event_manager' , on_event_manager_change )
228+ subscribe_session_status_event (state .event_manager )
123229end
124230
125231function M .teardown ()
126232 state .unsubscribe (' job_count' , on_running_change )
233+ state .unsubscribe (' active_session' , on_active_session_change )
234+ state .unsubscribe (' event_manager' , on_event_manager_change )
235+ unsubscribe_session_status_event (M ._animation .status_event_manager )
236+ M ._animation .status_data = nil
127237end
128238
129239return M
0 commit comments