nvim/AGENTS.md

11 KiB

AGENTS: Neovim Config Migration

Scope: applies to the entire ~/.config/nvim directory tree.

This repository is being migrated to a modern, minimal Neovim setup driven by Lua and lazy.nvim. Follow these rules when making changes.

Goals

  • Modern Lua-first config; avoid Vimscript unless explicitly requested.
  • Keep it minimal, fast, and maintainable.
  • Base plugin management on lazy.nvim with modular plugin specs.
  • Support Telescope navigation, netrw for file browsing/preview, Oil.nvim for file operations, LSP, Treesitter, Copilot, and sane UX defaults.
  • Native project-local configuration via exrc + secure (no external config plugins).

Do Not Reintroduce

  • Custom Vimscript tabline/statusline, foldtext, UI hacks.
  • Legacy autocommands toggling cursorline/column per window.
  • CoC or CoC-specific config.
  • Neo-tree (skipped in favor of netrw for navigation).
  • Providers for ruby/perl/node (disable unless required by a plugin).
  • Auto-reload vimrc-on-write templates.
  • cursorcolumn and old folding logic not related to UFO.
  • neoconf plugin (incompatible with Neovim 0.11+, use native exrc instead).
  • Motion plugins like leap.nvim or flash.nvim (not needed).
  • Markdown rendering plugins (skipped entirely).

Repository Structure (target)

~/.config/nvim/
├── init.lua                   -- entrypoint; bootstraps lazy.nvim and loads Lua modules
└── lua/
    ├── settings.lua          -- non-plugin options
    ├── keymaps.lua           -- non-plugin keymaps
    ├── autocmds.lua          -- non-plugin autocommands
    ├── abbreviations.lua     -- insert-mode abbreviations
    ├── netrw-config.lua      -- netrw configuration
    ├── utils.lua             -- helpers (only if needed)
    └── plugins/              -- one file per plugin or domain
        ├── telescope.lua
        ├── treesitter.lua
        ├── cmp.lua
        ├── lsp.lua
        ├── copilot.lua
        ├── oil.lua
        ├── ufo.lua
        ├── gitsigns.lua
        ├── none-ls.lua
        ├── nvim-lint.lua
        ├── mason.lua
        ├── mason-lspconfig.lua
        ├── mason-tool-installer.lua
        ├── comment.lua
        ├── surround.lua
        ├── autopairs.lua
        └── indent-blankline.lua
├── after/
│   ├── ftplugin/
│   │   └── php.lua           -- PHP-specific settings (includeexpr for gf)
│   └── queries/              -- Custom Treesitter queries
│       ├── css/
│       │   └── highlights.scm
│       └── html/
│           └── highlights.scm
├── templates/
│   └── template.sh           -- Shell script template
└── legacy/                   -- Archived Vimscript config (reference only)

Coding Conventions

  • Use Lua APIs: vim.opt, vim.api.nvim_create_autocmd, vim.keymap.set.
  • No inline Vimscript or vim.cmd blocks unless strictly necessary.
  • Keep plugin configuration self-contained in its plugin spec file.
  • Prefer small, readable modules and minimal configuration over heavy customization.
  • Keymaps: use vim.keymap.set with { silent = true, noremap = true } defaults unless otherwise required.
  • Autocommands: group via vim.api.nvim_create_augroup and create specific, narrowly scoped autocmds.
  • Avoid global state; return tables from modules and plugin specs.

Plugin Management (lazy.nvim)

  • Each plugin lives in lua/plugins/<name>.lua and returns a spec table.
  • Use opts = {} for default options and config = function(_, opts) ... end for setup.
  • Do not install any plugin not listed without explicit user confirmation (proposal and rationale are welcome).
  • Rejected: folke/neoconf.nvim (incompatible with Neovim 0.11+ vim.lsp.config API).

Required Plugin Categories

  • Core: nvim-lspconfig, nvim-cmp, cmp-nvim-lsp, cmp-buffer, cmp-path, LuaSnip.
  • Navigation: telescope.nvim + telescope-fzf-native.nvim, oil.nvim.
  • Treesitter: nvim-treesitter, nvim-treesitter-textobjects, nvim-ts-autotag.
  • UX/Editing: Comment.nvim, nvim-surround, nvim-autopairs, indent-blankline.nvim, nvim-ufo, undotree.
  • Git: gitsigns.nvim.
  • Copilot: copilot.lua, copilot-cmp.
  • Formatting/Linting: none-ls.nvim, nvim-lint.
  • LSP Management: mason.nvim, mason-lspconfig.nvim, mason-tool-installer.nvim.

Workflow Requirements to Preserve

  • Netrw for visual context and project structure browsing (tree view, preview splits).
  • Telescope for fuzzy finding (files, grep, buffers, LSP symbols).
  • Oil.nvim for file manipulation (handles buffer sync on rename/move/delete).
  • LSP for navigation (gd, gr, K, etc.).
  • Heavy HTML/PHP/JS/Markdown usage (WordPress plugin dev) — prioritize these languages in LSP/Treesitter.
  • Format-on-save with toggle capability.
  • Project-local configuration via .nvim.lua files.

