# 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 repo’s `.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: `a`/`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 - 2025-12-07: UX/Editing Phase 6 decisions: - Enable signcolumn=yes (always show for LSP diagnostics, git signs) - Enable cursorline (highlight current line) - Enable colorcolumn=80,120 (visual guides at 80 and 120 chars) - NO cursorcolumn (as per AGENTS.md) - NO auto-window toggling behavior (keep settings static, no per-window autocmds) - NO motion plugin (skip leap/flash for simplicity) - Undotree moved to separate phase (6.8) - Comment.nvim for commenting (gcc/gc/gbc/gb keymaps) - nvim-surround for text objects (ys/ds/cs operators) - nvim-autopairs for auto-closing brackets/quotes with Treesitter and cmp integration - indent-blankline for visual indent guides with scope highlighting - nvim-ufo for enhanced folding with Treesitter/LSP providers (zR/zM/K for peek) - undotree for visual undo history (u to toggle) - 2025-12-07: Git integration Phase 7: - Gitsigns with minimal config for signs in gutter (add, change, delete markers) - Hunk navigation: `]h`/`[h` for next/prev hunk - Hunk actions: stage, reset, preview - NO inline blame or advanced features (keep minimal) - 2025-12-07: Copilot Phase 8: - Integrated via copilot.lua + copilot-cmp (completion source) - Auto-trigger suggestions as you type - Copilot suggestions appear before LSP in completion menu (higher priority) - Enabled for all filetypes - No specific Copilot keymaps (use existing cmp keymaps) - Node.js v22.21.1 confirmed working - 2025-12-07: Formatting & Linting Phase 9: - **Philosophy**: Formatters are authoritative; Neovim settings match formatter output - **Formatters**: prettier (JS/TS/CSS/JSON/MD/HTML), phpcbf (PHP/WordPress), stylua (Lua), black (Python) - **Linters**: eslint_d (JS/TS), phpcs (PHP/WordPress), markdownlint (Markdown), ruff (Python) - **Strategy**: Project-local executables first (node_modules/.bin/, vendor/bin/), then Mason, then system PATH - **WordPress**: phpcs/phpcbf already installed globally; use phpcs.xml or --standard=WordPress - **Format-on-save**: Enabled by default, toggle with `lt` - **Manual format**: `lf` (buffer), `lf` (visual range) - **Linting split**: none-ls for formatting only, nvim-lint for diagnostics (none-ls removed linters) - **Python support**: pyright LSP, black formatter, ruff linter, treesitter parser - **Per-filetype indentation**: Explicit settings per filetype to match formatters - PHP: tabs, 2-space display (WordPress standards) - JS/TS/CSS/JSON/HTML: 2 spaces (Prettier) - Lua: 2 spaces (common convention) - Markdown: 2 spaces (Prettier) - Python: 4 spaces (Black/PEP 8) - **Global defaults**: 4 spaces (reasonable baseline for other filetypes) - 2025-12-07: Kept Behaviors Phase 10: - **Abbreviations**: Common typo corrections (`adn→and`, `waht→what`, `tehn→then`, `functin→function`, `positin→position`) in dedicated `lua/abbreviations.lua` file for modularity - **Templates**: Shell script template (template.sh) auto-loaded via BufNewFile autocmd for `*.sh` files - **Whitespace highlighting**: Already handled via `listchars` in Phase 3.2 (settings.lua) - **Persistent folds**: Not needed; UFO handles folding without explicit persistence mechanism - 2025-12-11: Colorscheme Phase 11.2: - **Color palette extraction**: Extracted all 45 color definitions from original Paper Tonic colorscheme - **Structure**: Created `lua/paper-tonic-modern/colors.lua` with comprehensive documentation - **Categories**: Background colors (main, UI, highlights, status), foreground colors (text grays, exceptions), alerts/diagnostics, primary accents (brownish-red), and secondary accents (green/blue/cyan/magenta palettes) - **Format**: Each color defined as `{hex, 256-color, ansi}` tuple for broad terminal compatibility - **Philosophy**: Light, paper-like theme with subtle colors for long reading sessions - **Next steps**: Phase 11.3 will create colorscheme structure and entry point - 2025-12-11: Colorscheme Phase 11.3: - **Colorscheme structure**: Created complete modular colorscheme architecture - **Entry point**: `colors/paper-tonic-modern.lua` properly resets and loads colorscheme - **Main module**: `lua/paper-tonic-modern/init.lua` with helper functions for setting highlights - **Helper functions**: `M.highlight()` for single groups, `M.highlight_all()` for batch operations - **Color conversion**: Smart conversion between gui/cterm/ansi formats - **Group modules**: Created stub files for editor, syntax, treesitter, semantic, lsp, and plugins - **Loading order**: Structured to load groups in logical sequence (editor → syntax → treesitter → semantic → lsp → plugins) - **Validation**: Colorscheme loads successfully, highlights applied correctly - **Language color consistency**: All documentation updated to reflect that each language maintains its color identity everywhere (PHP=primary, HTML=blue, CSS=green, templates=magenta) - 2025-12-11: Colorscheme Phase 11.4: - **Editor highlights**: Comprehensive UI element highlighting (Normal, StatusLine, CursorLine, Visual, Search, Pmenu, Folds, Diffs, Spelling, Messages) - **Syntax highlights**: Traditional Vim syntax groups (Comment, String, Function, Keyword, Type, etc.) with language-specific overrides - **Language support**: Added specific highlighting for CSS (green/c2), HTML (blue/c3), Lua, Markdown, JSON, JavaScript/TypeScript, PHP - **Color verification**: All key groups tested and verified (Normal=#8c8c8c on #ffffff, htmlTag=#005faf, cssClassName=#008700) - **CSS classes**: Green tones (c2) for CSS syntax elements - **HTML tags**: Blue tones (c3) for HTML structure - **PHP syntax**: Primary brownish-red tones for PHP keywords/functions - **Test file**: Created test-colorscheme.lua for visual verification - 2025-12-11: Colorscheme Phase 11.5: - **TreeSitter highlights**: Comprehensive modern `@*` highlight groups implemented - **Core groups**: @variable, @function, @keyword, @string, @number, @boolean, @comment, @type, @property, @operator, @punctuation - **Language constructs**: @keyword.function, @keyword.return, @keyword.conditional, @keyword.repeat, @keyword.exception - **Markup**: @markup.strong, @markup.italic, @markup.heading (1-6), @markup.link, @markup.raw, @markup.list - **Template languages**: @punctuation.special.twig, @keyword.jinja (magenta c5 for template syntax) - **Diagnostics**: @diff.plus, @diff.minus, @diff.delta - **Debug tool**: Added `hi` keymap to show highlight group and resolved colors under cursor - **Validation**: All TreeSitter groups tested and verified with correct palette colors - 2025-12-11: Colorscheme Phase 11.6: - **Language-specific TreeSitter groups**: Enhanced with comprehensive per-language overrides - **CSS/SCSS**: Properties, variables ($var, --custom), functions, tag selectors (green c2 tones) - **HTML**: Tags, attributes, delimiters (blue c3 throughout) - **PHP**: Variables ($var), functions, methods, built-ins ($this, $GLOBALS), properties (primary brownish-red) - **JavaScript/TypeScript**: Variables, functions, properties, built-ins (this, arguments), JSX/TSX tags (primary + blue for JSX) - **Lua**: Variables, functions, built-ins (_G, _VERSION), properties (primary) - **Markdown**: Headings (1-6), links, code blocks, inline code (primary for structure) - **JSON**: Properties, strings, numbers, booleans (neutral colors) - **Bash/Shell**: Variables, functions, built-ins, strings (primary) - **Color consistency verified**: HTML=#005faf (blue), CSS properties=#7c6666 (primary_weak), PHP variables=#7c6666 - **Test files**: Created test-html.html, test-css.css, test-colors.php for validation - 2025-12-11: Colorscheme Phase 11.7: - **Semantic highlighting**: Custom TreeSitter captures for cross-language consistency - **CSS semantic captures**: @CssClassName (green c2), @CssIdentifier (strong green c2_strong, bold), @cssPseudoClass (bold brownish-red primary_strong - distinguishes from green selectors), @cssPseudoElement (bold brownish-red), @cssNestingSelector (strong green), @CssUniversalSelector - **CSS properties**: @CssProp (primary_weak), @CssPropertyValue (bold fg), @CssUnit (delimiter) - **CSS media queries**: @cssMediaFeatureName, @cssMediaQuery, @cssMediaQueryValue - **HTML attributes**: @ClassNameAttribute, @IdAttribute, @DataAttribute (all fg_weak for attribute names) - **HTML data attributes**: @DataAttributeValue (Function color) - **Cross-language consistency**: Critical feature - class="my-class" in HTML uses same color (@CssClassName, green c2) as .my-class in CSS; id="my-id" in HTML uses same color (@CssIdentifier, green c2_strong) as #my-id in CSS - **Visual benefits**: Easy to visually match selectors between HTML and CSS files; consistent color coding across languages - **Custom queries**: Leverages existing after/queries/css/highlights.scm and after/queries/html/highlights.scm - **Priority fix**: Added `(#set! priority 200)` to all custom captures to override built-in captures (@string priority 99, @constant default priority) - **Technical note**: Custom queries require `;extends` directive and higher priority than built-in captures to work correctly - **Pseudo-class design**: Uses bold brownish-red (primary_strong) instead of green to distinguish behavioral modifiers (:hover, :focus) from structural selectors (.class, #id) - 2025-12-11: Colorscheme Phase 11.8: - **LSP highlights**: Comprehensive diagnostic and UI highlights - **LSP diagnostics**: Error (red #d70000), Warn (orange #d75f00), Info (blue #8989af), Hint (green #89af89) - **LSP diagnostic UI**: Underlines (undercurl for errors/warnings), signs, floating windows, virtual text with tinted backgrounds - **LSP references**: Cyan background gradients - Text (#e0eaff subtle), Read (#d4f0ff medium), Write (#a3e0ff strong) - **LSP semantic tokens**: Fallback groups linking to TreeSitter equivalents for consistency - **Telescope highlights**: Neutral base with primary accent for matching, selection, and titles - **Gitsigns highlights**: Status colors - Add (green), Change (blue), Delete (red); inline diff backgrounds - **nvim-cmp highlights**: Primary tones for item kinds, bold for match highlighting, italic for menu - **Oil.nvim highlights**: Bold directories, status colors for permissions (read=green, write=orange, execute=blue), operation colors - **indent-blankline**: Subtle grays for guides and scope - **nvim-ufo**: Subtle backgrounds for folds with preview support - 2025-12-11: Colorscheme Phase 11.9: - **Plugin configuration updated**: `lua/plugins/colorscheme.lua` loads `paper-tonic-modern` - **Cleanup**: Moved old `paper-tonic/` directory to `legacy/paper-tonic-original/` - **Validation**: Full config reload tested - all highlight groups load correctly - **Colorscheme integration**: Native Neovim colorscheme at `colors/paper-tonic-modern.lua` - **No overrides needed**: Modern implementation doesn't require separate override file ## 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 buffer’s 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.