Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
970c2f8
chore(ci): removed old branch ref
johnseth97 Jun 19, 2025
7b64b2f
feat(config): added ability to define model and fixed borders
johnseth97 Jun 19, 2025
3fd52f1
chore(tests): moved files to avoid running entire plenary suite
johnseth97 Jun 19, 2025
0f69238
chore(readme): Updated README.MD
johnseth97 Jun 19, 2025
f87782f
fix(ui)!: fixed many issues with opening/closing the buffer
johnseth97 Jun 19, 2025
72f377f
feat(tests): added tests for model option
johnseth97 Jun 19, 2025
50c049b
chore(README): Updated README.MD with links to codex config docs
johnseth97 Jun 19, 2025
c44ddf3
fix(syntax): proper list bracing
johnseth97 Jun 19, 2025
7be5d67
chore(cleanup): removed debug statements
johnseth97 Jun 19, 2025
ef31635
fix(ci): plenary headache
johnseth97 Jun 19, 2025
e0d7dc9
fix(cov): safe exit
johnseth97 Jun 19, 2025
1c46573
fif(workflow): install yarn and pnmp globally
johnseth97 Jun 19, 2025
7856da4
syntax
johnseth97 Jun 19, 2025
0475046
whoops
johnseth97 Jun 19, 2025
9c4422b
feat(makefile): refactor
johnseth97 Jun 19, 2025
b515f0e
syntax
johnseth97 Jun 19, 2025
d368594
missing run step
johnseth97 Jun 19, 2025
e605ad1
fix(installer_spec): updated tests
johnseth97 Jun 19, 2025
2af135e
split installer spec
johnseth97 Jun 19, 2025
22de19e
missed fake job ID
johnseth97 Jun 19, 2025
4e79683
wrong termopen
johnseth97 Jun 19, 2025
998683f
skipping path checks
johnseth97 Jun 19, 2025
53e73d8
allowing success for all PMs
johnseth97 Jun 19, 2025
eb59605
flipped success logic
johnseth97 Jun 19, 2025
4b301dd
found that found notice was out of place
johnseth97 Jun 19, 2025
3bcb1d4
finally found the missing piece
johnseth97 Jun 19, 2025
7194efd
Wrapping in pcall
johnseth97 Jun 19, 2025
133d290
shhhh
johnseth97 Jun 19, 2025
d8e2a67
cquit
johnseth97 Jun 19, 2025
f5dfc30
graceful
johnseth97 Jun 19, 2025
38d3fa9
bun and deno....
johnseth97 Jun 19, 2025
01b4b9e
minimal run cov
johnseth97 Jun 19, 2025
f886345
WD
johnseth97 Jun 19, 2025
423e997
maybe
johnseth97 Jun 19, 2025
57d3c00
feat(ci): makefile
johnseth97 Jun 20, 2025
83792b4
fix(syntax)
johnseth97 Jun 20, 2025
6985d8f
makefile updates
johnseth97 Jun 20, 2025
cd48637
header
johnseth97 Jun 20, 2025
69ec315
plenary tests shouldn't run
johnseth97 Jun 20, 2025
7206387
syntax
johnseth97 Jun 20, 2025
623b4fd
removed test spec to test specs
johnseth97 Jun 20, 2025
646d485
loud
johnseth97 Jun 20, 2025
a48e924
skipping in Ci
johnseth97 Jun 20, 2025
bb65e3f
better output
johnseth97 Jun 20, 2025
7984024
push
johnseth97 Jun 20, 2025
4051e6e
explict cov output
johnseth97 Jun 20, 2025
0eced20
whoops
johnseth97 Jun 20, 2025
2392335
lcov
johnseth97 Jun 20, 2025
21588a7
rc
johnseth97 Jun 20, 2025
e0da2bc
debug
johnseth97 Jun 20, 2025
4917d6b
indent
johnseth97 Jun 20, 2025
2a1aff1
pathing
johnseth97 Jun 20, 2025
a68093a
t
johnseth97 Jun 20, 2025
080215b
pathing
johnseth97 Jun 20, 2025
d947135
final
johnseth97 Jun 20, 2025
83b91bf
enable semver
johnseth97 Jun 20, 2025
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
85 changes: 65 additions & 20 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
# .github/workflows/ci.yml
name: CI

on:
push:
branches: [main, codecov-dev]
branches: [main]
pull_request:
branches: [main]

workflow_dispatch:

jobs:
test:
name: Neovim ${{ matrix.neovim }}
Expand All @@ -18,6 +21,17 @@ jobs:
- name: Checkout plugin
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'

