nvim/README.md

18 KiB
Raw Permalink 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
  • 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 <leader>lt
    • Manual format: <leader>lf (buffer), <leader>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 <leader>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 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.