Skip to content

Commit ed2da71

Browse files
committed
chore(renderer): some warnings/state cleaning
Mutating directly arrays/object on state breaks reactivity. This could causes confusion later on So I added missing remove method to use on arrays. And used the already existing append method to add messages
1 parent ce7f28e commit ed2da71

File tree

2 files changed

+40
-32
lines changed

2 files changed

+40
-32
lines changed

lua/opencode/state.lua

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ local config = require('opencode.config')
3636
---@field required_version string
3737
---@field opencode_cli_version string|nil
3838
---@field append fun( key:string, value:any)
39+
---@field remove fun( key:string, idx:number)
3940
---@field subscribe fun( key:string|nil, cb:fun(key:string, new_val:any, old_val:any))
4041
---@field unsubscribe fun( key:string|nil, cb:fun(key:string, new_val:any, old_val:any))
4142
---@field is_running fun():boolean
@@ -148,6 +149,19 @@ local function append(key, value)
148149
_notify(key, _state[key], old)
149150
end
150151

152+
local function remove(key, idx)
153+
if not _state[key] then
154+
return
155+
end
156+
if type(_state[key]) ~= 'table' then
157+
error('State key is not a table: ' .. key)
158+
end
159+
160+
local old = vim.deepcopy(_state[key] --[[@as table]])
161+
table.remove(_state[key] --[[@as table]], idx)
162+
_notify(key, _state[key], old)
163+
end
164+
151165
--- Observable state proxy. All reads/writes go through this table.
152166
--- Use `state.subscribe(key, cb)` to listen for changes.
153167
--- Use `state.unsubscribe(key, cb)` to remove listeners.
@@ -177,6 +191,7 @@ setmetatable(M, {
177191
})
178192

179193
M.append = append
194+
M.remove = remove
180195
M.subscribe = subscribe
181196
M.unsubscribe = unsubscribe
182197

lua/opencode/ui/renderer.lua

Lines changed: 25 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -359,56 +359,56 @@ end
359359
---@param message {info: MessageInfo} Event properties
360360
---@param revert_index? integer Revert index in session, if applicable
361361
function M.on_message_updated(message, revert_index)
362-
---@type OpencodeMessage
363-
if not message or not message.info or not message.info.id or not message.info.sessionID then
362+
local msg = message --[[@as OpencodeMessage]]
363+
if not msg or not msg.info or not msg.info.id or not msg.info.sessionID or not state.active_session then
364364
return
365365
end
366366

367-
if state.active_session.id ~= message.info.sessionID then
367+
if state.active_session.id ~= msg.info.sessionID then
368368
---@TODO This is probably a child session message, handle differently?
369369
-- vim.notify('Session id does not match, discarding message: ' .. vim.inspect(message), vim.log.levels.WARN)
370370
return
371371
end
372372

373-
local rendered_message = M._render_state:get_message(message.info.id)
373+
local rendered_message = M._render_state:get_message(msg.info.id)
374374
local found_msg = rendered_message and rendered_message.message
375375

376376
if revert_index then
377377
if not found_msg then
378-
table.insert(state.messages, message)
378+
state.append('messages', msg)
379379
end
380-
M._render_state:set_message(message, 0, 0)
380+
M._render_state:set_message(msg, 0, 0)
381381
return
382382
end
383383

384384
if found_msg then
385385
-- see if an error was added (or removed). have to check before we set
386386
-- found_msg.info = message.info below
387-
local rerender_message = not vim.deep_equal(found_msg.info.error, message.info.error)
387+
local rerender_message = not vim.deep_equal(found_msg.info.error, msg.info.error)
388388

389-
found_msg.info = message.info
389+
found_msg.info = msg.info
390390

391391
if rerender_message and not revert_index then
392392
local header_data = formatter.format_message_header(found_msg)
393-
M._replace_message_in_buffer(message.info.id, header_data)
393+
M._replace_message_in_buffer(msg.info.id, header_data)
394394
end
395395
else
396-
table.insert(state.messages, message)
396+
state.append('messages', msg)
397397

398-
local header_data = formatter.format_message_header(message)
398+
local header_data = formatter.format_message_header(msg)
399399
local range = M._write_formatted_data(header_data)
400400

401401
if range then
402-
M._render_state:set_message(message, range.line_start, range.line_end)
402+
M._render_state:set_message(msg, range.line_start, range.line_end)
403403
end
404404

405-
state.current_message = message
405+
state.current_message = msg
406406
if message.info.role == 'user' then
407-
state.last_user_message = message
407+
state.last_user_message = msg
408408
end
409409
end
410410

411-
M._update_stats_from_message(message)
411+
M._update_stats_from_message(msg)
412412

413413
M._scroll_to_bottom()
414414
end
@@ -418,7 +418,7 @@ end
418418
---@param properties {part: OpencodeMessagePart} Event properties
419419
---@param revert_index? integer Revert index in session, if applicable
420420
function M.on_part_updated(properties, revert_index)
421-
if not properties or not properties.part then
421+
if not properties or not properties.part or not state.active_session then
422422
return
423423
end
424424

@@ -549,9 +549,9 @@ function M.on_message_removed(properties)
549549

550550
M._remove_message_from_buffer(message_id)
551551

552-
for i, msg in ipairs(state.messages) do
552+
for i, msg in ipairs(state.messages or {}) do
553553
if msg.info.id == message_id then
554-
table.remove(state.messages, i)
554+
state.remove('messages', i)
555555
break
556556
end
557557
end
@@ -569,6 +569,9 @@ end
569569
---Event handler for session.updated events
570570
---@param properties {info: Session}
571571
function M.on_session_updated(properties)
572+
if not properties or not properties.info or not state.active_session then
573+
return
574+
end
572575
require('opencode.ui.topbar').render()
573576
if not vim.deep_equal(state.active_session.revert, properties.info.revert) then
574577
state.active_session.revert = properties.info.revert
@@ -588,14 +591,6 @@ function M.on_session_error(properties)
588591
if config.debug.enabled then
589592
vim.notify('Session error: ' .. vim.inspect(properties.error))
590593
end
591-
592-
-- local error_data = properties.error
593-
-- local error_message = error_data.data and error_data.data.message or vim.inspect(error_data)
594-
--
595-
-- local formatted = formatter.format_error_callout(error_message)
596-
--
597-
-- M._write_formatted_data(formatted)
598-
-- M._scroll_to_bottom()
599594
end
600595

601596
---Event handler for permission.updated events
@@ -707,7 +702,7 @@ function M._rerender_part(part_id)
707702
end
708703

709704
---Get all actions available at a specific line
710-
---@param line number 1-indexed line number
705+
---@param line integer 1-indexed line number
711706
---@return table[] List of actions available at that line
712707
function M.get_actions_for_line(line)
713708
return M._render_state:get_actions_at_line(line)
@@ -728,11 +723,9 @@ function M._update_stats_from_message(message)
728723
state.current_model = message.info.providerID .. '/' .. message.info.modelID
729724
end
730725

731-
if message.info.tokens and message.info.tokens.input > 0 then
732-
state.tokens_count = message.info.tokens.input
733-
+ message.info.tokens.output
734-
+ message.info.tokens.cache.read
735-
+ message.info.tokens.cache.write
726+
local tokens = message.info.tokens
727+
if tokens and tokens.input > 0 then
728+
state.tokens_count = tokens.input + tokens.output + tokens.cache.read + tokens.cache.write
736729
end
737730

738731
if message.info.cost and type(message.info.cost) == 'number' then

0 commit comments

Comments
 (0)