termite.nvim is a stacking float terminal manager for Neovim, written in Lua.
lua/termite/
init.lua - Main module, public API (toggle, create, focus_next, etc.)
config.lua - Configuration defaults and setup
state.lua - Shared mutable state (terminals list, visibility flags)
terminal.lua - Terminal creation, lifecycle, buffer management
layout/init.lua - Layout module entry
layout/stack.lua - Window geometry: positioning, sizing, reflow
borders.lua - Border character definitions
highlights.lua - Highlight group setup
plugin/termite.lua - Autoloaded: autocmds and user commands
spec/ - Tests using Plenary.nvim busted framework
make test # Run all tests
make test-file FILE= # Run specific test file
make lint # Run luacheck linter
make format # Format code with stylua
make check # Run format, lint, and testStyLua handles all formatting via .stylua.toml:
- Column width: 120
- Indent: Tabs (width 1)
- Quote style: AutoPreferDouble
- Call parentheses: Always
- Syntax: Lua52
- Never manually format; always run
make format
-- termite.nvim
-- Brief description
local config = require("termite.config")
local M = {}
-- Section {{{
M.public_function = function()
-- implementation
end
-- Helper functions {{{
local function helper()
-- implementation
end
-- }}}
-- }}}
return M
-- vim: foldmethod=marker:foldmarker={{{,}}}:foldlevel=0- snake_case for functions, variables, and modules
- UPPER_CASE for module-level constants (e.g.,
DEFAULTS,SUBCOMMANDS) - Descriptive names; avoid abbreviations except well-known ones (buf, win, opts, idx)
Group all require at top. Use local M = require("termite.module") pattern.
- NO inline comments - code should be self-documenting
- File header:
-- termite.nvim+ brief description - Use fold markers
-- {{{and-- }}}for organization - End-of-file:
-- vim: foldmethod=marker:foldmarker={{{,}}}:foldlevel=0 - NOTE comments acceptable for explaining non-obvious behavior
Always validate handles before use:
if term.win and vim.api.nvim_win_is_valid(term.win) then
-- safe to use term.win
endUse pcall() for operations that might fail:
pcall(vim.api.nvim_win_set_cursor, win, { line_count, 0 })Use vim.schedule() for operations after async callbacks:
vim.schedule(function()
if buf and vim.api.nvim_buf_is_valid(buf) then
vim.api.nvim_buf_delete(buf, { force = true })
end
end)- Prefer
vim.api.nvim_*over deprecatedvim.fn.* - Use
vim.tbl_deep_extend("force", default, override)for merging options - Create autocmds with
vim.api.nvim_create_autocmd() - Use
vim.keymap.set()withbuffer = bufnrfor buffer-local maps - Apply window options via
vim.wo[win][opt] = val
- Terminal buffers: scratch buffers (
nvim_create_buf(false, true)) - Windows: floating windows with
nvim_open_win(),relative = "editor" - Shell process:
vim.fn.jobstart(shell, { term = true, on_exit = ... }) - Cleanup: BufWipeout autocmd removes from terminal stack
- Default values in module-level
DEFAULTStable M.setup(opts)merges withvim.tbl_deep_extend("force", ...)- Access via
require("termite.config").values
Tests use Plenary.nvim with busted framework:
Reset modules in before_each for fresh state:
before_each(function()
package.loaded["termite.config"] = nil
config = require("termite.config")
end)- Use assertions:
assert.are.equal(),assert.are.same() - Group with
describe()andit()
- State is centralized in
state.lua- terminals, visibility flags, editor window ref - Layout logic is pure in
layout/stack.lua- no side effects, returns config tables - Terminal lifecycle in
terminal.lua- creates, shows, hides, closes terminals - Public API in
init.lua- coordinates other modules, handles user actions - Autoload behavior in
plugin/termite.lua- user commands and global autocmds
Follow Conventional Commits with scope:
feat(component)- New feature (e.g.,feat(terminal) add winbar)fix(component)- Bug fix (e.g.,fix(layout) corner borders)docs:- Documentation onlyrefactor(component)- Code restructuring without behavior changetest(component)- Test additions or fixeschore:- Build/tooling changes
Scope examples: terminal, layout, config, state, highlights, keymaps
CI runs on push/PR to main branch:
- Format check with StyLua
- Lint with luacheck
- Tests with Plenary
Run make check locally before pushing.