Skip to content

Commit c265665

Browse files
authored
feat: persist window width across hide/restore (#315)
Save user-adjusted window width ratio when hiding and restore it when restoring hidden windows.
1 parent 38c452a commit c265665

5 files changed

Lines changed: 77 additions & 14 deletions

File tree

lua/opencode/state.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
---@field api_client OpencodeApiClient
5959
---@field event_manager EventManager|nil
6060
---@field pre_zoom_width integer|nil
61+
---@field last_window_width_ratio number|nil
6162
---@field required_version string
6263
---@field opencode_cli_version string|nil
6364
---@field current_cwd string|nil

lua/opencode/ui/input_window.lua

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,7 @@ local function apply_dimensions(windows, height)
5858
return
5959
end
6060

61-
local total_width = vim.api.nvim_get_option_value('columns', {})
62-
local width_ratio = state.pre_zoom_width and config.ui.zoom_width or config.ui.window_width
63-
local width = math.floor(total_width * width_ratio)
64-
65-
pcall(vim.api.nvim_win_set_config, windows.input_win, { width = width, height = height })
61+
pcall(vim.api.nvim_win_set_config, windows.input_win, { height = height })
6662
end
6763

6864
function M.create_buf()

lua/opencode/ui/output_window.lua

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,17 @@ function M.update_dimensions(windows)
133133
return
134134
end
135135
local total_width = vim.api.nvim_get_option_value('columns', {})
136-
local width_ratio = state.pre_zoom_width and config.ui.zoom_width or config.ui.window_width
136+
137+
local width_ratio
138+
if windows.saved_width_ratio then
139+
width_ratio = windows.saved_width_ratio
140+
windows.saved_width_ratio = nil
141+
elseif state.pre_zoom_width then
142+
width_ratio = config.ui.zoom_width
143+
else
144+
width_ratio = config.ui.window_width
145+
end
146+
137147
local width = math.floor(total_width * width_ratio)
138148

139149
vim.api.nvim_win_set_config(windows.output_win, { width = width })

lua/opencode/ui/ui.lua

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,14 @@ function M.hide_visible_windows(windows)
134134
end
135135

136136
local snapshot = capture_hidden_snapshot(windows)
137+
138+
-- Only save width ratio for split modes (not dialog/current mode)
139+
if config.ui.position ~= 'current' then
140+
local total_cols = vim.o.columns
141+
local current_width = vim.api.nvim_win_get_width(windows.output_win)
142+
state.last_window_width_ratio = current_width / total_cols
143+
end
144+
137145
state.clear_hidden_window_state()
138146

139147
prepare_window_close()
@@ -227,6 +235,7 @@ function M.restore_hidden_windows()
227235
windows.output_win = win_ids.output_win
228236
windows.footer_win = nil
229237
windows.output_was_at_bottom = hidden.output_was_at_bottom == true
238+
windows.saved_width_ratio = state.last_window_width_ratio
230239

231240
state.set_cursor_position('input', hidden.input_cursor)
232241
state.set_cursor_position('output', hidden.output_cursor)
@@ -349,6 +358,7 @@ function M.create_windows()
349358

350359
windows.input_win = win_ids.input_win
351360
windows.output_win = win_ids.output_win
361+
windows.saved_width_ratio = state.last_window_width_ratio
352362

353363
input_window.setup(windows)
354364
output_window.setup(windows)

tests/unit/zoom_spec.lua

Lines changed: 54 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -99,24 +99,23 @@ describe('ui zoom state', function()
9999
end)
100100

101101
describe('input_window.update_dimensions', function()
102-
it('uses default window_width when not zoomed', function()
102+
it('does not change input window width', function()
103+
local original_width = vim.api.nvim_win_get_width(windows.input_win)
104+
103105
input_window.update_dimensions(windows)
104106

105-
local expected_width = math.floor(config.ui.window_width * vim.o.columns)
106107
local actual_width = vim.api.nvim_win_get_width(windows.input_win)
107-
108-
assert.equals(expected_width, actual_width)
108+
assert.equals(original_width, actual_width)
109109
end)
110110

111-
it('uses zoom_width when zoomed', function()
111+
it('does not change input window width when zoomed', function()
112112
state.pre_zoom_width = 80
113+
local original_width = vim.api.nvim_win_get_width(windows.input_win)
113114

114115
input_window.update_dimensions(windows)
115116

116-
local expected_width = math.floor(config.ui.zoom_width * vim.o.columns)
117117
local actual_width = vim.api.nvim_win_get_width(windows.input_win)
118-
119-
assert.equals(expected_width, actual_width)
118+
assert.equals(original_width, actual_width)
120119
end)
121120

122121
it('preserves zoom state after update_dimensions', function()
@@ -267,4 +266,51 @@ describe('ui zoom state', function()
267266
assert.is_nil(state.pre_zoom_width)
268267
end)
269268
end)
269+
270+
describe('window width persistence', function()
271+
it('saves width ratio when hiding windows', function()
272+
local custom_width = 100
273+
vim.api.nvim_win_set_width(windows.output_win, custom_width)
274+
ui.hide_visible_windows(windows)
275+
276+
local expected_ratio = custom_width / vim.o.columns
277+
assert.is_not_nil(state.last_window_width_ratio)
278+
assert.near(expected_ratio, state.last_window_width_ratio, 0.001)
279+
end)
280+
281+
it('does not save width in dialog mode (position=current)', function()
282+
local original_position = config.ui.position
283+
config.ui.position = 'current'
284+
state.last_window_width_ratio = nil
285+
286+
ui.hide_visible_windows(windows)
287+
assert.is_nil(state.last_window_width_ratio)
288+
289+
config.ui.position = original_position
290+
end)
291+
292+
it('uses saved width ratio in output_window.update_dimensions', function()
293+
local saved_ratio = 0.6
294+
windows.saved_width_ratio = saved_ratio
295+
296+
output_window.update_dimensions(windows)
297+
298+
local expected_width = math.floor(saved_ratio * vim.o.columns)
299+
local actual_width = vim.api.nvim_win_get_width(windows.output_win)
300+
assert.equals(expected_width, actual_width)
301+
assert.is_nil(windows.saved_width_ratio)
302+
end)
303+
304+
it('prefers saved width over zoom width', function()
305+
state.pre_zoom_width = 80
306+
local saved_ratio = 0.5
307+
windows.saved_width_ratio = saved_ratio
308+
309+
output_window.update_dimensions(windows)
310+
311+
local expected_width = math.floor(saved_ratio * vim.o.columns)
312+
local actual_width = vim.api.nvim_win_get_width(windows.output_win)
313+
assert.equals(expected_width, actual_width)
314+
end)
315+
end)
270316
end)

0 commit comments

Comments
 (0)