Skip to content

Commit 1b78266

Browse files
committed
wip: state-management refactor
1 parent 7f959f4 commit 1b78266

15 files changed

Lines changed: 513 additions & 95 deletions

lua/opencode/api.lua

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ end
4141

4242
function M.close()
4343
if state.display_route then
44-
state.display_route = nil
44+
state.ui.clear_display_route()
4545
ui.clear_output()
4646
-- need to trigger a re-render here to re-display the session
4747
ui.render_output()
@@ -393,7 +393,7 @@ M.submit_input_prompt = Promise.async(function()
393393
if state.display_route then
394394
-- we're displaying /help or something similar, need to clear that and refresh
395395
-- the session data before sending the command
396-
state.display_route = nil
396+
state.ui.clear_display_route()
397397
ui.render_output(true)
398398
end
399399

@@ -488,7 +488,7 @@ M.initialize = Promise.async(function()
488488
vim.notify('Invalid model format: ' .. tostring(state.current_model), vim.log.levels.ERROR)
489489
return
490490
end
491-
state.active_session = new_session
491+
state.session.set_active(new_session)
492492
M.open_input()
493493
state.api_client:init_session(state.active_session.id, {
494494
providerID = providerId,
@@ -536,7 +536,7 @@ end)
536536

537537
function M.with_header(lines, show_welcome)
538538
show_welcome = show_welcome or show_welcome
539-
state.display_route = '/header'
539+
state.ui.set_display_route('/header')
540540

541541
local msg = {
542542
'## Opencode.nvim',
@@ -561,7 +561,7 @@ function M.with_header(lines, show_welcome)
561561
end
562562

563563
function M.help()
564-
state.display_route = '/help'
564+
state.ui.set_display_route('/help')
565565
M.open_input()
566566
local msg = M.with_header({
567567
'### Available Commands',
@@ -614,7 +614,7 @@ M.commands_list = Promise.async(function()
614614
return
615615
end
616616

617-
state.display_route = '/commands'
617+
state.ui.set_display_route('/commands')
618618
M.open_input()
619619

620620
local msg = M.with_header({
@@ -862,7 +862,7 @@ M.rename_session = Promise.async(function(current_session, new_title)
862862
local session_obj = session.get_by_id(current_session.id):await()
863863
if session_obj then
864864
session_obj.title = title
865-
state.active_session = vim.deepcopy(session_obj)
865+
state.session.set_active(vim.deepcopy(session_obj))
866866
end
867867
end
868868
promise:resolve(current_session)
@@ -1059,7 +1059,7 @@ M.review = Promise.async(function(args)
10591059
vim.notify('Invalid model format: ' .. tostring(state.current_model), vim.log.levels.ERROR)
10601060
return
10611061
end
1062-
state.active_session = new_session
1062+
state.session.set_active(new_session)
10631063
M.open_input():await()
10641064
state.api_client
10651065
:send_command(state.active_session.id, {
@@ -1184,7 +1184,7 @@ M.commands = {
11841184
vim.notify('Failed to create new session', vim.log.levels.ERROR)
11851185
return
11861186
end
1187-
state.active_session = new_session
1187+
state.session.set_active(new_session)
11881188
M.open_input()
11891189
else
11901190
M.open_input_new_session()

lua/opencode/api_client.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ function OpencodeApiClient:_ensure_base_url()
5656

5757
if not state.opencode_server then
5858
-- this is last resort - try to start the server and could be blocking
59-
state.opencode_server = server_job.ensure_server():wait() --[[@as OpencodeServer]]
59+
state.jobs.set_server(server_job.ensure_server():wait() --[[@as OpencodeServer]])
6060
-- shouldn't normally happen but prevents error in replay tester
6161
if not state.opencode_server then
6262
return false

lua/opencode/core.lua

Lines changed: 37 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,12 @@ end)
3838
M.switch_session = Promise.async(function(session_id)
3939
local selected_session = session.get_by_id(session_id):await()
4040

41-
state.current_model = nil
42-
state.current_mode = nil
41+
state.model.clear_model()
42+
state.model.clear_mode()
4343
M.ensure_current_mode():await()
4444

45-
state.active_session = selected_session
46-
state.restore_points = {}
45+
state.session.set_active(selected_session)
46+
state.session.reset_restore_points()
4747
if state.is_visible() then
4848
ui.focus_input()
4949
else
@@ -74,7 +74,7 @@ M.check_cwd = function()
7474
{ current_cwd = state.current_cwd, new_cwd = vim.fn.getcwd() }
7575
)
7676
state.current_cwd = vim.fn.getcwd()
77-
state.active_session = nil
77+
state.session.clear_active()
7878
context.unload_attachments()
7979
end
8080
end
@@ -83,7 +83,7 @@ end
8383
M.open = Promise.async(function(opts)
8484
opts = opts or { focus = 'input', new_session = false }
8585

86-
state.is_opening = true
86+
state.ui.set_opening(true)
8787

8888
if not require('opencode.ui.ui').is_opencode_focused() then
8989
require('opencode.context').load()
@@ -95,8 +95,8 @@ M.open = Promise.async(function(opts)
9595

9696
if are_windows_closed then
9797
if not ui.is_opencode_focused() then
98-
state.last_code_win_before_opencode = vim.api.nvim_get_current_win()
99-
state.current_code_buf = vim.api.nvim_get_current_buf()
98+
state.ui.set_last_code_window(vim.api.nvim_get_current_win())
99+
state.ui.set_current_code_buf(vim.api.nvim_get_current_buf())
100100
end
101101

102102
M.is_prompting_allowed()
@@ -106,10 +106,10 @@ M.open = Promise.async(function(opts)
106106
if not restored then
107107
state.clear_hidden_window_state()
108108
restoring_hidden = false
109-
state.windows = ui.create_windows()
109+
state.ui.set_windows(ui.create_windows())
110110
end
111111
else
112-
state.windows = ui.create_windows()
112+
state.ui.set_windows(ui.create_windows())
113113
end
114114
end
115115

@@ -122,29 +122,29 @@ M.open = Promise.async(function(opts)
122122
local server = server_job.ensure_server():await()
123123

124124
if not server then
125-
state.is_opening = false
125+
state.ui.set_opening(false)
126126
return Promise.new():reject('Server failed to start')
127127
end
128128

129129
M.check_cwd()
130130

131131
local ok, err = pcall(function()
132132
if opts.new_session then
133-
state.active_session = nil
133+
state.session.clear_active()
134134
state.last_sent_context = nil
135135
context.unload_attachments()
136136

137137
M.ensure_current_mode():await()
138138

139-
state.active_session = M.create_new_session():await()
139+
state.session.set_active(M.create_new_session():await())
140140
log.debug('Created new session on open', { session = state.active_session.id })
141141
else
142142
M.ensure_current_mode():await()
143143

144144
if not state.active_session then
145-
state.active_session = session.get_last_workspace_session():await()
145+
state.session.set_active(session.get_last_workspace_session():await())
146146
if not state.active_session then
147-
state.active_session = M.create_new_session():await()
147+
state.session.set_active(M.create_new_session():await())
148148
end
149149
else
150150
if not state.display_route and are_windows_closed and not restoring_hidden then
@@ -157,10 +157,10 @@ M.open = Promise.async(function(opts)
157157
end
158158
end
159159

160-
state.is_opencode_focused = true
160+
state.ui.set_panel_focused(true)
161161
end)
162162

163-
state.is_opening = false
163+
state.ui.set_opening(false)
164164

165165
if not ok then
166166
vim.notify('Error opening panel: ' .. tostring(err), vim.log.levels.ERROR)
@@ -198,17 +198,17 @@ M.send_message = Promise.async(function(prompt, opts)
198198
if opts.model then
199199
local provider, model = opts.model:match('^(.-)/(.+)$')
200200
params.model = { providerID = provider, modelID = model }
201-
state.current_model = opts.model
201+
state.model.set_model(opts.model)
202202

203203
if opts.variant then
204204
params.variant = opts.variant
205-
state.current_variant = opts.variant
205+
state.model.set_variant(opts.variant)
206206
end
207207
end
208208

209209
if opts.agent then
210210
params.agent = opts.agent
211-
state.current_mode = opts.agent
211+
state.model.set_mode(opts.agent)
212212
end
213213

214214
params.parts = context.format_message(prompt, opts.context):await()
@@ -293,12 +293,10 @@ function M.configure_provider()
293293
return
294294
end
295295
local model_str = string.format('%s/%s', selection.provider, selection.model)
296-
state.current_model = model_str
296+
state.model.set_model(model_str)
297297

298298
if state.current_mode then
299-
local mode_map = vim.deepcopy(state.user_mode_model_map)
300-
mode_map[state.current_mode] = model_str
301-
state.user_mode_model_map = mode_map
299+
state.model.set_mode_model_override(state.current_mode, model_str)
302300
end
303301

304302
if state.is_visible() then
@@ -318,7 +316,7 @@ function M.configure_variant()
318316
return
319317
end
320318

321-
state.current_variant = selection.name
319+
state.model.set_variant(selection.name)
322320

323321
if state.is_visible() then
324322
ui.focus_input()
@@ -378,7 +376,7 @@ M.cycle_variant = Promise.async(function()
378376
next_variant = variants[next_index]
379377
end
380378

381-
state.current_variant = next_variant
379+
state.model.set_variant(next_variant)
382380

383381
local model_state = require('opencode.model_state')
384382
model_state.set_variant(provider, model, next_variant)
@@ -412,11 +410,11 @@ M.cancel = Promise.async(function()
412410
end
413411

414412
-- start a new one
415-
state.opencode_server = nil
413+
state.jobs.clear_server()
416414

417415
-- NOTE: start a new server here to make sure we're subscribed
418416
-- to server events before a user sends a message
419-
state.opencode_server = server_job.ensure_server():await() --[[@as OpencodeServer]]
417+
state.jobs.set_server(server_job.ensure_server():await() --[[@as OpencodeServer]])
420418
end
421419
end
422420

@@ -486,18 +484,18 @@ M.switch_to_mode = Promise.async(function(mode)
486484
return false
487485
end
488486

489-
state.current_mode = mode
487+
state.model.set_mode(mode)
490488
local opencode_config = config_file.get_opencode_config():await() --[[@as OpencodeConfigFile]]
491489

492490
local agent_config = opencode_config and opencode_config.agent or {}
493491
local mode_config = agent_config[mode] or {}
494492

495493
if state.user_mode_model_map[mode] then
496-
state.current_model = state.user_mode_model_map[mode]
494+
state.model.set_model(state.user_mode_model_map[mode])
497495
elseif mode_config.model and mode_config.model ~= '' then
498-
state.current_model = mode_config.model
496+
state.model.set_model(mode_config.model)
499497
elseif opencode_config and opencode_config.model and opencode_config.model ~= '' then
500-
state.current_model = opencode_config.model
498+
state.model.set_model(opencode_config.model)
501499
end
502500
return true
503501
end)
@@ -518,10 +516,10 @@ M.ensure_current_mode = Promise.async(function()
518516

519517
-- Try to use the configured default mode if it's available
520518
if default_mode and vim.tbl_contains(available_agents, default_mode) then
521-
state.current_mode = default_mode
519+
state.model.set_mode(default_mode)
522520
else
523521
-- Fallback to first available agent
524-
state.current_mode = available_agents[1]
522+
state.model.set_mode(available_agents[1])
525523
end
526524
end
527525
return true
@@ -537,7 +535,7 @@ M.initialize_current_model = Promise.async(function()
537535
local cfg = require('opencode.config_file').get_opencode_config():await()
538536

539537
if cfg and cfg.model and cfg.model ~= '' then
540-
state.current_model = cfg.model
538+
state.model.set_model(cfg.model)
541539
end
542540

543541
return state.current_model
@@ -583,11 +581,11 @@ M.handle_directory_change = Promise.async(function()
583581
log.debug('Working directory change %s', vim.inspect({ cwd = cwd }))
584582
vim.notify('Loading last session for new working dir [' .. cwd .. ']', vim.log.levels.INFO)
585583

586-
state.active_session = nil
584+
state.session.clear_active()
587585
state.last_sent_context = nil
588586
context.unload_attachments()
589587

590-
state.active_session = session.get_last_workspace_session():await() or M.create_new_session():await()
588+
state.session.set_active(session.get_last_workspace_session():await() or M.create_new_session():await())
591589

592590
log.debug('Loaded session for new working dir ' .. vim.inspect({ session = state.active_session }))
593591
end)
@@ -598,7 +596,7 @@ function M.setup()
598596
state.subscribe('pending_permissions', M._on_current_permission_change)
599597
state.subscribe('current_model', function(key, new_val, old_val)
600598
if new_val ~= old_val then
601-
state.current_variant = nil
599+
state.model.clear_variant()
602600

603601
-- Load saved variant for the new model
604602
if new_val then
@@ -607,7 +605,7 @@ function M.setup()
607605
local model_state = require('opencode.model_state')
608606
local saved_variant = model_state.get_variant(provider, model)
609607
if saved_variant then
610-
state.current_variant = saved_variant
608+
state.model.set_variant(saved_variant)
611609
end
612610
end
613611
end

lua/opencode/quick_chat.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -375,7 +375,7 @@ M.quick_chat = Promise.async(function(message, options, range)
375375
end
376376

377377
if config.debug.quick_chat and config.debug.quick_chat.set_active_session then
378-
state.active_session = quick_chat_session
378+
state.session.set_active(quick_chat_session)
379379
end
380380

381381
running_sessions[quick_chat_session.id] = {

lua/opencode/server_job.lua

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ end
7575
function M.call_api(url, method, body)
7676
local call_promise = Promise.new()
7777

78-
state.job_count = state.job_count + 1
78+
state.jobs.increment_count()
7979

8080
local request_entry = { nil, call_promise }
8181
table.insert(M.requests, request_entry)
@@ -87,7 +87,7 @@ function M.call_api(url, method, body)
8787
break
8888
end
8989
end
90-
state.job_count = #M.requests
90+
state.jobs.set_count(#M.requests)
9191
end
9292

9393
local opts = {
@@ -246,7 +246,7 @@ local function spawn_and_retry(base_url, custom_port, custom_url, promise, timeo
246246

247247
retry_connect(base_url, timeout, 3, function(url)
248248
port_mapping.register(custom_port, vim.fn.getcwd(), true, 'custom', url, server_pid)
249-
state.opencode_server = opencode_server.from_custom(url, custom_port, 'custom')
249+
state.jobs.set_server(opencode_server.from_custom(url, custom_port, 'custom'))
250250
promise:resolve(state.opencode_server)
251251
end, function(_err)
252252
if config.server.port == 'auto' then
@@ -264,7 +264,7 @@ function M.try_connect_to_custom_server(base_url, timeout, promise, custom_port,
264264
local existing_started_by_nvim = port_mapping.started_by_nvim(custom_port)
265265
local mode = config.server.spawn_command and 'custom' or 'attach'
266266
port_mapping.register(custom_port, vim.fn.getcwd(), existing_started_by_nvim, mode, url, nil)
267-
state.opencode_server = opencode_server.from_custom(url, custom_port, mode)
267+
state.jobs.set_server(opencode_server.from_custom(url, custom_port, mode))
268268
log.notify(
269269
string.format('Connected to remote server at %s on port %d.', base_url, custom_port),
270270
vim.log.levels.INFO
@@ -285,7 +285,7 @@ end
285285
--- @param port? number|string Optional custom port
286286
--- @param hostname? string Optional custom hostname
287287
function M.spawn_local_server(promise, port, hostname)
288-
state.opencode_server = opencode_server.new()
288+
state.jobs.set_server(opencode_server.new())
289289

290290
local spawn_opts = {
291291
on_ready = function(job, base_url)

0 commit comments

Comments
 (0)