Skip to content

Commit 32003d9

Browse files
committed
refactor(state): centralize observable API under state.store
Replace top-level observable helpers (state.subscribe, state.unsubscribe, state.append, state.emit)
1 parent 13c630e commit 32003d9

16 files changed

Lines changed: 86 additions & 88 deletions

lua/opencode/api_client.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -532,7 +532,7 @@ local function create_client(base_url)
532532
end
533533
end
534534

535-
state.subscribe('opencode_server', on_server_change)
535+
state.store.subscribe('opencode_server', on_server_change)
536536

537537
return api_client
538538
end

lua/opencode/context.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,7 @@ function M.setup()
315315
M.load()
316316
end, 200)
317317

318-
state.subscribe({ 'current_code_buf', 'current_context_config', 'is_opencode_focused' }, function()
318+
state.store.subscribe({ 'current_code_buf', 'current_context_config', 'is_opencode_focused' }, function()
319319
debounced_load()
320320
end)
321321

lua/opencode/core.lua

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,7 @@ M.cycle_variant = Promise.async(function()
381381
end)
382382

383383
M.cancel = Promise.async(function()
384-
if state.active_session and state.is_running() then
384+
if state.active_session and state.jobs.is_running() then
385385
M._abort_count = M._abort_count + 1
386386

387387
local permissions = state.pending_permissions or {}
@@ -588,10 +588,10 @@ M.handle_directory_change = Promise.async(function()
588588
end)
589589

590590
function M.setup()
591-
state.subscribe('opencode_server', on_opencode_server)
592-
state.subscribe('user_message_count', M._on_user_message_count_change)
593-
state.subscribe('pending_permissions', M._on_current_permission_change)
594-
state.subscribe('current_model', function(key, new_val, old_val)
591+
state.store.subscribe('opencode_server', on_opencode_server)
592+
state.store.subscribe('user_message_count', M._on_user_message_count_change)
593+
state.store.subscribe('pending_permissions', M._on_current_permission_change)
594+
state.store.subscribe('current_model', function(key, new_val, old_val)
595595
if new_val ~= old_val then
596596
state.model.clear_variant()
597597

lua/opencode/event_manager.lua

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -480,7 +480,7 @@ function EventManager:start()
480480
self.is_started = true
481481

482482
if self.state_server_listener then
483-
state.unsubscribe('opencode_server', self.state_server_listener)
483+
state.store.unsubscribe('opencode_server', self.state_server_listener)
484484
end
485485

486486
self.state_server_listener = function(key, current, prev)
@@ -504,10 +504,10 @@ function EventManager:start()
504504
end
505505
end
506506

507-
state.subscribe('opencode_server', self.state_server_listener)
507+
state.store.subscribe('opencode_server', self.state_server_listener)
508508

509509
if self.state_cwd_listener then
510-
state.unsubscribe('current_cwd', self.state_cwd_listener)
510+
state.store.unsubscribe('current_cwd', self.state_cwd_listener)
511511
end
512512

513513
self.state_cwd_listener = function(key, new_cwd, old_cwd)
@@ -517,7 +517,7 @@ function EventManager:start()
517517
end
518518
end
519519

520-
state.subscribe('current_cwd', self.state_cwd_listener)
520+
state.store.subscribe('current_cwd', self.state_cwd_listener)
521521
end
522522

523523
function EventManager:stop()
@@ -527,11 +527,11 @@ function EventManager:stop()
527527

528528
self.is_started = false
529529
if self.state_server_listener then
530-
state.unsubscribe('opencode_server', self.state_server_listener)
530+
state.store.unsubscribe('opencode_server', self.state_server_listener)
531531
self.state_server_listener = nil
532532
end
533533
if self.state_cwd_listener then
534-
state.unsubscribe('current_cwd', self.state_cwd_listener)
534+
state.store.unsubscribe('current_cwd', self.state_cwd_listener)
535535
self.state_cwd_listener = nil
536536
end
537537
self:_cleanup_server_subscription()

lua/opencode/state/init.lua

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ local context = require('opencode.state.context')
1414
---@field model OpencodeModelStateMutations
1515
---@field renderer OpencodeRendererStateMutations
1616
---@field context OpencodeContextStateMutations
17-
---@field is_running fun():boolean
1817

1918
---@alias OpencodeState OpencodeStateModule & OpencodeStateData
2019
---@type OpencodeState
@@ -26,17 +25,8 @@ local M = {
2625
model = model,
2726
renderer = renderer,
2827
context = context,
29-
subscribe = store.subscribe,
30-
unsubscribe = store.unsubscribe,
31-
emit = store.emit,
32-
append = store.append,
33-
remove = store.remove,
3428
}
3529

36-
function M.is_running()
37-
return M.job_count > 0
38-
end
39-
4030
return setmetatable(M, {
4131
__index = function(_, key)
4232
return store.get(key)

lua/opencode/state/jobs.lua

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ local store = require('opencode.state.store')
99
---@field set_api_client fun(client: OpencodeApiClient|nil)
1010
---@field set_event_manager fun(manager: EventManager|nil)
1111
---@field set_opencode_cli_version fun(version: string|nil)
12+
---@field is_running fun():boolean
1213

1314
local M = {}
1415

@@ -55,4 +56,8 @@ function M.set_opencode_cli_version(version)
5556
return store.set('opencode_cli_version', version)
5657
end
5758

59+
function M.is_running()
60+
return (store.get('job_count') or 0) > 0
61+
end
62+
5863
return M

lua/opencode/ui/context_bar.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ local function update_winbar_highlights(win_id)
170170
end
171171

172172
function M.setup()
173-
state.subscribe(
173+
state.store.subscribe(
174174
{ 'current_context_config', 'current_code_buf', 'is_opencode_focused', 'context_updated_at', 'user_message_count' },
175175
function()
176176
M.render()

lua/opencode/ui/footer.lua

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,14 @@ end
3535
local function build_right_segments()
3636
local segments = {}
3737

38-
if state.is_running() and not state.is_opening then
38+
if state.jobs.is_running() and not state.is_opening then
3939
local cancel_keymap = config.get_key_for_function('input_window', 'cancel') or '<C-c>'
4040
table.insert(segments, { string.format('%s ', cancel_keymap), 'OpencodeInputLegend' })
4141
table.insert(segments, { 'to cancel', 'OpencodeHint' })
4242
table.insert(segments, { ' ' })
4343
end
4444

45-
if not state.is_running() and state.current_model and config.ui.display_model then
45+
if not state.jobs.is_running() and state.current_model and config.ui.display_model then
4646
table.insert(segments, { state.current_model, 'OpencodeHint' })
4747
if state.current_variant then
4848
table.insert(segments, { '·', 'OpencodeHint' })
@@ -151,13 +151,13 @@ function M.setup(windows)
151151
vim.api.nvim_set_option_value('winhl', 'Normal:OpencodeHint', { win = windows.footer_win })
152152

153153
-- for model changes
154-
state.subscribe('current_model', on_change)
155-
state.subscribe('current_mode', on_change)
156-
state.subscribe('current_variant', on_change)
157-
state.subscribe('active_session', on_change)
154+
state.store.subscribe('current_model', on_change)
155+
state.store.subscribe('current_mode', on_change)
156+
state.store.subscribe('current_variant', on_change)
157+
state.store.subscribe('active_session', on_change)
158158
-- to show C-c message
159-
state.subscribe('job_count', on_job_count_changed)
160-
state.subscribe('restore_points', on_change)
159+
state.store.subscribe('job_count', on_job_count_changed)
160+
state.store.subscribe('restore_points', on_change)
161161

162162
vim.api.nvim_create_autocmd({ 'VimResized', 'WinResized' }, {
163163
group = vim.api.nvim_create_augroup('OpencodeFooterResize', { clear = true }),
@@ -180,12 +180,12 @@ function M.close(preserve_buffer)
180180
end
181181
end
182182

183-
state.unsubscribe('current_model', on_change)
184-
state.unsubscribe('current_mode', on_change)
185-
state.unsubscribe('current_variant', on_change)
186-
state.unsubscribe('active_session', on_change)
187-
state.unsubscribe('job_count', on_job_count_changed)
188-
state.unsubscribe('restore_points', on_change)
183+
state.store.unsubscribe('current_model', on_change)
184+
state.store.unsubscribe('current_mode', on_change)
185+
state.store.unsubscribe('current_variant', on_change)
186+
state.store.unsubscribe('active_session', on_change)
187+
state.store.unsubscribe('job_count', on_job_count_changed)
188+
state.store.unsubscribe('restore_points', on_change)
189189

190190
loading_animation.teardown()
191191
end

lua/opencode/ui/formatter.lua

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -375,9 +375,10 @@ end
375375

376376
---@param output Output Output object to write to
377377
---@param text string
378-
function M._format_assistant_message(output, text)
378+
---@param message_id string|nil Optional message ID for reference parsing
379+
function M._format_assistant_message(output, text, message_id)
379380
local reference_picker = require('opencode.ui.reference_picker')
380-
local references = reference_picker.parse_references(text, '')
381+
local references = reference_picker.parse_references(text, message_id)
381382

382383
-- If no references, just add the text as-is
383384
if #references == 0 then
@@ -501,7 +502,7 @@ function M.format_part(part, message, is_last_part, get_child_parts)
501502
end
502503
elseif role == 'assistant' then
503504
if part.type == 'text' and part.text then
504-
M._format_assistant_message(output, vim.trim(part.text))
505+
M._format_assistant_message(output, vim.trim(part.text), part.messageID)
505506
content_added = true
506507
elseif part.type == 'reasoning' then
507508
M._format_reasoning(output, part)

lua/opencode/ui/loading_animation.lua

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ M.render = vim.schedule_wrap(function(windows)
138138
return false
139139
end
140140

141-
if not state.is_running() then
141+
if not state.jobs.is_running() then
142142
M.stop()
143143
return false
144144
end
@@ -168,7 +168,7 @@ function M._start_animation_timer(windows)
168168
on_tick = function()
169169
M._animation.current_frame = M._next_frame()
170170
M.render(state.windows)
171-
if state.is_running() then
171+
if state.jobs.is_running() then
172172
return true
173173
else
174174
M.stop()
@@ -222,16 +222,16 @@ local function on_running_change(_, new_value)
222222
end
223223

224224
function M.setup()
225-
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)
225+
state.store.subscribe('job_count', on_running_change)
226+
state.store.subscribe('active_session', on_active_session_change)
227+
state.store.subscribe('event_manager', on_event_manager_change)
228228
subscribe_session_status_event(state.event_manager)
229229
end
230230

231231
function M.teardown()
232-
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)
232+
state.store.unsubscribe('job_count', on_running_change)
233+
state.store.unsubscribe('active_session', on_active_session_change)
234+
state.store.unsubscribe('event_manager', on_event_manager_change)
235235
unsubscribe_session_status_event(M._animation.status_event_manager)
236236
M._animation.status_data = nil
237237
end

0 commit comments

Comments
 (0)