From 7a71454cea9589810715956801c566fb0d00fa53 Mon Sep 17 00:00:00 2001 From: Anthony Barbier Date: Thu, 25 Jun 2026 12:16:52 +0100 Subject: [PATCH 1/2] Allow to use the current window without resizing it. --- lua/codex/init.lua | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/lua/codex/init.lua b/lua/codex/init.lua index 4378b46..9df5dc1 100644 --- a/lua/codex/init.lua +++ b/lua/codex/init.lua @@ -17,6 +17,7 @@ local config = { autoinstall = true, panel = false, -- if true, open Codex in a side-panel instead of floating window use_buffer = false, -- if true, capture Codex stdout into a normal buffer instead of a terminal + panel_cmd = 'vertical rightbelow vsplit', -- Command to use to create the panel or empty string to use the current window. } function M.setup(user_config) @@ -88,15 +89,19 @@ local function open_window() }) end ---- Open Codex in a side-panel (vertical split) instead of floating window +--- Open Codex in a panel instead of floating window local function open_panel() - -- Create a vertical split on the right and show the buffer - vim.cmd('vertical rightbelow vsplit') + -- Create a window if needed and show the buffer + if config.panel_cmd ~= '' then + vim.cmd(config.panel_cmd) + end local win = vim.api.nvim_get_current_win() vim.api.nvim_win_set_buf(win, state.buf) -- Adjust width according to config (percentage of total columns) - local width = math.floor(vim.o.columns * config.width) - vim.api.nvim_win_set_width(win, width) + if config.width > 0 then + local width = math.floor(vim.o.columns * config.width) + vim.api.nvim_win_set_width(win, width) + end state.win = win end From 1722088bec6f108aeb1b7f0dbb9425bc3171523f Mon Sep 17 00:00:00 2001 From: Anthony Barbier Date: Fri, 3 Jul 2026 11:28:36 +0100 Subject: [PATCH 2/2] Refresh state on toggle in case the user manually swapped the buffer or closed the window --- lua/codex/init.lua | 40 +++++++++++++++++++++++++++++++++----- tests/specs/codex_spec.lua | 40 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 5 deletions(-) diff --git a/lua/codex/init.lua b/lua/codex/init.lua index 9df5dc1..5a06e94 100644 --- a/lua/codex/init.lua +++ b/lua/codex/init.lua @@ -105,6 +105,38 @@ local function open_panel() state.win = win end +local function is_valid_buf(buf) + return type(buf) == 'number' and vim.api.nvim_buf_is_valid(buf) +end + +local function win_get_buf(win) + if type(win) ~= 'number' or not vim.api.nvim_win_is_valid(win) then + return nil + end + + local ok, buf = pcall(vim.api.nvim_win_get_buf, win) + if ok then + return buf + end +end + +local function refresh_window_state() + if not is_valid_buf(state.buf) then + state.win = nil + return + end + + local current_win = vim.api.nvim_get_current_win() + if win_get_buf(current_win) == state.buf then + state.win = current_win + return + end + + if win_get_buf(state.win) ~= state.buf then + state.win = nil + end +end + function M.open() local function create_clean_buf() local buf = vim.api.nvim_create_buf(false, false) @@ -169,11 +201,7 @@ function M.open() end end - local function is_buf_reusable(buf) - return type(buf) == 'number' and vim.api.nvim_buf_is_valid(buf) - end - - if not is_buf_reusable(state.buf) then + if not is_valid_buf(state.buf) then state.buf = create_clean_buf() end @@ -235,6 +263,8 @@ function M.close() end function M.toggle() + refresh_window_state() + if state.win and vim.api.nvim_win_is_valid(state.win) then M.close() else diff --git a/tests/specs/codex_spec.lua b/tests/specs/codex_spec.lua index 3b10db9..5500faf 100644 --- a/tests/specs/codex_spec.lua +++ b/tests/specs/codex_spec.lua @@ -8,6 +8,8 @@ describe('codex.nvim', function() before_each(function() vim.cmd 'set noswapfile' -- prevent side effects vim.cmd 'silent! bwipeout!' -- close any open codex windows + package.loaded['codex'] = nil + package.loaded['codex.state'] = nil end) it('loads the module', function() @@ -56,6 +58,44 @@ describe('codex.nvim', function() assert(not ok, 'Codex window should be closed') end) + it('opens when the tracked window no longer shows the Codex buffer', function() + local codex = require 'codex' + local state = require 'codex.state' + codex.setup { cmd = { 'echo', 'test' } } + + codex.open() + local original_win = vim.api.nvim_get_current_win() + local codex_buf = vim.api.nvim_win_get_buf(original_win) + local other_buf = vim.api.nvim_create_buf(false, true) + + vim.api.nvim_win_set_buf(original_win, other_buf) + codex.toggle() + + local current_win = vim.api.nvim_get_current_win() + eq(codex_buf, vim.api.nvim_win_get_buf(current_win)) + eq(current_win, state.win) + + codex.close() + end) + + it('closes when the current window manually shows the Codex buffer', function() + local codex = require 'codex' + local state = require 'codex.state' + codex.setup { cmd = { 'echo', 'test' } } + + codex.open() + local codex_win = vim.api.nvim_get_current_win() + local codex_buf = vim.api.nvim_win_get_buf(codex_win) + + state.win = nil + vim.api.nvim_set_current_win(codex_win) + vim.api.nvim_win_set_buf(codex_win, codex_buf) + codex.toggle() + + local ok, _ = pcall(vim.api.nvim_win_get_buf, codex_win) + assert(not ok, 'Codex window should be closed') + end) + it('shows statusline only when job is active but window is not', function() require('codex').setup { cmd = { 'sleep', '1000' } } require('codex').open()