nvim/README.md

7.1 KiB
Raw Blame History

Neovim Rebuild — Decisions & Reference

Authoritative notes for the Neovim migration. Use this alongside MIGRATION_PLAN.md and neovim-migration-guide.md.

  • Migration plan: MIGRATION_PLAN.md
  • Guide and requirements: neovim-migration-guide.md

Decisions Log

Record every decision here with a short rationale. Append new entries; do not rewrite history.

  • 2025-12-06: PHP LSP = intelephense (good PHP ecosystem support; integrates includePaths).
  • 2025-12-06: Enable Markdown LSP = marksman (lightweight, good MD features).
  • 2025-12-06: Use legacy listchars and showbreak values (preserve muscle memory).
  • 2025-12-06: No direnv fallback for local config (keep setup simple and repo-driven).
  • 2025-12-06: Project-local config = layered JSON .nvim.json + .nvim.local.json with .nvimroot as workspace boundary marker (multi-repo friendly).
  • 2025-12-06: Switch to folke/neoconf.nvim for project-local configuration (supersedes custom layered JSON loader); use .neoconf.json at workspace root.
  • 2025-12-06: Use mason.nvim + mason-lspconfig.nvim to install/manage LSP servers; keep custom lspconfig setup; include .neoconf.json in root detection.
    • For PHP validation inside this repo: we require .neoconf.json to attach intelephense to avoid the repos .git being chosen as the LSP root.
  • 2025-12-06: Plugin approval policy — other plugins are allowed, but do not install any plugin not listed without explicit confirmation.
  • 2025-12-07: CRITICAL REGRESSION FIX: Neovim 0.11+ does NOT support on_new_config callback in vim.lsp.config(). Project-local settings (.nvim.lua) must be loaded via LspAttach autocmd instead. The on_new_config hook was silently ignored, causing empty settings and breaking goto-definition for external includes. Solution: Use LspAttach to load project settings, merge into client.settings, and send workspace/didChangeConfiguration notification.
  • 2025-12-07: Native exrc + .nvim.lua finalized as project-local config approach (replaces neoconf, which is incompatible with Neovim 0.11+ native LSP API). Security via vim.opt.secure = true.
  • 2025-12-07: Navigation Phase 4 decisions:
    • Skip Neo-tree in favor of netrw for project visualization
    • Use Telescope as primary "find file" tool with fuzzy finding
    • Add Oil.nvim for file manipulation (rename/move/delete with buffer sync)
    • netrw for tree view and preview splits; Oil for operations that would break buffer names
    • PHP gf enhancement via includeexpr for WordPress/PHP path resolution
  • 2025-12-07: Treesitter Phase 5 decisions:
    • Focus on core languages: PHP, HTML, JavaScript, TypeScript, CSS, Markdown, Lua, Bash, JSON
    • Enable syntax highlighting with performance safeguard (disable for files >100KB)
    • Incremental selection: CR to expand, BS to shrink, S-CR for scope expansion
    • Textobjects for functions (af/if), classes (ac/ic), parameters (aa/ia), conditionals, loops, comments
    • Movement keymaps: ]f/[f for next/prev function, ]c/[c for classes, ]a/[a for parameters
    • Parameter swapping: <leader>a/<leader>A to swap with next/prev parameter
    • Auto-tag for HTML/PHP/JS/React/TS/Vue files (auto-close, auto-rename, close-on-slash)
    • Indent disabled initially (experimental); can enable per-filetype if stable

Project-Local Configuration (design)

Context: Projects can contain multiple git repositories (e.g., WordPress site with theme + multiple plugins). We need a way to set per-project intelephense.includePaths and similar without globalizing settings.

Options considered

  • Layered JSON files (recommended): .nvim.json (committed) + .nvim.local.json (gitignored)
    • Walk upward from current file; collect and merge configs until reaching a boundary marker or filesystem root.
    • Boundary marker: .nvimroot to define a workspace that can encompass multiple repos.
    • Merge order: top → bottom; nearest wins on conflicts; arrays replace by default unless we later add a merge strategy.
    • Pros: safe (data-only), portable, reviewable in PRs.
    • Cons: less dynamic than Lua.
  • Layered Lua files: .nvim.lua + .nvim.local.lua
    • Pros: maximum flexibility (computed paths).
    • Cons: executes code from the repo; security gates required.
  • Env/direnv: rejected (decision 2025-12-06).
  • Central registry file in ~/.config/nvim/: possible later for private overrides, but not primary.

Chosen approach (confirmed)

  • Use folke/neoconf.nvim with .neoconf.json at the workspace root (or project roots) to supply LSP/plugin settings. Multi-repo: keep a single .neoconf.json at the parent workspace folder and open Neovim from there (or use a rooter later if needed).

Example .neoconf.json

{
  "lspconfig": {
    "intelephense": {
      "settings": {
        "intelephense": {
          "environment": {
            "includePaths": [
              "wp-content/themes/my-theme",
              "wp-content/plugins/custom-plugin"
            ]
          }
        }
      }
    }
  }
}
  • Files recognized per directory level:
    • .nvim.json: checked into VCS; shared per-project defaults.
    • .nvim.local.json: gitignored; machine-specific overrides.
  • Loader behavior:
    1. Start at the buffers directory; ascend toward root.
    2. Stop at directory containing .nvimroot (if found) or at filesystem root.
    3. At each level, if .nvim.json or .nvim.local.json exists, parse and stage for merge.
    4. Merge staged configs in ascending order; nearest directory applies last.
  • Path resolution:
    • Relative paths resolve against the topmost boundary (i.e., .nvimroot directory if present; otherwise the highest directory in which a config was found). This allows referencing sibling repos (e.g., theme and plugins) from a single top-level site folder.

Example .nvim.json

{
  "lsp": {
    "php": {
      "intelephense": {
        "includePaths": [
          "wp-content/themes/my-theme",
          "wp-content/plugins/custom-plugin",
          "vendor/some-package/src"
        ]
      }
    }
  }
}

Intended integration

  • A helper module lua/local_config.lua will expose:
    • load(start_dir) -> table collecting and merging configs
    • get(path, default) for reads, e.g., get({"lsp","php","intelephense","includePaths"}, {})
  • LSP wiring (in Phase 3.5):
    • Read includePaths via the helper and pass to settings.intelephense.environment.includePaths in lspconfig.intelephense.setup{}.

Open items to confirm

  • Confirm JSON as the format (vs Lua) for project-local config.
  • Confirm .nvimroot as the workspace boundary marker name.
  • Confirm array merge behavior (replace vs concatenate). Initial proposal: replace.

LSP Scope (initial)

  • Core servers: lua_ls, tsserver, html, cssls, jsonls, bashls
  • PHP: intelephense (decision)
  • Markdown: marksman (decision)
  • Keep configuration minimal; defer language-specific tuning.

Text & Editing Settings

  • spelllang = en_gb
  • listchars and showbreak will reuse legacy values.
  • completeopt = menu,menuone,noselect for nvim-cmp.

Process Reminders

  • After any change or decision, update this README and MIGRATION_PLAN.md.
  • Keep subphases small and verify each step in isolation.