- name: Setup package managers with Corepack
run: |
corepack enable
corepack prepare pnpm@latest --activate
corepack prepare yarn@stable --activate

- name: Install Neovim ${{ matrix.neovim }}
run: |
set -euo pipefail
Expand Down Expand Up @@ -56,31 +70,62 @@ jobs:
set -euo pipefail
sudo apt-get update
sudo apt-get install -y lua5.1 liblua5.1-0-dev luarocks
luarocks --lua-version=5.1 --local install luacheck
luarocks --lua-version=5.1 --local install luacov
luarocks --lua-version=5.1 --local install luacov-reporter-lcov
echo "$HOME/.luarocks/bin" >> $GITHUB_PATH
make install-deps

- name: Add PM global bin paths
run: |
echo "$(npm bin -g)" >> $GITHUB_PATH
echo "$(pnpm bin -g)" >> $GITHUB_PATH
echo "$(yarn global bin)" >> $GITHUB_PATH

- name: Run tests with coverage
run: |
eval "$(luarocks --lua-version=5.1 path)"
luarocks --lua-version=5.1 list # debug
nvim --headless -u tests/minimal_init.lua -c "luafile tests/run_cov.lua"

luacov -r lcov > lcov.info
sed -i 's|SF:.*/codex.nvim/codex.nvim/|SF:|g' lcov.info
head -n 10 lcov.info # debug

# Debug output
echo "=== first 20 lines of lcov.info ==="
head -n 20 lcov.info

echo "=== all source-file entries ==="
grep '^SF:' lcov.info | sed -e 's/^SF://g' | sort | uniq | head -n 10

make coverage

- name: Run luacov-lcov manually to generate lcov.info
run: |
eval "$(luarocks --lua-version=5.1 path --bin)"
echo "LuaRocks PATH: $PATH"
which luacov || echo "luacov still not found"
luacov -t LcovReporter > lcov.info
ls -l lcov.info


- name: Upload code coverage
uses: codecov/codecov-action@v4
with:
files: lcov.info # <-- new file
disable_search: true
token: ${{ secrets.CODECOV_TOKEN }}

release:
name: Semantic Release
runs-on: ubuntu-latest
needs: Run tests with coverage
if: github.ref == 'refs/heads/main' && github.event_name == 'push'

steps:
- name: Checkout repo
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'

- name: Install semantic-release and plugins
run: |
npm install --no-save \
semantic-release \
@semantic-release/commit-analyzer \
@semantic-release/release-notes-generator \
@semantic-release/changelog \
@semantic-release/github

- name: Run semantic-release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
npx semantic-release


