From 3f81e8be61ae7b82b8eebdbaf0cbba32bab0959f Mon Sep 17 00:00:00 2001 From: Aaron Weisberg Date: Thu, 18 Dec 2025 19:44:40 -0800 Subject: [PATCH 1/3] feat(ui): add support for 'current' position in UI configuration - allow 'current' as a valid position option for UI placement - update position handling in dimensions and window closing logic - ensure compatibility with existing configurations --- lua/opencode/health.lua | 2 +- lua/opencode/types.lua | 2 +- lua/opencode/ui/input_window.lua | 10 ++++++++-- lua/opencode/ui/output_window.lua | 3 +++ lua/opencode/ui/ui.lua | 16 ++++++++++++++-- 5 files changed, 27 insertions(+), 6 deletions(-) diff --git a/lua/opencode/health.lua b/lua/opencode/health.lua index 0c77949d..4a62c4bd 100644 --- a/lua/opencode/health.lua +++ b/lua/opencode/health.lua @@ -113,7 +113,7 @@ local function check_configuration() ---@cast config OpencodeConfig - local valid_positions = { 'left', 'right', 'top', 'bottom' } + local valid_positions = { 'left', 'right', 'top', 'bottom', 'current' } if not vim.tbl_contains(valid_positions, config.ui.position) then health.warn( string.format('Invalid UI position: %s', config.ui.position), diff --git a/lua/opencode/types.lua b/lua/opencode/types.lua index 3e9c50e2..0df3e3f7 100644 --- a/lua/opencode/types.lua +++ b/lua/opencode/types.lua @@ -114,7 +114,7 @@ ---@field frames string[] ---@class OpencodeUIConfig ----@field position 'right'|'left' # Position of the UI (default: 'right') +---@field position 'right'|'left'|'current' # Position of the UI (default: 'right') ---@field input_position 'bottom'|'top' # Position of the input window (default: 'bottom') ---@field window_width number ---@field zoom_width number diff --git a/lua/opencode/ui/input_window.lua b/lua/opencode/ui/input_window.lua index 59f5e5bc..1a4b986d 100644 --- a/lua/opencode/ui/input_window.lua +++ b/lua/opencode/ui/input_window.lua @@ -124,11 +124,17 @@ function M.update_dimensions(windows) return end - local total_width = vim.api.nvim_get_option_value('columns', {}) local total_height = vim.api.nvim_get_option_value('lines', {}) - local width = math.floor(total_width * config.ui.window_width) local height = math.floor(total_height * config.ui.input_height) + if config.ui.position == 'current' then + pcall(vim.api.nvim_win_set_height, windows.input_win, height) + return + end + + local total_width = vim.api.nvim_get_option_value('columns', {}) + local width = math.floor(total_width * config.ui.window_width) + vim.api.nvim_win_set_config(windows.input_win, { width = width, height = height }) end diff --git a/lua/opencode/ui/output_window.lua b/lua/opencode/ui/output_window.lua index 696a612e..4b6516b3 100644 --- a/lua/opencode/ui/output_window.lua +++ b/lua/opencode/ui/output_window.lua @@ -78,6 +78,9 @@ function M.setup(windows) end function M.update_dimensions(windows) + if config.ui.position == 'current' then + return + end local total_width = vim.api.nvim_get_option_value('columns', {}) local width = math.floor(total_width * config.ui.window_width) diff --git a/lua/opencode/ui/ui.lua b/lua/opencode/ui/ui.lua index 57972e44..d025a2b7 100644 --- a/lua/opencode/ui/ui.lua +++ b/lua/opencode/ui/ui.lua @@ -26,7 +26,14 @@ function M.close_windows(windows) ---@cast windows { input_win: integer, output_win: integer, input_buf: integer, output_buf: integer } pcall(vim.api.nvim_win_close, windows.input_win, true) - pcall(vim.api.nvim_win_close, windows.output_win, true) + if config.ui.position == 'current' then + pcall(vim.api.nvim_set_option_value, 'winfixbuf', false, { win = windows.output_win }) + if state.current_code_buf and vim.api.nvim_buf_is_valid(state.current_code_buf) then + pcall(vim.api.nvim_win_set_buf, windows.output_win, state.current_code_buf) + end + else + pcall(vim.api.nvim_win_close, windows.output_win, true) + end pcall(vim.api.nvim_buf_delete, windows.input_buf, { force = true }) pcall(vim.api.nvim_buf_delete, windows.output_buf, { force = true }) footer.close() @@ -67,7 +74,12 @@ function M.create_split_windows(input_buf, output_buf) end local ui_conf = config.ui - local main_win = open_split(ui_conf.position, 'vertical') + local main_win + if ui_conf.position == 'current' then + main_win = vim.api.nvim_get_current_win() + else + main_win = open_split(ui_conf.position, 'vertical') + end vim.api.nvim_set_current_win(main_win) local input_win = open_split(ui_conf.input_position, 'horizontal') From a5c308feaa4934f3d644815f95af8e43709a3768 Mon Sep 17 00:00:00 2001 From: Aaron Weisberg Date: Thu, 18 Dec 2025 20:56:09 -0800 Subject: [PATCH 2/3] fix(ui): disable winfixbuf in 'current' mode and auto-close on buffer switch When 'ui.position' is set to 'current', disabling 'winfixbuf' prevents E1513 errors when external pickers (like Snacks) try to switch buffers. Added a BufEnter autocmd to automatically close the Opencode UI when a non-Opencode buffer enters an Opencode window in this mode. --- lua/opencode/ui/autocmds.lua | 26 ++++++++++++++++++++++++++ lua/opencode/ui/input_window.lua | 4 +++- lua/opencode/ui/output_window.lua | 4 +++- 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/lua/opencode/ui/autocmds.lua b/lua/opencode/ui/autocmds.lua index 2457c867..6b70d30a 100644 --- a/lua/opencode/ui/autocmds.lua +++ b/lua/opencode/ui/autocmds.lua @@ -42,6 +42,32 @@ function M.setup_autocmds(windows) require('opencode.state').is_opencode_focused = require('opencode.ui.ui').is_opencode_focused() end, }) + + if require('opencode.config').ui.position == 'current' then + vim.api.nvim_create_autocmd('BufEnter', { + group = group, + callback = function() + local current_win = vim.api.nvim_get_current_win() + local current_buf = vim.api.nvim_get_current_buf() + + if current_win ~= windows.output_win and current_win ~= windows.input_win then + return + end + + local is_opencode_buf = ( + current_buf == windows.output_buf + or current_buf == windows.input_buf + or (windows.footer_buf and current_buf == windows.footer_buf) + ) + + if not is_opencode_buf then + vim.schedule(function() + require('opencode.ui.ui').close_windows(windows) + end) + end + end, + }) + end end function M.setup_resize_handler(windows) diff --git a/lua/opencode/ui/input_window.lua b/lua/opencode/ui/input_window.lua index 1a4b986d..2c72189e 100644 --- a/lua/opencode/ui/input_window.lua +++ b/lua/opencode/ui/input_window.lua @@ -107,7 +107,9 @@ function M.setup(windows) vim.api.nvim_set_option_value('buftype', 'nofile', { buf = windows.input_buf }) vim.api.nvim_set_option_value('swapfile', false, { buf = windows.input_buf }) -- vim.b[windows.input_buf].completion = false - vim.api.nvim_set_option_value('winfixbuf', true, { win = windows.input_win }) + if config.ui.position ~= 'current' then + vim.api.nvim_set_option_value('winfixbuf', true, { win = windows.input_win }) + end vim.api.nvim_set_option_value('winfixheight', true, { win = windows.input_win }) vim.api.nvim_set_option_value('winfixwidth', true, { win = windows.input_win }) diff --git a/lua/opencode/ui/output_window.lua b/lua/opencode/ui/output_window.lua index 4b6516b3..6da3ff8d 100644 --- a/lua/opencode/ui/output_window.lua +++ b/lua/opencode/ui/output_window.lua @@ -66,7 +66,9 @@ function M.setup(windows) vim.api.nvim_set_option_value('modifiable', false, { buf = windows.output_buf }) vim.api.nvim_set_option_value('buftype', 'nofile', { buf = windows.output_buf }) vim.api.nvim_set_option_value('swapfile', false, { buf = windows.output_buf }) - vim.api.nvim_set_option_value('winfixbuf', true, { win = windows.output_win }) + if config.ui.position ~= 'current' then + vim.api.nvim_set_option_value('winfixbuf', true, { win = windows.output_win }) + end vim.api.nvim_set_option_value('winfixheight', true, { win = windows.output_win }) vim.api.nvim_set_option_value('winfixwidth', true, { win = windows.output_win }) vim.api.nvim_set_option_value('signcolumn', 'yes', { scope = 'local', win = windows.output_win }) From 03609775ef8514a46ae3a556aca18977f3df0491 Mon Sep 17 00:00:00 2001 From: Aaron Weisberg Date: Fri, 19 Dec 2025 09:01:43 -0800 Subject: [PATCH 3/3] docs(readme): update UI position options in configuration - clarify that UI position can now be 'current' alongside 'right' and 'left' - improve documentation for better user understanding of options --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6c404283..f166b8be 100644 --- a/README.md +++ b/README.md @@ -175,7 +175,7 @@ require('opencode').setup({ } }, ui = { - position = 'right', -- 'right' (default) or 'left'. Position of the UI split + position = 'right', -- 'right' (default), 'left' or 'current'. Position of the UI split. 'current' uses the current window for the output. input_position = 'bottom', -- 'bottom' (default) or 'top'. Position of the input window window_width = 0.40, -- Width as percentage of editor width zoom_width = 0.8, -- Zoom width as percentage of editor width