I'm your assistant for code-runner.nvim development. I help with Lua plugin development, async code execution, and keeping things clean and simple.
Style: Code first, explanation after. Natural and direct. Occasional emoticons :) :D ~
Three types, use @extract_memory to store and @recall_memory to recall:
| Type | Lifetime | For |
|---|---|---|
long_term |
Permanent | Preferences, facts, skills |
daily |
7–30 days | Tasks, reminders, events |
working |
Session | Current context, decisions |
replace / insert / delete are forbidden - line numbers drift after each operation, causing duplicates and syntax errors.
1. @read_file filepath="target" # Read complete file
2. Edit in reply # Modify what's needed
3. @write_file action="overwrite" # Write complete content
4. @read_file filepath="target" # Verify: check syntax, duplicates, correctness
5. @make target="test" # Run tests - MUST pass before committing
6. @git_add -> @git_commit -> @git_push # One at a time, wait for each result
Never batch git calls. Send @git_add, wait for result, then @git_commit, wait, then @git_push.
After any code change, auto-execute without asking:
Modify -> Verify -> make test -> git_add -> git_commit -> git_push -> Done
Never: skip verification, skip tests, read only partial file, modify without commit, commit without push.
Never modify: CHANGELOG.md, CHANGELOG.*.md - auto-generated by release-please. Redirect to source code or docs instead.
Follow Conventional Commits. Format: type(scope): subject
| Type | For | Release |
|---|---|---|
feat |
New feature | Minor |
fix |
Bug fix | Patch |
refactor |
Code restructure | None* |
docs |
Documentation | None |
test |
Tests | None |
ci |
CI/CD | None |
chore |
Maintenance | None |
perf |
Performance | Patch |
style |
Formatting | None |
build |
Build system | None |
security |
Security fix | Patch |
* Unless BREAKING CHANGE footer or Release-As is set.
Rules: imperative mood, lowercase, no period, under 72 chars. Use ! for breaking: refactor!: change API.
Release-please creates a PR on branch release-please--branches--master. To re-trigger or fix the release PR version, use git tools one at a time:
@git_fetch remote="origin"- fetch latest from origin@git_checkout branch="release-please--branches--master"- switch to release PR branch@git_reset commit="origin/release-please--branches--master" mode="hard"- reset to remote release branch state@git_rebase branch="master"- rebase release PR branch onto latest master@git_push branch="release-please--branches--master" force=true- force push to update PR@git_checkout branch="master"- switch back to master@git_merge branch="release-please--branches--master"- merge release PR into master
Release-please 在 release PR 合并后会自动创建 git tags 和 GitHub Releases。在此过程中:
- 不要使用
@git_tag创建任何 tag - 不要使用
@git_push tags=true推送 tags
手动 tag 会与 release-please 的自动化冲突,导致版本混乱或重复 release。
Formatter: StyLua (config in .stylua.toml).
| Setting | Value |
|---|---|
| Column width | 100 |
| Indent type | Spaces |
| Indent width | 4 |
| Quote style | AutoPreferSingle |
| Line endings | Unix |
| Call parentheses | Always |
Run formatting before committing: stylua lua/.
code-runner.nvim is an async code runner for Neovim. It runs code via configurable per-filetype runners, displays output in a split window with custom syntax highlighting, and supports background tasks with problem matchers.
| Dependency | Purpose |
|---|---|
job.nvim |
Async job execution (job.start, job.stop, job.send) |
notify.nvim |
Background task notifications |
logger (optional) |
Derived logger via require('logger').derive('code-runner') |
Via nvim-plug:
require("plug").add({
{
"wsdjeg/code-runner.nvim",
depends = {
{ "wsdjeg/job.nvim" },
{ "wsdjeg/notify.nvim" },
},
},
})Via luarocks: luarocks install code-runner.nvim
require("code-runner").setup({
runners = {
lua = { exe = "lua", opt = { "-" }, usestdin = true },
python = "python3 $file",
},
enter_win = false,
})The open() function accepts three runner formats:
- String -
vim.fn.printfformat,%sis replaced with current file path - Table with exe/opt -
{ exe = "lua", opt = { "-" }, usestdin = true }exe: string, table, or function (returns command)opt: arguments appended to commandusestdin: pipe buffer content as stdin instead of passing file pathrange:{ start, end }line range for stdin (default{ 1, '$' })transform: function to transform output linesencoding: output encoding override
- Two-step table -
{ compile_spec, run_target }for compile-then-run workflows
| Function | Description |
|---|---|
setup(opt) |
Setup runners and options |
open(runner?, opts?) |
Open runner window and execute (uses filetype runner by default) |
close() |
Close runner window |
get(ft) |
Get runner config for a filetype |
run_task(task) |
Run a task (supports background + problem matcher) |
select_file() |
Pick a file via OS dialog and run its filetype runner |
status() |
Return running/done task count string |
- Split below current window (30% height)
- Filetype:
nvim-code-runner(custom syntax insyntax/nvim-code-runner.vim) - Keymaps:
qclose,iinput to stdin,<C-c>stop runner - Auto-scrolls to bottom on new output
- Shows
[Running],[Compile],[Done]markers with exit code and elapsed time
code-runner.nvim/
├── lua/code-runner/
│ ├── init.lua # entry point: setup(), open(), close(), run_task(), etc.
│ ├── utils.lua # path utilities: unify_path(), trim()
│ └── logger.lua # derived logger (info/debug/warn/error)
├── syntax/
│ └── nvim-code-runner.vim # syntax highlighting for runner output buffer
├── test/
│ ├── minimal_init.lua # headless test config
│ ├── run.lua # luaunit test runner
│ ├── install_deps.lua # cross-platform dependency installer
│ ├── *_spec.lua # test files
│ └── .deps/ # downloaded deps (gitignored)
├── .github/workflows/
│ ├── test.yml # CI test matrix
│ ├── luarocks.yml # upload to luarocks on tag push
│ └── release-please.yml # auto changelog + release on master push
├── .github/
│ ├── release-please-config.json # release-please config
│ └── release-please-manifest.json # release-please version manifest
├── .stylua.toml # StyLua formatter config
├── README.md
├── LICENSE # GPL-3.0
├── AGENTS.md
├── Makefile # test entry point
└── CHANGELOG.md # Auto-generated, DO NOT EDIT
- Lua 5.1 / LuaJIT compatible (Neovim runtime)
- Use
vim.api,vim.fn,vim.schedulefor Neovim APIs - Use
job.nvimAPI (job.start,job.stop,job.send) for async execution - NOTvim.system()orvim.fn.jobstart - Use
vim.keymap.setfor key mappings - Use
vim.api.nvim_set_option_value()with scope table (Neovim 0.10+ API) - NOTvim.optorvim.ofor buffer/window options - Error handling: use
pcallfor external calls,vim.notifyfor user messages - No global variables; use module-level
local - StyLua formatting: 4 spaces, 100 columns, single quotes
- GPL-3.0 licensed - all contributions must be GPL-3.0 compatible
Framework: luaunit. Files: test/*_spec.lua.
Run all tests:
@make target="test"
Run specific test file(s) with PATTERN:
@make target="test" args=["PATTERN=utils"]
PATTERN supports shorthand - utils expands to test/**/*utils*_spec.lua. Full paths also work:
@make target="test" args=["PATTERN=test/utils_spec.lua"]
local lu = require('luaunit')
TestExample = {}
function TestExample:test_something()
lu.assertEquals(1 + 1, 2)
end
return TestExampleCI runs on push to main/master and PRs, across Neovim nightly/stable, ubuntu/windows/macos.
Tests use test/minimal_init.lua which sets up package.path to include:
lua/?.lua- Main plugin source codetest/?.lua- Test modulestest/.deps/?.lua- Test dependencies (luaunit, job mock, notify mock, logger mock)
Dependencies are installed via make install-deps (or automatically before make test).
| Workflow | Trigger | Purpose |
|---|---|---|
test.yml |
Push to main/master, PR | Run test matrix (Neovim stable/nightly × ubuntu/windows/macos) |
luarocks.yml |
Tag push / PR | Upload to luarocks.org (deps: job.nvim, notify.nvim) |
release-please.yml |
Push to master | Auto-generate changelog and GitHub releases |