@@ -154,6 +154,7 @@ local util = require('opencode.util')
154154--- @class EventManager
155155--- @field events table<string , function[]> Event listener registry
156156--- @field server_subscription table | nil Subscription to server events
157+ --- @field state_server_listener function | nil Listener for state.opencode_server updates
157158--- @field is_started boolean Whether the event manager is started
158159--- @field captured_events table[] List of captured events for debugging
159160--- @field throttling_emitter ThrottlingEmitter Throttle instance for batching events
@@ -166,6 +167,7 @@ function EventManager.new()
166167 local self = setmetatable ({
167168 events = {},
168169 server_subscription = nil ,
170+ state_server_listener = nil ,
169171 is_started = false ,
170172 captured_events = {},
171173 }, EventManager )
@@ -208,6 +210,13 @@ function EventManager:subscribe(event_name, callback)
208210 if not self .events [event_name ] then
209211 self .events [event_name ] = {}
210212 end
213+
214+ for _ , cb in ipairs (self .events [event_name ]) do
215+ if cb == callback then
216+ return
217+ end
218+ end
219+
211220 table.insert (self .events [event_name ], callback )
212221end
213222
@@ -243,10 +252,10 @@ function EventManager:unsubscribe(event_name, callback)
243252 return
244253 end
245254
246- for i , cb in ipairs (listeners ) do
255+ for i = # listeners , 1 , - 1 do
256+ local cb = listeners [i ]
247257 if cb == callback then
248258 table.remove (listeners , i )
249- break
250259 end
251260 end
252261end
@@ -351,31 +360,34 @@ function EventManager:start()
351360
352361 self .is_started = true
353362
354- state .subscribe (
355- ' opencode_server' ,
356- --- @param key string
357- --- @param current OpencodeServer | nil
358- --- @param prev OpencodeServer | nil
359- function (key , current , prev )
360- if current and current :get_spawn_promise () then
361- self :emit (' custom.server_starting' , { url = current .url })
362-
363- current :get_spawn_promise ():and_then (function (server )
364- self :emit (' custom.server_ready' , { url = server .url })
365- vim .defer_fn (function ()
366- self :_subscribe_to_server_events (server )
367- end , 200 )
368- end )
369-
370- current :get_shutdown_promise ():and_then (function ()
371- self :emit (' custom.server_stopped' , {})
372- self :_cleanup_server_subscription ()
373- end )
374- elseif prev and not current then
363+ if self .state_server_listener then
364+ state .unsubscribe (' opencode_server' , self .state_server_listener )
365+ end
366+
367+ self .state_server_listener = function (key , current , prev )
368+ if current and current :get_spawn_promise () then
369+ self :emit (' custom.server_starting' , { url = current .url })
370+
371+ current :get_spawn_promise ():and_then (function (server )
372+ self :emit (' custom.server_ready' , { url = server .url })
373+ vim .defer_fn (function ()
374+ self :_subscribe_to_server_events (server )
375+ end , 200 )
376+ end )
377+
378+ current :get_shutdown_promise ():and_then (function ()
375379 self :emit (' custom.server_stopped' , {})
376380 self :_cleanup_server_subscription ()
377- end
381+ end )
382+ elseif prev and not current then
383+ self :emit (' custom.server_stopped' , {})
384+ self :_cleanup_server_subscription ()
378385 end
386+ end
387+
388+ state .subscribe (
389+ ' opencode_server' ,
390+ self .state_server_listener
379391 )
380392end
381393
@@ -385,6 +397,10 @@ function EventManager:stop()
385397 end
386398
387399 self .is_started = false
400+ if self .state_server_listener then
401+ state .unsubscribe (' opencode_server' , self .state_server_listener )
402+ self .state_server_listener = nil
403+ end
388404 self :_cleanup_server_subscription ()
389405
390406 self .throttling_emitter :clear ()
0 commit comments