This document provides instructions for AI agents working on the zoekt.nvim project.
zoekt.nvim is a Neovim plugin that integrates the Zoekt code search engine. The plugin provides commands for indexing codebases and searching through them using Zoekt's powerful search capabilities.
# Run all tests
nvim --headless -c "PlenaryBustedDirectory tests/ {minimal_init = 'tests/minimal_init.lua'}"
# Run specific test file
nvim --headless -c "PlenaryBustedFile tests/zoekt_spec.lua"
# Check Lua syntax (requires luacheck)
luacheck lua/
# Format Lua code (requires stylua)
stylua lua/ tests/- Make changes to Lua files in
lua/zoekt/ - Write/update tests in
tests/ - Run tests to verify functionality
- Test manually in Neovim
- Use snake_case for variables and functions
- Use PascalCase for classes/modules
- Indent with 2 spaces
- Follow existing code patterns in the repository
- Document public APIs with comments
local M = {}
-- Private functions
local function private_helper()
-- implementation
end
-- Public API
function M.public_function()
-- implementation
end
return M- Use plenary.nvim's
describeanditDSL - Mock external commands (zoekt binaries) in tests
- Test both success and error cases
- Keep tests isolated and independent
lua/zoekt/init.lua: Main entry point and setuplua/zoekt/config.lua: Configuration managementlua/zoekt/index.lua: Handles ZoektIndex commandlua/zoekt/search.lua: Handles ZoektSearch command
- plenary.nvim: Used for async operations and testing framework
- Zoekt binaries: External dependencies that must be mocked in tests
- User calls
require("zoekt").setup(opts) - Config module merges user options with defaults
- Environment variable
ZOEKT_INDEX_PATHtakes precedence if set - Index path is expanded (~ to home directory)
- Commands are defined in
init.luausingvim.api.nvim_create_user_command - Command handlers parse arguments and delegate to appropriate modules
- Results are displayed using quickfix list (
vim.fn.setqflist)
Use plenary.nvim's async utilities when available:
local Job = require("plenary.job")
Job:new({
command = "zoekt",
args = { "-index", index_path, query },
on_exit = function(j, return_val)
-- handle results
end,
}):start()Always validate inputs and provide helpful error messages:
if not executable_exists("zoekt") then
vim.notify("Zoekt is not installed or not in PATH", vim.log.levels.ERROR)
return
endAlways expand and normalize paths:
local path = vim.fn.expand(config.index_path)
local absolute_path = vim.fn.fnamemodify(path, ":p")describe("zoekt.nvim", function()
describe("ZoektIndex", function()
it("should detect git repositories", function()
-- test implementation
end)
it("should handle non-git directories", function()
-- test implementation
end)
end)
describe("ZoektSearch", function()
it("should populate quickfix list", function()
-- test implementation
end)
end)
end)Mock Zoekt binaries to avoid dependencies in tests:
local function mock_zoekt_command(output)
-- Return mock Job that returns predefined output
end- Path expansion: Always use
vim.fn.expand()for paths with~ - Git detection: Use
vim.fn.finddir(".git", ".;")to detect git repositories - Quickfix formatting: Ensure proper format for
setqflistentries - Async handling: Consider using callbacks or plenary's async for non-blocking operations