Skip to content

Commit e0ae70a

Browse files
committed
fix(renderer): fix subscriptions memory leak
When closing the chat panel subscriptions were not cleaned properly This led to leak in subscriptions callback and also led to renderer for the same events Performance was degrading over time.
1 parent 5658ce7 commit e0ae70a

File tree

2 files changed

+61
-6
lines changed

2 files changed

+61
-6
lines changed

lua/opencode/ui/renderer.lua

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,14 @@ function M.reset()
5454
trigger_on_data_rendered()
5555
end
5656

57+
M.on_session_idle = function()
58+
vim.notify('Session is idle, no-op')
59+
end
60+
5761
---Set up event subscriptions
5862
---@param subscribe? boolean false to unsubscribe
5963
function M.setup_subscriptions(subscribe)
60-
subscribe = subscribe or true
64+
subscribe = subscribe == nil and true or subscribe
6165

6266
if subscribe then
6367
state.subscribe('is_opencode_focused', M.on_focus_changed)
@@ -75,6 +79,7 @@ function M.setup_subscriptions(subscribe)
7579
{ 'session.updated', M.on_session_updated },
7680
{ 'session.compacted', M.on_session_compacted },
7781
{ 'session.error', M.on_session_error },
82+
{ 'session.idle', M.on_session_idle },
7883
{ 'message.updated', M.on_message_updated },
7984
{ 'message.removed', M.on_message_removed },
8085
{ 'message.part.updated', M.on_part_updated },
@@ -132,8 +137,6 @@ function M._render_full_session_data(session_data)
132137

133138
local revert_index = nil
134139

135-
-- local event_manager = state.event_manager
136-
137140
-- if we're loading a session and there's no currently selected model, set it
138141
-- from the messages
139142
local set_mode_from_messages = not state.current_model
@@ -143,11 +146,9 @@ function M._render_full_session_data(session_data)
143146
revert_index = i
144147
end
145148

146-
-- table.insert(event_manager.captured_events, { type = 'message.updated', properties = { info = msg.info } })
147149
M.on_message_updated({ info = msg.info }, revert_index)
148150

149151
for _, part in ipairs(msg.parts or {}) do
150-
-- table.insert(event_manager.captured_events, { type = 'message.part.updated', properties = { part = part } })
151152
M.on_part_updated({ part = part }, revert_index)
152153
end
153154
end

tests/replay/renderer_spec.lua

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,61 @@ local function assert_output_matches(expected, actual, name)
9191
end
9292
end
9393

94-
describe('renderer', function()
94+
describe('renderer unit tests', function()
95+
local event_subscriptions = {
96+
'session.updated',
97+
'session.compacted',
98+
'session.error',
99+
'session.idle',
100+
'message.updated',
101+
'message.removed',
102+
'message.part.updated',
103+
'message.part.removed',
104+
'permission.updated',
105+
'permission.replied',
106+
'file.edited',
107+
'custom.restore_point.created',
108+
'custom.emit_events.finished',
109+
}
110+
111+
before_each(function()
112+
require('opencode.event_manager').setup()
113+
end)
114+
115+
it('subsribes to events correctly', function()
116+
local renderer = require('opencode.ui.renderer')
117+
local event_manager = state.event_manager
118+
119+
event_manager.events = {}
120+
121+
renderer.setup_subscriptions()
122+
123+
for _, event_name in ipairs(event_subscriptions) do
124+
assert.is_true(
125+
event_manager.events[event_name] ~= nil,
126+
string.format('Renderer did not subscribe to event: %s', event_name)
127+
)
128+
end
129+
end)
130+
131+
it('unsubsribes from events correctly', function()
132+
local renderer = require('opencode.ui.renderer')
133+
local event_manager = state.event_manager
134+
135+
renderer.setup_subscriptions()
136+
137+
renderer.setup_subscriptions(false)
138+
139+
for _, event_name in ipairs(event_subscriptions) do
140+
assert.is_true(
141+
vim.tbl_isempty(event_manager.events[event_name]),
142+
string.format('Renderer did not unsubscribe from event: %s', event_name)
143+
)
144+
end
145+
end)
146+
end)
147+
148+
describe('renderer functional tests', function()
95149
config.debug.show_ids = true
96150

97151
before_each(function()

0 commit comments

Comments
 (0)