Behaviours to Keep (modernized)

  • Abbreviations: adn→and, waht→what, tehn→then, functin→function, positin→position.
  • Templates: auto-populate .sh from template.
  • Whitespace highlighting (use modern alternatives, e.g., listchars, plugins if needed).
  • Persistent folds (prefer nvim-ufo).
  • Spell & text: spelllang=en_gb, custom listchars, showbreak.
  • Keyword characters: iskeyword+=$ (for PHP/shell variables), iskeyword+=- (for CSS/HTML/config files).

Current Status (Phase 10 Complete)

  • Phase 1-2: Archive legacy, bootstrap lazy.nvim
  • Phase 3: Core editing & LSP (native exrc + vim.lsp.config migration complete)
  • Phase 4: Navigation (Telescope, netrw, Oil.nvim)
  • Phase 5: Treesitter (parsers, textobjects, autotag)
  • Phase 6: UX/Editing (Comment, surround, autopairs, indent guides, UFO, undotree)
  • Phase 7: Git integration (Gitsigns)
  • Phase 8: Copilot integration (copilot.lua + copilot-cmp)
  • Phase 9: Formatting & Linting (none-ls, nvim-lint, Mason tool installer)
  • Phase 10: Migrate kept behaviors (abbreviations, templates, custom Treesitter queries)
  • ⏸️ Phase 11: Cleanup & validation (pending)

Migration Notes

  • Do not edit legacy Vimscript files except to extract settings to Lua. Keep them intact until migration completes.
  • Introduce init.lua and bootstrap lazy.nvim before adding plugins.
  • Disable unnecessary providers early: vim.g.loaded_ruby_provider = 0, etc.
  • Keep startup fast; avoid unnecessary autoloading or heavy defaults.
  • When cleaning, archive existing files into a legacy/ folder within this config instead of deleting. Maintain a brief index if helpful.

Validation

  • Ensure Neovim starts without errors and with minimal startup time.
  • Verify Telescope navigation, netrw browsing, Oil.nvim file operations, LSP basics, and completion.
  • Keep plugin count tight; remove anything unused.

Key Decisions & Architecture

LSP Configuration

  • Modern API (Neovim 0.11+): Uses vim.lsp.config() + vim.lsp.enable(), NOT require('lspconfig')[server].setup()
  • Project-local config: Native exrc + secure (no neoconf - incompatible with 0.11+)
  • Config format: .nvim.lua files return { lsp = { [server_name] = { settings = {...} } } }
  • Security: secure mode prompts user to trust .nvim.lua files (one-time per file hash)
  • Settings loading: on_new_config hook loads from actual root_dir (not cwd)
  • PHP: intelephense with single_file_support = false, uses environment.includePaths for external libs

Navigation Strategy

  • netrw: Visual context, tree view, preview splits (horizontal 50/50 below)
  • Telescope: Fuzzy finding (files, grep, buffers, LSP symbols)
  • Oil.nvim: File manipulation (handles buffer sync on rename/move/delete)
  • PHP gf enhancement: Custom includeexpr in after/ftplugin/php.lua for WordPress/PHP patterns

Formatting & Linting

  • Formatters: prettier, phpcbf, stylua, black (project-local → Mason → global)
  • Linters: eslint_d, phpcs, markdownlint, ruff (via nvim-lint)
  • Format-on-save: Enabled by default, toggle with <leader>lt
  • Philosophy: Formatters are source of truth; Neovim settings match formatter rules per filetype

Treesitter

  • Parsers: lua, vim, vimdoc, php, html, javascript, typescript, tsx, css, scss, json, markdown, bash, regex
  • Features: Incremental selection (CR/BS), textobjects (functions, classes, parameters), autotag
  • Custom queries: after/queries/css/highlights.scm, after/queries/html/highlights.scm

Session Management

  • Auto-load: On VimEnter, loads Session.vim if it exists (unless files specified on command line)
  • Auto-save: On VimLeavePre, saves to Session.vim if it already exists
  • Manual control: Create with :mksession to enable; delete to disable
  • Per-directory: Sessions are opt-in and workspace-specific

Developer Workflows

Testing Changes

# 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

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 LspAttach autocmd with actual root_dir.

Process

  • Before large changes, update the task plan via the CLI update_plan tool.
  • Keep the live checklist in MIGRATION_PLAN.md:1 up to date and in sync with changes.
  • After any config or plugin change, immediately update MIGRATION_PLAN.md (check off items, add notes, or adjust next steps).
  • After any change or decision, also update LOG.md:1 (decisions log and design docs).
  • After adding/removing/editing any keymaps, immediately update README.md with the change (add new entries, remove deleted mappings, or update descriptions).
  • After changing formatter/linter configuration, standards, or tool resolution, immediately update the "Configuration" section in README.md (update tool lists, override instructions, or behavior descriptions).
  • At the start of each phase, confirm scope and priorities for that phase.
  • Execute phases via subphases (N.x), where each bullet under a phase is its own implement-and-test step (e.g., Phase 3.1, 3.2, 3.3, 3.4).
  • Record decisions and rationale in LOG.md:1 as they're made.
  • Keep PR-sized patches; avoid broad unrelated edits.
  • Document non-obvious choices in commit messages or short comments near the code that needs it.