# Neovim Config - AI Agent Instructions ## Project Overview Modern Lua-first Neovim configuration using lazy.nvim, currently in active migration from legacy Vimscript. Target: minimal, fast, tab-per-context workflow with Neo-tree, Telescope, LSP, and Copilot. **Critical**: Read `AGENTS.md` first—it defines all coding rules, migration strategy, and what NOT to reintroduce. ## Architecture & Files ``` ~/.config/nvim/ ├── init.lua # Entry point: loads settings/keymaps/autocmds, bootstraps lazy.nvim ├── lua/ │ ├── settings.lua # Non-plugin vim options (exrc, secure, spelllang, listchars) │ ├── keymaps.lua # Non-plugin keymaps │ ├── autocmds.lua # Non-plugin autocommands │ ├── abbreviations.lua # Insert-mode abbreviations (typo corrections) │ ├── netrw-config.lua # Netrw configuration │ └── plugins/ # One file per plugin/domain (lazy.nvim specs) │ ├── lsp.lua # LSP via vim.lsp.config + vim.lsp.enable (Neovim 0.11+) │ ├── cmp.lua # Completion: nvim-cmp + LuaSnip │ └── mason*.lua # LSP server installation ├── AGENTS.md # PRIMARY: All rules, migration plan, do-not-reintroduce list ├── MIGRATION_PLAN.md # Phase-by-phase checklist (source of truth for progress) ├── README.md # Decision log and design rationale └── legacy/ # Archived Vimscript (do not edit; reference only) ``` ## Critical Patterns ### 1. LSP Configuration (Phase 3 Complete) **Modern API (Neovim 0.11+)**: Uses `vim.lsp.config()` + `vim.lsp.enable()`, NOT `require('lspconfig')[server].setup()`. **CRITICAL (2025-12-07)**: Neovim 0.11+ does NOT support `on_new_config` callback. Use `LspAttach` autocmd instead. ```lua -- lua/plugins/lsp.lua pattern: -- Define config vim.lsp.config(server_name, { capabilities = capabilities, -- NO on_attach here, NO on_new_config here }) -- Enable server vim.lsp.enable({ "lua_ls", "intelephense", ... }) -- Load project settings via LspAttach autocmd vim.api.nvim_create_autocmd('LspAttach', { callback = function(args) local client = vim.lsp.get_client_by_id(args.data.client_id) -- Load .nvim.lua from client.root_dir -- Merge into client.settings -- Send workspace/didChangeConfiguration notification end, }) ``` **Key decisions**: - No neoconf (incompatible with Neovim 0.11+, issue #116) - Native `exrc` + `secure` for project config (see settings.lua) - Project settings loaded via `LspAttach` autocmd (NOT `on_new_config` which is deprecated) - `workspace/didChangeConfiguration` sent after merging settings into `client.settings` ### 2. Project-Local Configuration **Format**: `.nvim.lua` at project root, returns: ```lua return { lsp = { intelephense = { settings = { intelephense = { environment = { includePaths = { "/absolute/path/to/external/lib" } } } } } } } ``` **Security**: `vim.opt.secure = true` prompts user before loading (one-time per file hash). Trusted files stored in `~/.local/state/nvim/trust`. ### 3. Plugin Management - **lazy.nvim**: All plugins in `lua/plugins/` as individual files returning spec tables - **Mason**: Installs LSP servers only; custom lspconfig setup retained - **Plugin specs**: Use `opts = {}` for defaults, `config = function(_, opts)` for setup - **Approval policy**: Do not install unlisted plugins without explicit user confirmation ### 4. Tab-Per-Context Workflow (Future Phase 4) - Each tab maintains own Neo-tree root - Splits stay within tabs - Neo-tree: sidebar toggle + floating view + preview (no buffer pollution) - Heavy PHP/HTML/JS/Markdown usage (WordPress plugin dev) ## Conventions ### Code Style - **Lua APIs only**: `vim.opt`, `vim.keymap.set`, `vim.api.nvim_create_autocmd` - **No Vimscript**: Avoid `vim.cmd` blocks unless strictly necessary - **Keymaps**: `{ silent = true, noremap = true }` by default - **Autocommands**: Group via `vim.api.nvim_create_augroup`, narrow scope ### File Organization - One plugin = one file in `lua/plugins/` - Keep plugin config self-contained in its spec - Settings/keymaps/autocmds: only non-plugin logic in respective files - No global state; return tables from modules ### Migration Process 1. Check `MIGRATION_PLAN.md` for current phase and priorities 2. **Before large changes**: Update plan via CLI `update_plan` tool (if available) 3. **After any change**: Immediately update `MIGRATION_PLAN.md` (check off items, add notes) 4. **After decisions**: Update `README.md` decisions log 5. Execute phases via subphases (N.x); one bullet = one implement-and-test step 6. Archive legacy files to `legacy/` instead of deleting ## Do NOT Reintroduce (from AGENTS.md) - Custom Vimscript tabline/statusline/foldtext - Legacy autocommands (cursorline/column per window) - CoC or CoC-specific config - netrw settings (Neo-tree replaces it) - Providers for ruby/perl/node (disabled unless required) - Auto-reload vimrc-on-write templates - `cursorcolumn` and old folding logic (UFO will handle folding) - neoconf plugin (incompatible with Neovim 0.11+) ## Developer Workflows ### Testing Changes ```bash # Quick syntax check nvim --headless -c 'lua print("Config loads")' -c 'quitall' # Check LSP status in test workspace cd ~/.config/nvim/WORKSPACE_TEST nvim site/external.php # Then :LspInfo # Validate goto-definition for external libs # In external.php, cursor on Util::greetExternal, press gd ``` ### Validation Workspaces - `WORKSPACE_TEST/`: PHP project with `.nvim.lua` and `.git` - `EXTERNAL_TEST/`: External library referenced via includePaths - Test that `gd` resolves symbols in EXTERNAL_TEST from WORKSPACE_TEST ### Current Migration Status (as of 2025-12-07) - ✅ Phase 1-2: Archive legacy, bootstrap lazy.nvim - ✅ Phase 3: Core editing & LSP complete - Settings, completion, LSP servers, Mason installed - Native exrc + vim.lsp.config migration done - Project-local `.nvim.lua` working - ⏸️ Phase 4+: Navigation (Neo-tree, Telescope), Treesitter, UX plugins pending ## Integration Points ### External Dependencies - **Neovim 0.11+**: Required for `vim.lsp.config` API - **LSP Servers** (via Mason): lua_ls, ts_ls, html, cssls, jsonls, bashls, marksman, intelephense - **PHP**: intelephense with `single_file_support = false`, uses `environment.includePaths` for external libs ### Cross-Component Communication - LSP settings flow: `.nvim.lua` → `on_new_config` → `new_config.settings` → `workspace/didChangeConfiguration` - Completion: cmp-nvim-lsp provides capabilities → lspconfig → LSP servers ## Common Issues ### lua_ls Won't Start Mason-installed lua_ls may fail with missing `libbfd-2.38-system.so`. Install via system package manager instead. ### LSP Root Detection If parent repo picked as root, create empty `.git` or `.nvimroot` marker in intended workspace root. ### Duplicate gd Results (Fixed) Was caused by settings loading at wrong time; fixed by using `on_new_config` with actual `root_dir`. ## When Stuck 1. Check `MIGRATION_PLAN.md` for known issues and current phase 2. Review `AGENTS.md` for rules about what to avoid 3. Read `README.md` decisions log for context on past choices 4. Validate with test workspaces before modifying production config