Files
dotfiles/dot_config/nvim/AGENTS.md
T
2026-08-02 12:00:14 -04:00

3.8 KiB

Neovim Config

Plugin management uses Neovim's native vim.pack (0.12+). No lazy.nvim.

Layout

  • init.lua — entry point: require("config") then require("plugins")
  • lua/config/*.lua — core settings (options, keymaps, LSP, autocmds)
  • lua/plugins/init.lua — loads every plugin module in order, hosts PackChanged build hooks
  • lua/plugins/<name>.lua — one self-contained module per plugin
  • nvim-pack-lock.json — lock file, auto-updated by vim.pack, commit it

Plugin module structure

Each lua/plugins/<name>.lua is self-contained: it declares its own vim.pack.add specs (including shared deps like nvim-lua/plenary.nvim, nvim-tree/nvim-web-devicons, MunifTanjim/nui.nvim — repeated adds are idempotent), then runs setup/config code directly. All plugins load eagerly at startup; there is no lazy loading.

Example:

vim.pack.add({
  { src = "https://github.com/owner/repo.nvim" },
})

require("repo").setup({ ... })

Adding a new plugin

  1. Create lua/plugins/<name>.lua with a vim.pack.add spec and its config
  2. Add require("plugins.<name>") to lua/plugins/init.lua (theme first if it affects colorscheme/highlights)
  3. Restart nvim — the plugin is cloned automatically on first startup

Spec conventions

  • version — pin to a semver release: version = vim.version.range("^1"); use a branch name string (e.g. version = "main") only when the plugin requires it (nvim-treesitter and its textobjects do)
  • name — set only when the repo name is undesirable (e.g. catppuccin/nvim is installed as catppuccin)
  • Shared deps listed explicitly in every module that needs them

Build steps

There is no build field. Post-install/update steps run from the PackChanged autocmd in lua/plugins/init.lua, keyed by plugin name. It must stay registered before the first vim.pack.add call, so keep new hooks in that file:

-- in the PackChanged callback in lua/plugins/init.lua
if name == "my-plugin" and (kind == "install" or kind == "update") then
  vim.system({ "make" }, { cwd = path })
end

Current hooks: make for telescope-fzf-native, parser update for nvim-treesitter.

Useful commands

vim.pack has no :Pack* user commands — everything goes through :lua. Plugin names are the installed directory names (e.g. telescope-fzf-native.nvim).

  • :lua vim.pack.update() — fetch and update all plugins to their pinned version (or latest branch), updating nvim-pack-lock.json
  • :lua vim.pack.update({ "gitsigns.nvim" }) — update a single plugin
  • :lua vim.pack.update(nil, { offline = true }) — update using cached refs, no network fetch
  • :lua vim.pack.update(nil, { target = "lockfile" }) — restore all plugins to the revisions in nvim-pack-lock.json (rollback)
  • :lua vim.pack.get() — list all installed plugins with spec, path, revision, active status
  • :lua vim.pack.add({ { src = "https://github.com/owner/repo.nvim" } }) — install/register a plugin on the fly (restart required to persist in config)
  • :lua vim.pack.del("name") — delete a plugin directory and its lock entry

Updating / removing

  • Update everything: :lua vim.pack.update() (see commands above for variants)
  • Remove a plugin: delete its entry from vim.pack.add calls and its lua/plugins/<name>.lua + require in lua/plugins/init.lua, then run :lua vim.pack.del("name") to delete the directory and lock entry

Pitfalls

  • First startup installs missing plugins and asks for confirmation — expected behavior, not an error
  • The first vim.pack.add call in a session triggers installs, so PackChanged hooks must be registered in lua/plugins/init.lua before the requires
  • Only install actual Neovim plugins via vim.pack — CLI tools (e.g. fd, ripgrep) must not be added
  • Plugins already on disk are not re-checked against their spec on startup; run vim.pack.update() to sync revisions