18 KiB
18 KiB
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
listcharsandshowbreakvalues (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.jsonwith.nvimrootas workspace boundary marker (multi-repo friendly). - 2025-12-06: Switch to
folke/neoconf.nvimfor project-local configuration (supersedes custom layered JSON loader); use.neoconf.jsonat workspace root. - 2025-12-06: Use
mason.nvim+mason-lspconfig.nvimto install/manage LSP servers; keep custom lspconfig setup; include.neoconf.jsonin root detection.- For PHP validation inside this repo: we require
.neoconf.jsonto attachintelephenseto avoid the repo’s.gitbeing chosen as the LSP root.
- For PHP validation inside this repo: we require
- 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_configcallback invim.lsp.config(). Project-local settings (.nvim.lua) must be loaded viaLspAttachautocmd instead. Theon_new_confighook was silently ignored, causing empty settings and breaking goto-definition for external includes. Solution: UseLspAttachto load project settings, merge intoclient.settings, and sendworkspace/didChangeConfigurationnotification. - 2025-12-07: Native
exrc+.nvim.luafinalized as project-local config approach (replaces neoconf, which is incompatible with Neovim 0.11+ native LSP API). Security viavim.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
gfenhancement viaincludeexprfor 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/[ffor next/prev function,]c/[cfor classes,]a/[afor parameters - Parameter swapping:
<leader>a/<leader>Ato 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/[hfor 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 dedicatedlua/abbreviations.luafile for modularity - Templates: Shell script template (template.sh) auto-loaded via BufNewFile autocmd for
*.shfiles - Whitespace highlighting: Already handled via
listcharsin Phase 3.2 (settings.lua) - Persistent folds: Not needed; UFO handles folding without explicit persistence mechanism
- Abbreviations: Common typo corrections (
- 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.luawith 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.luaproperly resets and loads colorscheme - Main module:
lua/paper-tonic-modern/init.luawith 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>hikeymap to show highlight group and resolved colors under cursor - Validation: All TreeSitter groups tested and verified with correct palette colors
- TreeSitter highlights: Comprehensive modern
- 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
;extendsdirective 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.lualoadspaper-tonic-modern - Cleanup: Moved old
paper-tonic/directory tolegacy/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
- Plugin configuration updated:
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:
.nvimrootto 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.nvimwith.neoconf.jsonat the workspace root (or project roots) to supply LSP/plugin settings. Multi-repo: keep a single.neoconf.jsonat 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:
- Start at the buffer’s directory; ascend toward root.
- Stop at directory containing
.nvimroot(if found) or at filesystem root. - At each level, if
.nvim.jsonor.nvim.local.jsonexists, parse and stage for merge. - Merge staged configs in ascending order; nearest directory applies last.
- Path resolution:
- Relative paths resolve against the topmost boundary (i.e.,
.nvimrootdirectory 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.
- Relative paths resolve against the topmost boundary (i.e.,
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.luawill expose:load(start_dir) -> tablecollecting and merging configsget(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.includePathsinlspconfig.intelephense.setup{}.
- Read includePaths via the helper and pass to
Open items to confirm
- Confirm JSON as the format (vs Lua) for project-local config.
- Confirm
.nvimrootas 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_gblistcharsandshowbreakwill reuse legacy values.completeopt = menu,menuone,noselectfornvim-cmp.
Process Reminders
- After any change or decision, update this README and MIGRATION_PLAN.md.
- Keep subphases small and verify each step in isolation.