Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 45 additions & 10 deletions lua/codex/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -88,18 +89,54 @@ 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

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)
Expand Down Expand Up @@ -164,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

Expand Down Expand Up @@ -230,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
Expand Down
40 changes: 40 additions & 0 deletions tests/specs/codex_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -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()
Expand Down