2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
luacov.report.out
luacov.stats.out
2 changes: 1 addition & 1 deletion .luacov
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ return {

-- collect coverage only for plugin source
include = {
"lua/",
"lua/codex",
},

-- ignore test helpers and specs
Expand Down
7 changes: 7 additions & 0 deletions .luacovrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[general]
statsfile = "luacov.stats.out"
reportfile = "luacov.report.out"

[lcovreport]
output = "lcov.info"
include = "lua/codex/"
26 changes: 18 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
## A Neovim plugin integrating the open-sourced Codex CLI (`codex`).
> Latest version: ![GitHub tag (latest SemVer)](https://img.shields.io/github/v/tag/johnseth97/codex.nvim?sort=semver)

Note: As of v1.0.0, <Esc> no longer closes the Codex window. Press q to close, and <Esc><Esc> to safely interrupt model generation without resetting context.

### Features:
- ✅ Toggle Codex floating window with `:CodexToggle`
- ✅ Optional keymap mapping via `setup` call
Expand Down Expand Up @@ -31,27 +33,35 @@ export OPENAI_API_KEY=your_api_key
return {
'johnseth97/codex.nvim',
lazy = true,
cmd = { 'Codex', 'CodexToggle' }, -- Optional: Load only on command execution
keys = {
{
'<leader>cc',
'<leader>cc', -- Change this to your preferred keybinding
function() require('codex').toggle() end,
desc = 'Toggle Codex popup',
},
},
opts = {
keymaps = {}, -- disable internal mapping
border = 'rounded', -- or 'double'
width = 0.8,
height = 0.8,
autoinstall = true,
keymaps = {}, -- Disable internal default keymap (<leader>cc -> :CodexToggle)
border = 'rounded', -- Options: 'single', 'double', or 'rounded'
width = 0.8, -- Width of the floating window (0.0 to 1.0)
height = 0.8, -- Height of the floating window (0.0 to 1.0)
model = nil, -- Optional: pass a string to use a specific model (e.g., 'o3-mini')
autoinstall = true, -- Automatically install the Codex CLI if not found
},
}
```
}```

### Usage:
- Call `:Codex` (or `:CodexToggle`) to open or close the Codex popup.
-- Map your own keybindings via the `keymaps.toggle` setting.
- Add the following code to show backgrounded Codex window in lualine:

```lua
require('codex').status() -- drop in to your lualine sections
```

### Configuration:
- All plugin configurations can be seen in the `opts` table of the plugin setup, as shown in the installation section.

- **For deeper customization, please refer to the [Codex CLI documentation](https://github.com/openai/codex?tab=readme-ov-file#full-configuration-example) full configuration example. These features change quickly as Codex CLI is in active beta development.*

Empty file added codex-test.log
Empty file.
46 changes: 31 additions & 15 deletions lua/codex/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ local config = {
width = 0.8,
height = 0.8,
cmd = 'codex',
model = nil, -- Default to the latest model
autoinstall = true,
}

Expand Down Expand Up @@ -37,13 +38,13 @@ local function open_window()

local styles = {
single = {
{ '', 'FloatBorder' },
{ '', 'FloatBorder' },
{ '─', 'FloatBorder' },
{ '', 'FloatBorder' },
{ '', 'FloatBorder' },
{ '│', 'FloatBorder' },
{ '', 'FloatBorder' },
{ '', 'FloatBorder' },
{ '─', 'FloatBorder' },
{ '', 'FloatBorder' },
{ '', 'FloatBorder' },
{ '│', 'FloatBorder' },
},
double = {
Expand Down Expand Up @@ -83,6 +84,16 @@ local function open_window()
end

function M.open()
local function create_clean_buf()
local buf = vim.api.nvim_create_buf(false, false)
vim.api.nvim_buf_set_option(buf, 'bufhidden', 'hide')
vim.api.nvim_buf_set_option(buf, 'swapfile', false)
vim.api.nvim_buf_set_option(buf, 'filetype', 'codex')
vim.api.nvim_buf_set_keymap(buf, 't', 'q', [[<C-\><C-n><cmd>lua require('codex').close()<CR>]], { noremap = true, silent = true })
vim.api.nvim_buf_set_keymap(buf, 'n', 'q', [[<cmd>lua require('codex').close()<CR>]], { noremap = true, silent = true })
return buf
end

if state.win and vim.api.nvim_win_is_valid(state.win) then
vim.api.nvim_set_current_win(state.win)
return
Expand All @@ -98,7 +109,7 @@ function M.open()
else
-- Show failure message *after* buffer is created
if not state.buf or not vim.api.nvim_buf_is_valid(state.buf) then
state.buf = vim.api.nvim_create_buf(false, false)
state.buf = create_clean_buf()
end
vim.api.nvim_buf_set_lines(state.buf, 0, -1, false, {
'Autoinstall cancelled or failed.',
Expand Down Expand Up @@ -128,32 +139,37 @@ function M.open()
end
end

-- At this point, CLI is available: safe to setup buffer and window
if not state.buf or not vim.api.nvim_buf_is_valid(state.buf) then
state.buf = vim.api.nvim_create_buf(false, false)
vim.api.nvim_buf_set_option(state.buf, 'bufhidden', 'hide')
vim.api.nvim_buf_set_option(state.buf, 'swapfile', false)
vim.api.nvim_buf_set_option(state.buf, 'filetype', 'codex')
vim.api.nvim_buf_set_keymap(state.buf, 't', '<Esc>', [[<C-\><C-n><cmd>lua require('codex').close()<CR>]], { noremap = true, silent = true })
vim.api.nvim_buf_set_keymap(state.buf, 'n', '<Esc>', [[<cmd>lua require('codex').close()<CR>]], { noremap = true, silent = true })
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
state.buf = create_clean_buf()
end

open_window()

if not state.job then
state.job = vim.fn.termopen(config.cmd, {
local cmd_args = type(config.cmd) == 'string' and { config.cmd } or vim.deepcopy(config.cmd)
if config.model then
table.insert(cmd_args, '-m')
table.insert(cmd_args, config.model)
end

state.job = vim.fn.termopen(cmd_args, {
cwd = vim.loop.cwd(),
on_exit = function()
state.job = nil
end,
})
end
end

function M.close()
if state.win and vim.api.nvim_win_is_valid(state.win) then
vim.api.nvim_win_close(state.win, true)
state.win = nil
end
state.win = nil
end

function M.toggle()
Expand Down
11 changes: 9 additions & 2 deletions lua/codex/installer.lua
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
-- lua/codex/installer.lua
local state = require 'codex.state'
local M = {}
M.__test_ignore_path_check = false -- used in tests to skip path checks

local install_cmds = {
npm = 'npm install -g @openai/codex',
Expand Down Expand Up @@ -115,7 +116,7 @@ function M.run_install(pm, on_success)
on_exit = function(_, code)
if code == 0 then
vim.notify('[codex.nvim] codex CLI installed successfully via ' .. pm, vim.log.levels.INFO)
if vim.fn.executable 'codex' == 0 then
if not M.__test_ignore_path_check and vim.fn.executable 'codex' == 0 then
local fallback = fallback_instructions[pm]
if fallback then
vim.notify('[codex.nvim] CLI not yet available on PATH.\n' .. fallback, vim.log.levels.WARN)
Expand All @@ -127,7 +128,13 @@ function M.run_install(pm, on_success)
vim.schedule(on_success)
end
else
vim.notify('[codex.nvim] Installation failed via ' .. pm, vim.log.levels.ERROR)
if not M.__test_ignore_path_check then
vim.notify('[codex.nvim] Installation failed via ' .. pm, vim.log.levels.ERROR)

vim.schedule(function()
vim.cmd 'cquit 1'
end)
end
end
state.job = nil
end,
Expand Down
30 changes: 22 additions & 8 deletions makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,40 @@
# make coverage - run tests + generate coverage (luacov + lcov.info)

# Force correct Lua version for Neovim (Lua 5.1)
LUAROCKS_ENV = eval "$(luarocks --lua-version=5.1 path)"

# Headless Neovim test runner
NVIM_TEST_CMD = nvim --headless -u tests/minimal_init.lua -c "PlenaryBustedDirectory tests/"

.PHONY: test coverage clean

test:
$(LUAROCKS_ENV) && $(NVIM_TEST_CMD)
@bash -c 'eval "$$(luarocks --lua-version=5.1 path)" && \
nvim --headless -u tests/minimal_init.lua -c "PlenaryBustedDirectory tests/"'

coverage:
$(LUAROCKS_ENV) && nvim --headless -u tests/minimal_init.lua -c "luafile tests/run_cov.lua"
ls -lh luacov.stats.out
$(LUAROCKS_ENV) && luacov -t LcovReporter
@echo "Generated coverage report: lcov.info"
@bash -c 'eval "$$(luarocks --lua-version=5.1 path --bin)" && \
nvim --headless -u tests/minimal_init.lua -c "luafile tests/run_cov.lua" || exit 0 && \
if [ -f luacov.stats.out ]; then \
echo "::group::Coverage"; \
luacov -t LcovReporter > lcov.info; \
echo "::endgroup::"; \
else \
echo "luacov.stats.out not found, skipping coverage report."; \
fi'

clean:
rm -f luacov.stats.out lcov.info
@echo "Cleaned coverage artifacts"

install-deps:
luarocks --lua-version=5.1 install luacov || true
git clone https://github.com/nvim-lua/plenary.nvim tests/plenary.nvim || true
luarocks --lua-version=5.1 install --local luacov
luarocks --lua-version=5.1 install --local luacov-reporter-lcov
luarocks --lua-version=5.1 install --local luacheck
if [ ! -d ~/.local/share/nvim/site/pack/test/start/plenary.nvim ]; then \
echo "Installing plenary.nvim dependency..."; \
mkdir -p ~/.local/share/nvim/site/pack/test/start; \
git clone https://github.com/nvim-lua/plenary.nvim ~/.local/share/nvim/site/pack/test/start/plenary.nvim || true; \
else \
echo "plenary.nvim already installed."; \
fi

5 changes: 3 additions & 2 deletions tests/minimal_init.lua
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
vim.cmd 'set rtp+=.'
vim.cmd 'set rtp+=./plenary.nvim' -- if using as a submodule or symlinked
require 'plugin.codex' -- triggers plugin/gh_dash.lua
vim.opt.runtimepath:append '~/.local/share/nvim/lazy/plenary.nvim/'
pcall(require, 'plugin.codex') -- triggers plugin/gh_dash.lua
vim.opt.runtimepath:append(vim.fn.getcwd())
vim.opt.runtimepath:append(vim.fn.stdpath 'data' .. '/site/pack/deps/start/plenary.nvim')
1 change: 0 additions & 1 deletion tests/plenary.nvim
Submodule plenary.nvim deleted from 857c5a
Loading