Complete config migration cleanup

Retire legacy files and migration fixtures, move runtime state out of the repository, and migrate Tree-sitter and textobjects to their Neovim 0.12-compatible main branches.
This commit is contained in:
Ray Elliott 2026-10-28 19:26:42 +00:00
commit f8f478a985
99 changed files with 288 additions and 5473 deletions

View file

@ -6,8 +6,7 @@ This file exists to satisfy GitHub Copilot's convention of looking for instructi
## Quick Reference
- **Primary instructions**: See `/home/ray/.config/nvim/AGENTS.md`
- **Migration plan**: See `MIGRATION_PLAN.md`
- **Primary instructions**: See `AGENTS.md`
- **Decision log**: See `LOG.md`
- **Keymap reference**: See `README.md`
@ -15,9 +14,8 @@ This file exists to satisfy GitHub Copilot's convention of looking for instructi
1. **Read `AGENTS.md` first** - it contains all coding rules, architecture decisions, and what NOT to reintroduce
2. **Update docs after changes**:
- Config changes → update `MIGRATION_PLAN.md`
- Decisions → update `LOG.md`
- Keymap changes → update `README.md`
- User-facing behavior and keymaps → update `README.md`
3. **Modern Lua-first**: Use `vim.opt`, `vim.keymap.set`, `vim.api` - avoid Vimscript
4. **LSP (Neovim 0.11+)**: Use `vim.lsp.config()` + `vim.lsp.enable()`, NOT lspconfig `.setup()`
5. **Project config**: Native `exrc` + `secure`, no neoconf plugin

11
.gitignore vendored
View file

@ -1,11 +1,2 @@
bundle/
autoload/
undodir/*
.vimtmp/*
legacy/.vimtmp/
.nvimlog
view/*
tmpdir
WORKSPACE_TEST/
EXTERNAL_TEST/
WORKSPACE_SIMPLE/
Session.vim

255
AGENTS.md
View file

@ -1,213 +1,70 @@
# AGENTS: Neovim Config Migration
# AGENTS: Neovim Configuration
Scope: applies to the entire `~/.config/nvim` directory tree.
Scope: the entire `~/.config/nvim` repository.
This repository is being migrated to a modern, minimal Neovim setup driven by Lua and lazy.nvim. Follow these rules when making changes.
## Current setup
## 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 tree browsing, previews, and file operations, LSP, native completion, Treesitter, Copilot, and sane UX defaults.
- Native project-local configuration via `exrc` + `secure` (no external config plugins).
This is the active, daily-use Neovim 0.12 configuration. It is Lua-first,
managed with lazy.nvim, and intended to remain small, fast, and maintainable.
## 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).
The main workflows are:
## 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
├── completion.lua -- native insert-mode and LSP completion
├── netrw-config.lua -- netrw configuration
├── netrw-preview.lua -- live file previews and directory summaries
├── utils.lua -- helpers (only if needed)
└── plugins/ -- one file per plugin or domain
├── telescope.lua
├── treesitter.lua
├── lsp.lua
├── copilot.lua
├── ufo.lua
├── gitsigns.lua
├── conform.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)
```
- netrw for tree browsing, previews, and file operations
- Telescope for fuzzy files, grep, buffers, and symbols
- native `vim.lsp.config()` / `vim.lsp.enable()` configuration
- native insert-mode completion and snippets
- Copilot inline suggestions, separate from the completion menu
- Tree-sitter, Conform, nvim-lint, Gitsigns, and nvim-ufo
- native `nvim.undotree`
- project-local `.nvim.lua` files through native `exrc` + `secure`
## 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.
`README.md` documents the user-facing workflows and keymaps. `LOG.md` records
architectural decisions.
## 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).
## Maintenance rules
## Required Plugin Categories
- Core: `nvim-lspconfig`; use Neovim 0.12 native insert-mode/LSP completion and snippets instead of the nvim-cmp stack.
- Navigation: `telescope.nvim` + `telescope-fzf-native.nvim`; netrw is the sole file explorer.
- Treesitter: `nvim-treesitter`, `nvim-treesitter-textobjects`, `nvim-ts-autotag`.
- UX/Editing: `Comment.nvim`, `nvim-surround`, `nvim-autopairs`, `indent-blankline.nvim`, `nvim-ufo`; use Neovim 0.12's native optional `nvim.undotree` package.
- Git: `gitsigns.nvim`.
- Copilot: `copilot.lua` with inline suggestions; do not integrate Copilot into the native completion popup.
- Formatting/Linting: `conform.nvim`, `nvim-lint`.
- LSP Management: `mason.nvim`, `mason-lspconfig.nvim`, `mason-tool-installer.nvim`.
- Prefer Lua APIs such as `vim.opt`, `vim.keymap.set`, and
`vim.api.nvim_create_autocmd`; use Vimscript only when a native integration
requires it.
- Keep non-plugin behavior in focused modules under `lua/`.
- Keep each plugin specification self-contained under `lua/plugins/`.
- Continue using lazy.nvim; do not mix plugin managers without an explicit
decision to migrate.
- Do not add a plugin without explicit user confirmation.
- Keep netrw as the sole file explorer and Telescope as the fuzzy navigator.
- Use Neovim's native completion rather than reintroducing nvim-cmp or LuaSnip.
- Keep Copilot as inline suggestions rather than a completion-menu source.
- Use the modern LSP API; do not restore legacy `lspconfig.setup()` calls or
neoconf.
- Preserve native project-local configuration through `exrc` + `secure`.
- Keep providers for Ruby, Perl, and Node disabled unless an active plugin
requires one.
- Preserve the existing Lua tabline, but do not restore the old Vimscript
tabline/statusline, foldtext, cursorline/column window hacks, CoC, Neo-tree,
motion plugins, or Markdown rendering plugins unless the user explicitly
revisits those decisions.
- Preserve unrelated user changes and keep patches narrowly scoped.
## 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).
- Netrw for file manipulation as well as browsing, preserving the same workflow on remote systems.
- 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.
## Documentation and validation
## 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).
- Update `README.md` whenever user-facing behavior or keymaps change.
- Update its configuration section when formatter, linter, or tool resolution
changes.
- Record significant architectural decisions in `LOG.md`.
- After configuration or plugin changes, run at least:
## Current Status (Phase 14 In Progress)
- ✅ Phase 1-2: Archive legacy, bootstrap lazy.nvim
- ✅ Phase 3: Core editing & LSP (native exrc + vim.lsp.config migration complete)
- ✅ Phase 4: Navigation (Telescope and netrw)
- ✅ Phase 5: Treesitter (parsers, textobjects, autotag)
- ✅ Phase 6: UX/Editing (Comment, surround, autopairs, indent guides, UFO, native Undotree)
- ✅ Phase 7: Git integration (Gitsigns)
- ✅ Phase 8: Copilot integration (copilot.lua inline suggestions)
- ✅ Phase 9: Formatting & Linting (conform.nvim, nvim-lint, Mason tool installer)
- ✅ Phase 10: Migrate kept behaviors (abbreviations, templates, custom Treesitter queries)
- ✅ Phase 11: Modern Paper Tonic colorscheme
- ⏳ Phase 12: Cleanup and validation (repository cleanup and automated checks complete; interactive workflow checks remain)
- ✅ Phase 13: Neovim 0.12.6 activated and native editing workflows validated
- ✅ Phase 13.9: Native Undotree and completion consolidation complete
- ⏳ Phase 14: Netrw live previews and directory summaries implemented; interactive validation remains
```bash
nvim --headless -c 'lua print("Config loads")' -c 'quitall'
```
## 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.
- For relevant changes, also exercise the affected workflow interactively.
## Validation
- Ensure Neovim starts without errors and with minimal startup time.
- Verify Telescope navigation, netrw browsing and file operations, LSP basics, and completion.
- Keep plugin count tight; remove anything unused.
## History
## 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**: `LspAttach` securely reads `.nvim.lua` from the client's 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)
- **netrw**: Sole file explorer for tree browsing, previews, and file operations
- **PHP gf enhancement**: Custom `includeexpr` in `after/ftplugin/php.lua` for WordPress/PHP patterns
### Formatting & Linting
- **Formatters**: prettier, phpcbf, stylua, ruff_format (project-local → Mason → global)
- **Linters**: eslint_d, phpcs, markdownlint, plus Ruff through LSP
- **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
```bash
# 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.
This configuration began as a large Vimscript setup with bundled plugins and
was incrementally rebuilt as a modern Lua configuration. The migration covered
lazy.nvim, native LSP and project configuration, native completion and
Undotree, Telescope, a netrw-centered explorer workflow, Tree-sitter, Copilot,
formatting, linting, and the Paper Tonic colorscheme. After sustained daily use
on Neovim 0.12.6, the migration was declared complete on 2026-10-28. The
decision history remains in `LOG.md` and Git history.

View file

@ -1,72 +0,0 @@
# Migration Plan: none-ls → conform.nvim
**Date:** 2026-01-12
**Status:** ✅ **COMPLETED**
**Reason:** none-ls's phpcbf formatter is buggy (adds blank lines). conform.nvim is more modern, doesn't use LSP overhead, better maintained.
## Current State
**Formatting (conform.nvim):**
- ✅ prettier (JS/TS/CSS/JSON/HTML/Markdown)
- ✅ stylua (Lua)
- ✅ phpcbf (PHP) with WordPress standard
**Linting (nvim-lint):**
- phpcs, eslint_d, markdownlint
**LSP (lspconfig):**
- Language features (autocomplete, goto-def, hover, etc.)
## Migration Checklist
### Phase 1: Setup conform.nvim
- [x] Create `lua/plugins/conform.lua`
- [x] Configure formatters:
- [x] prettier (JS/TS/CSS/JSON/HTML/Markdown)
- [x] stylua (Lua)
- [x] phpcbf (PHP) with WordPress standard support
- [x] Configure format-on-save behavior
- [x] Set up project-local executable resolution (vendor/bin, node_modules/.bin, Mason, global)
- [x] Add keymaps for manual formatting (`<leader>lf`, `<leader>lt`)
### Phase 2: Remove none-ls
- [x] Delete `lua/plugins/none-ls.lua`
- [x] Remove none-ls from lazy-lock.json (happens automatically on `:Lazy sync`)
- [x] Remove the custom phpcbf autocmd workaround (no longer needed)
### Phase 3: Testing
- [x] Test prettier formatting (JS/TS/CSS files)
- [x] Test stylua formatting (Lua files)
- [x] Test phpcbf formatting (PHP files) - **verified NO blank lines added**
- [x] Test format-on-save toggle (`<leader>lt`)
- [x] Test manual format (`<leader>lf`)
- [x] Test project-local formatter detection
- [x] Verify phpcs.xml is respected when present
### Phase 4: Documentation
- [x] Update README.md Configuration section
- [x] Update AGENTS.md Process section (plugin list, formatting tools)
- [x] Update MIGRATION_PLAN.md status (Phase 9.2)
- [x] Update LOG.md with decision and rationale
## Expected Benefits
1. **No more blank line bug** - conform calls phpcbf cleanly without none-ls's buggy preprocessing
2. **No LSP overhead** - formatters run as simple shell commands
3. **Better maintained** - conform.nvim is actively developed
4. **Cleaner architecture** - clear separation: LSP (features), nvim-lint (diagnostics), conform (formatting)
5. **Easier debugging** - simpler execution path, better error messages
## Rollback Plan
If conform.nvim has issues:
1. Restore `lua/plugins/none-ls.lua` from git
2. Keep the custom phpcbf autocmd for PHP
3. Run `:Lazy sync` to reinstall none-ls
## Notes
- conform.nvim has built-in support for all our formatters (prettier, stylua, phpcbf)
- It handles executable resolution similarly to our `find_executable()` helper
- Format-on-save can be toggled per-buffer or globally
- Visual range formatting supported out of the box

18
LOG.md
View file

@ -1,9 +1,9 @@
# Neovim Rebuild — Decisions & Reference
Authoritative notes for the Neovim migration. Use this alongside `MIGRATION_PLAN.md` and `neovim-migration-guide.md`.
Historical migration record and ongoing architectural decision log.
- Migration plan: MIGRATION_PLAN.md
- Guide and requirements: neovim-migration-guide.md
- Maintenance instructions: `AGENTS.md`
- Active workflows and keymap reference: `README.md` and `:KeymapsGuide`
## Decisions Log
@ -222,6 +222,10 @@ Record every decision here with a short rationale. Append new entries; do not re
- 2026-10-28: Hardened preview scrolling after an interactive over-scroll surfaced a window-local error that did not reproduce headlessly. The temporary preview-window call is now protected, so stale-window and boundary failures are treated like native top/bottom clamping instead of reaching the command line.
- 2026-10-28: Excluded netrw from automatic session persistence after `:mksession` serialized its generated `NetrwTreeListing` name and restored an empty explorer buffer. Before the existing exit-time save, preview windows and netrw windows are removed; a netrw-only tab is dropped, while the sole remaining netrw window is replaced with an ordinary file buffer or a blank fallback. Netrw is intentionally not rebuilt on load.
- 2026-10-28: Changed the enhanced netrw `p` mapping into a true toggle. With no preview it opens the selected file or directory and begins live cursor updates; with an existing preview it closes that window and stops updates, matching manual `:pclose` behavior.
- 2026-10-28: Declared the migration complete after sustained daily use of the modern Lua configuration. Interactive navigation, language tooling, native completion, Copilot, formatting, linting, and the enhanced netrw workflow are considered validated. Real SSH URI previews and use of stock netrw without this configuration remain optional portability checks, not release gates. This decision also ends the requirement to retain migration-only archives and fixtures in the live repository; their removal will be handled as a separate, explicit cleanup.
- 2026-10-28: Replaced the migration-era `AGENTS.md` with a concise maintenance guide for the established configuration. Removed completed phase tracking, obsolete validation-workspace instructions, resolved issue notes, and the target-tree description; retained current architectural guardrails, documentation expectations, a smoke-test command, and a short history note.
- 2026-10-28: Retired the completed migration's legacy configuration, vendored plugin archive, UltiSnips collection, validation workspaces, root test assets, superseded planning documents, and phase labels in active Lua comments. Git history now provides the historical archive. Persistent undo storage moved from the configuration repository to `stdpath('state')/undo`; the active README, architectural log, lockfile, colorscheme, spell data, and templates remain.
- 2026-10-28: Diagnosed the Tree-sitter `TSNode:range()` failure as the known incompatibility between Neovim 0.12 and nvim-treesitter's locked legacy `master` branch. Migrated nvim-treesitter and nvim-treesitter-textobjects to their rewritten `main` branches: native Neovim highlighting and incremental selection replace the old modules, textobjects use explicit mappings, indentation uses the new plugin expression when a query exists, and autotag retains its direct supported setup. Installed the verified official Tree-sitter CLI 0.26.9 binary in `~/.local/bin` after the system package required interactive sudo and Cargo compilation required unavailable libclang. Reinstalled all configured parsers in the new site directory and removed obsolete generated parser copies from the plugin checkout. The plugin audit confirmed every plugin is current for its configured branch or release constraint; nvim-surround remains on the latest release rather than its newer unreleased `main` commit.
## Project-Local Configuration
@ -263,7 +267,9 @@ Neoconf and the earlier layered JSON proposal were rejected. They remain in the
- `listchars` and `showbreak` will reuse legacy values.
- `autocomplete` with `completeopt = menu,menuone,noselect,popup,fuzzy` for Neovim 0.12 native completion.
## Process Reminders
## Maintenance Reminders
- After any change or decision, update this README and MIGRATION_PLAN.md.
- Keep subphases small and verify each step in isolation.
- Follow `AGENTS.md` for current maintenance rules.
- Update `README.md` when user-facing behavior changes.
- Record significant architectural decisions in this log.
- Keep changes focused and verify affected workflows.

View file

@ -1,702 +0,0 @@
# Neovim Migration Checklist
Source of truth for the step-by-step rebuild. Keep this concise and up to date. See details in `neovim-migration-guide.md`.
## Phase 0 — Ground Rules
- [x] Create AGENTS.md with rules
## Phase 1 — Clean & Archive Legacy Config
## Phase 1.1 — Confirm scope and priorities
- [x] Confirm scope and priorities for this phase
## Phase 1.2 — Inventory legacy files
- [x] Inventory existing Vimscript, plugin files, and directories
## Phase 1.3 — Create archive location
- [x] Create `legacy/` archive folder within this config
## Phase 1.4 — Move legacy files into archive
- [x] Move legacy init files and plugin directories into `legacy/` (do not delete)
## Phase 1.5 — Document archived contents
- [x] Optionally add `legacy/README.md` noting what was archived
## Phase 1.6 — Preserve selected directories
- [x] Keep `undodir`, `spell`, `view`, `UltiSnips`, `templates` as-is for now (review later)
- [x] Re-enabled persistent undo in settings.lua (2025-01-06)
## Phase 2 — Bootstrap
## Phase 2.1 — Confirm scope and priorities
- [x] Confirm scope and priorities for this phase
## Phase 2.2 — Scaffold Lua config skeleton
- [x] Scaffold Lua config skeleton (`init.lua`, `lua/settings.lua`, `lua/keymaps.lua`, `lua/autocmds.lua`, `lua/utils.lua`, `lua/plugins/`)
## Phase 2.3 — Bootstrap lazy.nvim
- [x] Bootstrap `lazy.nvim` plugin manager
## Phase 2.4 — Disable unused providers
- [x] Disable unused providers (ruby, perl, node)
## Phase 2.5 — Ensure lazy boots without specs
- [x] Ensure lazy boots without specs (add empty `lua/plugins/init.lua`)
## Phase 3 — Core Editing & LSP
## Phase 3.1 — Confirm scope and priorities
- [x] Confirm scope and priorities for this phase
- [x] Decision: PHP LSP = `intelephense`
- [x] Decision: Enable Markdown LSP = `marksman`
- [x] Decision: Use legacy `listchars` and `showbreak` values
- [x] Decision: Support per‑project config for `intelephense.includePaths`
- [x] Decision: No direnv fallback for local config
## Phase 3.2 — Non-plugin settings to Lua
- [x] Port non-plugin settings to Lua (options, listchars, showbreak, spelllang=en_gb)
## Phase 3.3 — Core completion stack
- [x] Add core completion stack: `nvim-cmp`, `cmp-nvim-lsp`, `cmp-buffer`, `cmp-path`, `LuaSnip`
- [x] Disable auto-selection in nvim-cmp (require explicit confirm)
## Phase 3.4 — Project‑local configuration (native exrc)
- [x] Confirm scope and priorities for this subphase
- [x] Decision: Use native `exrc` + `secure` instead of neoconf (neoconf incompatible with Neovim 0.11+ vim.lsp.config API)
- [x] Enable `exrc` and `secure` in settings.lua
- [x] Implement `.nvim.lua` loader in an `LspAttach` callback using the client's actual root directory
- [x] Wire `intelephense.environment.includePaths` via `.nvim.lua`
- [x] Create validation workspaces: `WORKSPACE_TEST/` and `EXTERNAL_TEST/` with sample PHP files
- [x] Migrate to `vim.lsp.config()` and `vim.lsp.enable()` (Neovim 0.11+ native API)
- [x] Verify project settings load correctly from actual root_dir
- [x] Clean up debug notifications and temporary code
## Phase 3.7 — Clean LSP config
- [x] Remove debug/helper logic from LSP config
- [x] Migrate from deprecated `require('lspconfig')[server].setup()` to `vim.lsp.config()` + `vim.lsp.enable()`
- [x] Use `LspAttach` for project-local settings loading (loads from actual root_dir, not cwd)
## Phase 3.8 — Validate project-local LSP settings
- [x] Create test workspaces with `.nvim.lua` files
- [x] Validate settings load from the attached client's actual root_dir
- [x] Verify `gd` works for external library references via `intelephense.environment.includePaths`
- [x] Clean up debug code and notifications
## Phase 3.9 — Native exrc + vim.lsp.config migration (RESOLVED)
- [x] Discovered neoconf incompatible with Neovim 0.11+ (GitHub issue #116, unresolved since May 2024)
- [x] Migrated to native `exrc` + `secure` approach (zero dependencies, aligned with minimal philosophy)
- [x] Implemented secure `.nvim.lua` loading during `LspAttach` (loads from actual root_dir)
- [x] Migrated from deprecated `require('lspconfig')` framework to `vim.lsp.config()` + `vim.lsp.enable()`
- [x] Root detection handled by nvim-lspconfig's native configs (no custom root_dir needed)
- [x] Validated `gd` works for external library symbols via `intelephense.environment.includePaths`
- [x] Settings schema: `.nvim.lua` returns `{ lsp = { [server_name] = { settings = {...} } } }`
- [x] Security: `secure` mode prompts user to trust `.nvim.lua` files before execution
- [x] Kept `single_file_support = false` for `intelephense`
- [x] Fixed duplicate `gd` results issue
## Phase 3.5 — LSP minimal defaults
- [x] Add `nvim-lspconfig` with minimal defaults (no over-configuration)
- [x] Add minimal LSP on-attach keymaps (gd, gr, K, gD, gI)
- [x] Add global LSP keymaps with fallback in `lua/keymaps.lua`
- [x] Intelephense: set `single_file_support=false`, root detection via nvim-lspconfig defaults
- [x] Project settings securely loaded during `LspAttach` from `.nvim.lua` files
## Phase 3.6 — LSP server management (Mason)
- [x] Confirm scope and priorities for this subphase
- [x] Add `williamboman/mason.nvim` and `williamboman/mason-lspconfig.nvim`
- [x] Ensure servers installed: `lua_ls`, `tsserver`, `html`, `cssls`, `jsonls`, `bashls`, `marksman`, `intelephense`
- [x] Keep our custom per-server setup; use Mason only for installation
## Phase 4 — Navigation
## Phase 4.1 — Confirm scope and priorities
- [x] Confirm scope and priorities for this phase
- [x] Decision: Skip Neo-tree in favor of netrw for navigation/visual context
- [x] Decision: Use netrw for project structure visualization and file preview
- [x] Decision: Telescope as primary "find file" tool
- [x] Decision: Evaluate Oil.nvim for file manipulation (later removed in Phase 4.5)
## Phase 4.2 — Configure netrw
- [x] Configure netrw with tree view, preview split, and basic settings (no banner, sensible defaults)
- [x] Created `lua/netrw-config.lua` with settings: tree view, horizontal preview split below, 50/50 split, human-readable sizes
- [x] Add netrw keymaps: `<leader>te` (new tab at current file's directory), `<leader>tE` (new tab at project root)
- [x] Decision: No `<leader>e` or `<leader>v` keymaps - use `:Ex`, `:Vex` directly when needed
- [x] Preview behavior: Enter opens file in netrw window, `p` opens 50/50 horizontal split below
## Phase 4.2.1 — PHP gf enhancement
- [x] Add PHP `includeexpr` for intelligent `gf` behavior (handles `__DIR__`, `__FILE__`, `dirname(__FILE__)` patterns)
- [x] Created `after/ftplugin/php.lua` with path resolution for WordPress/PHP patterns
- [x] Tested and validated with test-gf.php
## Phase 4.3 — Telescope setup
- [x] Add `telescope.nvim` + `telescope-fzf-native.nvim` for fuzzy finding
- [x] Configure basic pickers: `find_files`, `live_grep`, `buffers`, `help_tags`, `oldfiles`, `current_buffer_fuzzy_find`
- [x] Add LSP pickers: `lsp_document_symbols`, `lsp_workspace_symbols`
- [x] Keymaps configured:
- `<leader>ff` - Find files
- `<leader>fg` - Live grep (search text)
- `<leader>fb` - Find buffers (with `<C-d>` to delete)
- `<leader>fh` - Find help
- `<leader>fr` - Recent files
- `<leader>/` - Search current buffer
- `<leader>fs` - Document symbols (LSP)
- `<leader>fS` - Workspace symbols (LSP)
- [x] Minimal UI: dropdown theme for files/buffers, no previewer for quick selection
## Phase 4.4 — Oil.nvim evaluation (retired)
- [x] Add `stevearc/oil.nvim` for filesystem operations (rename, create, delete, copy, move)
- [x] Configure to handle buffer name sync on file operations
- [x] Keep minimal - use only when shell operations would cause buffer issues
- [x] Keymaps configured:
- `<leader>fo` - Open Oil file browser (regular buffer)
- `<leader>fO` - Open Oil in floating window (with floating previews)
- `<C-p>` in Oil - Preview files (vertical split to right for regular, floating window for float mode)
- [x] Preview splits open to the right via `vertical = true` and `split = 'belowright'`
- [x] Floating window preview direction: `preview_split = "right"`
- [x] Note: Evaluate practicality; can switch to `mini.files` if preferred
## Phase 4.5 — Return to a netrw-only explorer workflow
- [x] Remove Oil.nvim after workflow evaluation
- [x] Use netrw as the sole tree browser and file explorer for consistency on remote systems
- [x] Keep Telescope as a fuzzy finder rather than a file explorer
## Phase 5 — Treesitter
## Phase 5.1 — Confirm scope and priorities
- [x] Confirm scope and priorities for this phase
- [x] Decision: Focus on languages: PHP, HTML, JavaScript, TypeScript, CSS, Markdown, Lua, Bash, JSON
- [x] Decision: Enable syntax highlighting and incremental selection (CR to expand, BS to shrink)
- [x] Decision: Enable textobjects for functions, classes, parameters, conditionals, loops
- [x] Decision: Enable autotag for HTML/PHP/JS/React files
- [x] Decision: Disable indent (experimental) to start; can enable per-filetype if stable
## Phase 5.2 — Base Treesitter
- [x] Add `nvim-treesitter` with incremental selection, highlighting
- [x] Configure parsers: lua, vim, vimdoc, php, html, javascript, typescript, tsx, css, scss, json, markdown, markdown_inline, bash, regex
- [x] Enable auto-install for missing parsers
- [x] Incremental selection keymaps: CR (init/expand), S-CR (scope expand), BS (shrink)
- [x] Disable for large files (>100KB) to maintain performance
## Phase 5.3 — Treesitter textobjects
- [x] Add `nvim-treesitter-textobjects`
- [x] Select keymaps: `af`/`if` (function), `ac`/`ic` (class), `aa`/`ia` (parameter), `ai`/`ii` (conditional), `al`/`il` (loop), `a/` (comment)
- [x] Move keymaps: `]f`/`[f` (next/prev function start), `]F`/`[F` (function end), similar for classes and parameters
- [x] Swap keymaps: `<leader>a`/`<leader>A` (swap parameter with next/prev)
## Phase 5.4 — Treesitter autotag
- [x] Add `nvim-ts-autotag`
- [x] Enable auto-close, auto-rename, and close-on-slash for HTML/PHP/JS/React/TS/Vue files
## Phase 6 — UX / Editing
## Phase 6.1 — Confirm scope and priorities
- [x] Confirm scope and priorities for this phase
- [x] Decision: No cursorcolumn (as per AGENTS.md)
- [x] Decision: No auto-window toggling behavior (keep settings static)
- [x] Decision: No motion plugin (skip leap/flash)
- [x] Decision: Move undotree to separate Phase 6.8
- [x] UX settings to add: signcolumn, cursorline, colorcolumn
## Phase 6.2 — Core UX settings
- [x] Add signcolumn=yes (always show gutter for LSP/git)
- [x] Add cursorline (highlight current line)
- [x] Add colorcolumn=80,120 (visual guides)
- [x] No cursorcolumn (excluded as per AGENTS.md)
- [x] No per-window autocommands (keep simple)
## Phase 6.3 — Comment.nvim
- [x] Add `numToStr/Comment.nvim`
- [x] Configure for gcc/gc commenting
- [x] Add keymaps if needed
## Phase 6.4 — Surround
- [x] Add `kylechui/nvim-surround`
- [x] Minimal config with default keymaps (ys, ds, cs)
## Phase 6.5 — Autopairs
- [x] Add `windwp/nvim-autopairs`
- [x] Integrate with nvim-cmp
## Phase 6.6 — Indent guides
- [x] Add `lukas-reineke/indent-blankline.nvim`
- [x] Configure scope highlighting
## Phase 6.7 — Folding (UFO)
- [x] Add `kevinhwang91/nvim-ufo` for folding
- [x] Configure with Treesitter and LSP providers
- [x] Add fold keymaps (za, zR, zM, etc.)
## Phase 6.8 — Undotree
- [x] Add `mbbill/undotree`
- [x] Add keymap to toggle undotree
- [x] Configure minimal settings
## Phase 7 — Git Integration
## Phase 7.1 — Confirm scope and priorities
- [x] Confirm scope and priorities for this phase
- [x] Decision: Gitsigns with minimal config - signs in gutter, hunk navigation/actions only
- [x] Decision: Skip markdown rendering plugins entirely
## Phase 7.2 — Gitsigns
- [x] Add `lewis6991/gitsigns.nvim`
- [x] Configure signs in gutter (add, change, delete, topdelete, changedelete)
- [x] Add hunk navigation keymaps (]h/[h for next/prev hunk)
- [x] Add hunk action keymaps (stage, reset, preview)
- [x] Keep minimal - no inline blame, no advanced features
## Phase 8 — Copilot
## Phase 8.1 — Confirm scope and priorities
- [x] Confirm scope and priorities for this phase
- [x] Decision: Integrate Copilot into nvim-cmp as completion source
- [x] Decision: Auto-trigger suggestions as you type
- [x] Decision: No specific Copilot keymaps needed (use existing cmp keymaps)
- [x] Decision: Enable for all filetypes
- [x] Decision: Copilot suggestions appear before LSP suggestions in completion menu
- [x] Node.js v22.21.1 upgraded and confirmed working
## Phase 8.2 — Copilot setup
- [x] Add `zbirenbaum/copilot.lua` + `zbirenbaum/copilot-cmp`
- [x] Configure copilot.lua with auto-trigger and all filetypes
- [x] Add copilot-cmp as source to nvim-cmp
- [x] Set copilot-cmp priority higher than LSP in completion menu
- [x] Note: Copilot initializes on first InsertEnter; enter/exit insert mode once before using `:Copilot auth`
## Phase 9 — Formatting & Linting
## Phase 9.1 — Confirm scope and priorities
- [x] Confirm scope and priorities for this phase
- [x] Decision: Formatters - prettier (JS/TS/CSS/JSON/MD/HTML), phpcbf (PHP), stylua (Lua), ruff_format via conform (Python; supersedes the original black plan)
- [x] Decision: Linters - eslint (JS/TS), phpcs (PHP), markdownlint (Markdown), ruff (Python)
- [x] Decision: Project-local executables preferred, fallback to global (node_modules/.bin/, vendor/bin/)
- [x] Decision: phpcs/phpcbf already installed globally with WordPress coding standards - no installation needed
- [x] Decision: Format-on-save enabled by default with toggle capability
- [x] Decision: Manual format keymaps: `<leader>lf` (normal), `<leader>lf` (visual range)
- [x] Decision: Respect project config files (.prettierrc, phpcs.xml, .eslintrc, pyproject.toml, etc.)
- [x] Strategy: Helper function detects project-local executables first, then global
- [x] WordPress: phpcs.xml in project root or --standard=WordPress flag for WordPress projects
- [x] Philosophy: Formatters are authoritative source of truth; Neovim settings should match formatter rules per filetype
- [x] Note: Phase 9.4 will align Neovim editor settings (tabstop, shiftwidth, expandtab) with formatter configurations
## Phase 9.2 — conform.nvim setup with project-aware executables
- [x] Add `stevearc/conform.nvim` (replaced none-ls due to phpcbf preprocessing bug)
- [x] Configure formatters (conform has built-in support for all):
- [x] prettier (auto-detects project-local, Mason, global)
- [x] phpcbf (auto-detects project-local, global; customized for WordPress standard)
- [x] stylua (auto-detects project-local, Mason, global)
- [x] Add `mfussenegger/nvim-lint` for linting (separate from formatting)
- [x] Configure linters via nvim-lint:
- [x] eslint_d (project-local first, then Mason, then global - daemon version for speed)
- [x] phpcs (project-local first, then global system install - already available)
- [x] markdownlint (Mason installed)
- [x] Add format-on-save autocommand with toggle capability (`<leader>lt` to toggle)
- [x] Add manual format keymaps: `<leader>lf` (buffer), `<leader>lf` (visual range)
- [x] Ensure WordPress coding standards work via phpcs.xml or --standard flag
- [x] Search order handled by conform.nvim automatically: project → Mason → system PATH
- [x] Note: Linting runs on BufEnter, BufWritePost, InsertLeave events
- [x] Removed none-ls.lua (bug caused blank lines in PHP formatting)
## Phase 9.3 — Mason formatter/linter installation
- [x] Add `WhoIsSethDaniel/mason-tool-installer.nvim` for automated installation
- [x] Install via Mason: prettier, eslint_d, markdownlint, stylua, and ruff
- [x] Note: phpcs/phpcbf already installed globally, skip Mason installation
- [x] Verify all tools available: Tools installed to ~/.local/share/nvim/mason/bin/
## Phase 9.4 — Align Neovim settings with formatter rules
- [x] Configure per-filetype settings to match formatter defaults
- [x] PHP: tabs, 2-width display (WordPress standards)
- [x] JS/TS/CSS/JSON/HTML: spaces, 2-width (Prettier defaults)
- [x] Lua: spaces, 2-width (common Neovim convention)
- [x] Markdown: spaces, 2-width (Prettier defaults)
- [x] Python: spaces, 4-width (Black/PEP 8 defaults)
- [x] Use autocmds in lua/autocmds.lua for filetype-specific tabstop, shiftwidth, expandtab
- [x] Set global defaults: 4-width, spaces (reasonable baseline)
- [x] Goal: Manual editing feels natural and matches what formatter will produce on save
- [x] Note: All settings kept explicit per-filetype for clarity and maintainability
## Phase 10 — Migrate Kept Behaviours
## Phase 10.1 — Confirm scope and priorities
- [x] Confirm scope and priorities for this phase
- [x] Decision: Port abbreviations to Lua via vim.cmd.iabbrev
- [x] Decision: Port shell template auto-loading via autocmd + BufReadPost
- [x] Decision: Whitespace highlighting already handled via listchars (Phase 3.2)
- [x] Decision: Skip persistent folds (UFO handles folding, no explicit persistence needed)
## Phase 10.2 — Abbreviations
- [x] Abbreviations: `adn→and`, `waht→what`, `tehn→then`, `functin→function`, `positin→position`
- [x] Created dedicated `lua/abbreviations.lua` for modularity and easier maintenance
## Phase 10.3 — Templates
- [x] Templates: auto-populate new `.sh` from template
- [x] Added BufNewFile autocmd for *.sh in lua/autocmds.lua
## Phase 10.4 — Whitespace highlighting
- [x] Whitespace highlighting (modern approach)
- [x] Note: Already handled via listchars in Phase 3.2 (settings.lua)
## Phase 10.5 — Persistent folds
- [x] Persistent folds (via UFO) -- no need, this is no longer required.
- [x] Note: UFO handles folding; no explicit persistence mechanism needed
## Phase 10.6 — Custom tabline function
- [x] Implement custom tabline with configurable path shortening (`lua/utils.lua`)
- [x] Configure tabline in `lua/settings.lua` with `utils.tabline_full_parents`
- [x] Document tabline configuration in `README.md`
- [x] Show N parent directories in full, shorten earlier paths to first letter
## Phase 11 — Colorscheme: Modern Paper Tonic
## Phase 11.1 — Confirm scope and priorities
- [x] Confirm scope and priorities for this phase
- [x] Decision: Create modern Paper Tonic fork from scratch
- [x] Decision: Name = "paper-tonic-modern"
- [x] Decision: Location = inside nvim config initially, move to repo later
- [x] Decision: Structure = modular Lua colorscheme (colors.lua, groups/*.lua)
- [x] Phased approach:
- Phase 11.2-11.4: Extract palette and base groups
- Phase 11.5-11.6: General TreeSitter highlights (modern @* groups)
- Phase 11.7: Semantic highlighting (custom CSS/HTML captures)
- Phase 11.8: Plugin support (LSP, Telescope, Gitsigns, etc.)
## Phase 11.2 — Extract Paper Tonic color palette
- [x] Create `lua/paper-tonic-modern/colors.lua`
- [x] Extract all `c_*` color variables from Paper Tonic
- [x] Document what each color represents (foreground, background, accent colors)
- [x] Convert to modern format (keep hex, 256-color, ANSI mappings)
## Phase 11.3 — Create colorscheme structure
- [x] Create directory structure:
- `colors/paper-tonic-modern.lua` (entry point)
- `lua/paper-tonic-modern/init.lua` (main logic)
- `lua/paper-tonic-modern/colors.lua` (palette)
- `lua/paper-tonic-modern/groups/` (highlight group definitions)
- [x] Create helper function for setting highlights
- [x] Set up colorscheme loading mechanism
## Phase 11.4 — Base vim highlight groups
- [x] Create `lua/paper-tonic-modern/groups/editor.lua`
- [x] Map Paper Tonic colors to base groups: Normal, Comment, LineNr, CursorLine, etc.
- [x] Create `lua/paper-tonic-modern/groups/syntax.lua`
- [x] Map to syntax groups: Function, String, Keyword, Identifier, etc.
- [x] Test with simple Lua file to verify base colors work
## Phase 11.5 — Modern TreeSitter highlight groups
- [x] Create `lua/paper-tonic-modern/groups/treesitter.lua`
- [x] Map modern `@*` groups to Paper Tonic colors:
- Core: @variable, @function, @keyword, @string, @number, @boolean, @comment
- Types: @type, @property, @field, @parameter
- Operators: @operator, @punctuation.delimiter, @punctuation.bracket
- Language constructs: @keyword.function, @keyword.return, @keyword.conditional
- [x] Use `:help treesitter-highlight-groups` as reference
- [x] Test with multiple languages: Lua, PHP, JavaScript, HTML, CSS
## Phase 11.6 — Language-specific TreeSitter groups
- [x] Add language-specific overrides (e.g., @variable.php, @tag.html)
- [x] Ensure HTML tags, CSS selectors, PHP variables have appropriate colors
- [x] Test across primary languages (HTML, PHP, JS, CSS, Markdown)
- [x] Added comprehensive language-specific groups:
- CSS/SCSS: properties, variables, functions (green c2 tones)
- HTML: tags, attributes, delimiters (blue c3)
- PHP: variables, functions, methods, built-ins (primary brownish-red)
- JavaScript/TypeScript: variables, functions, properties, JSX tags (primary + blue for JSX)
- Lua: variables, functions, built-ins (primary)
- Markdown: headings, links, code blocks (primary for structure)
- JSON: properties, strings, numbers (neutral)
- Bash: variables, functions, built-ins (primary)
## Phase 11.7 — Semantic highlighting (custom captures)
- [x] Create `lua/paper-tonic-modern/groups/semantic.lua`
- [x] Define your custom semantic captures:
- @CssClassName (for CSS .class and HTML class="" - same color)
- @CssIdentifier (for CSS #id and HTML id="" - same color)
- @DataAttribute, @DataAttributeValue (HTML data-* attributes)
- @cssPseudoClass, @cssNestingSelector, @CssUniversalSelector (CSS-specific)
- [x] Verify cross-language consistency: class names in HTML match CSS
- [x] Implemented semantic highlights:
- CSS: @CssClassName (green c2), @CssIdentifier (strong green c2_strong), @cssPseudoClass (weak green c2_weak)
- CSS: @cssNestingSelector (strong green), @CssUniversalSelector (SpecialChar)
- CSS: @CssProp (primary_weak), @CssPropertyValue (bold), @CssUnit (Delimiter)
- HTML: @ClassNameAttribute, @IdAttribute, @DataAttribute (all fg_weak for attribute names)
- HTML: @DataAttributeValue (Function)
- Cross-language: class values and #id values in HTML use same colors as CSS selectors
- [x] Test with existing custom queries (after/queries/css/highlights.scm, after/queries/html/highlights.scm)
## Phase 11.8 — Plugin highlight groups
- [x] Create `lua/paper-tonic-modern/groups/lsp.lua`
- [x] Define LSP diagnostics: DiagnosticError, DiagnosticWarn, DiagnosticHint, DiagnosticInfo
- [x] Define LSP UI: LspReferenceText, LspReferenceRead, LspReferenceWrite
- [x] Create `lua/paper-tonic-modern/groups/plugins.lua`
- [x] Add Telescope highlights (TelescopeNormal, TelescopeBorder, TelescopeSelection)
- [x] Add Gitsigns highlights (GitSignsAdd, GitSignsChange, GitSignsDelete)
- [x] Add nvim-cmp highlights (CmpItemKind*, CmpItemMenu, etc.)
**Notes**:
- LSP diagnostics use red (error), orange (warn), blue (info), green (hint)
- LSP references use cyan backgrounds with varying intensity (text/read/write)
- LSP semantic tokens link to TreeSitter groups for consistency
- Telescope uses neutral colors with primary accent for matching and selection
- Gitsigns uses status colors: green (add), blue (change), red (delete)
- nvim-cmp uses primary tones for kinds, bold for matching text
- indent-blankline and ufo use subtle grays for non-intrusive UI
## Phase 11.9 — Update plugin configuration
- [x] Update `lua/plugins/colorscheme.lua` to use paper-tonic-modern
- [x] Remove old Paper Tonic reference
- [x] Remove colorscheme-overrides.lua (no longer needed)
- [x] Test full config reload
**Notes**:
- `lua/plugins/colorscheme.lua` already updated to load `paper-tonic-modern`
- Old `paper-tonic/` directory moved to `legacy/paper-tonic-original/` (archived)
- No `colorscheme-overrides.lua` existed (not needed with modern implementation)
- Full config reload tested: Normal ✓, DiagnosticError ✓, TelescopeNormal ✓, GitSignsAdd ✓
- Colorscheme loads correctly: `vim.g.colors_name = 'paper-tonic-modern'`
## Phase 11.10 — Validation and polish
- [x] Test all primary language parsers (Lua, PHP, HTML, CSS, JS, Markdown)
- [x] Verify semantic highlight captures for matching CSS/HTML classes and IDs load correctly
- [x] Check configured plugin UI highlight groups (Telescope, Gitsigns, nvim-cmp)
- [x] Verify LSP diagnostic highlight groups are defined and distinct
- [x] Document color scheme in README
## Phase 11.11 — Extract to separate repo (later)
- [ ] Move to `~/projects/paper-tonic-modern/`
- [ ] Update plugin config to point to new location
- [ ] Add proper README, LICENSE, screenshots
- [ ] Consider publishing to GitHub
## Phase 12 — Cleanup & Validation
## Phase 12.1 — Confirm scope and priorities
- [x] Confirm scope and priorities for this phase
## Phase 12.2 — Retire legacy files
- [x] Retire tracked `.vimtmp` backup artifacts and prevent them from being re-added
- [x] Retire the broken `legacy/paper-tonic-original` symlink
- [x] Keep the meaningful legacy Vimscript archive as historical reference
## Phase 12.3 — Startup performance
- [x] Validate startup performance (clean headless launch in approximately 45 ms on 2026-10-27)
## Phase 12.4 — Navigation validation
- [ ] Validate Telescope navigation + LSP jumps
- [ ] Validate netrw browsing and preview splits
- [x] Remove Oil.nvim and its keymaps, lockfile entry, highlights, and active documentation
- [x] Fix working directory behavior (disabled autochdir, locked Telescope to project root)
- [x] Make alternate-buffer jumps skip netrw explorer buffers when returning to the last real file
- [x] Guard alternate-buffer tracking against unset or invalid buffer numbers
## Phase 12.5 — Language tooling validation
- [ ] Validate HTML/PHP/JS/Markdown tooling
- [ ] Verify LSP (gd, gr, K, diagnostics)
- [ ] Verify formatting (prettier, phpcbf, stylua)
- [ ] Verify linting (eslint_d, phpcs, markdownlint)
- [x] Confirm primary Tree-sitter parsers and HTML/CSS custom queries load
- [x] Confirm Intelephense attaches with secure project-local includePaths
- [x] Confirm configured formatter and linter executables resolve
## Phase 12.6 — Final polish
- [x] Review all keymaps and ensure they're documented (README.md + :KeymapsGuide)
- [x] Update LOG.md with final architecture and usage
- [x] Omit transient netrw and preview windows from automatic session saves
- [ ] Clean up any remaining debug code or temporary comments
## Phase 13 — Controlled Neovim 0.12 Upgrade
## Phase 13.1 — Confirm scope and upgrade policy
- [x] Confirm scope and priorities for this phase
- [x] Target the current stable release: Neovim 0.12.6
- [x] Continue using the official standalone Linux archive; do not hand Neovim management to pacman
- [x] Keep Neovim 0.11.5 available until the upgraded setup has passed normal-use validation
- [x] Separate the Neovim upgrade, plugin update, and Mason tool update into independently testable steps
## Phase 13.2 — Create a clean rollback checkpoint
- [x] Commit the completed Oil.nvim removal before beginning the upgrade
- [x] Record the current Neovim version, plugin lockfile, parser state, and startup result
- [x] Confirm the existing 0.11.5 configuration still passes its automated checks
- [x] Do not remove or overwrite the working 0.11.5 installation
## Phase 13.3 — Audit 0.12 compatibility before switching
- [x] Review the Neovim 0.12 breaking changes against the active configuration
- [x] Remove deprecated `vim.lsp.with()` handler wrappers; the shared floating-preview override already supplies the configured border
- [x] Disable mason-lspconfig's automatic server activation and remove its obsolete `automatic_installation` option; `lsp.lua` remains the sole activation authority
- [x] Replace deprecated `client.notify(...)` with the 0.12-compatible `client:notify(...)` method for project-local settings
- [x] Replace deprecated `vim.loop` usage with `vim.uv`
- [x] Replace deprecated diagnostic navigation APIs with the current diagnostic jump API
- [x] Revalidate native `exrc` behavior now that 0.12 searches parent directories
- [x] Verify `vim.secure.read()` behavior in the project-local LSP settings loader
- [x] Determine how Neovim 0.12's bundled optional netrw package behaves with the configured explorer workflow
- [x] Confirm no explicit `:packadd netrw` is needed: Neovim's default runtime wrapper loads netrw automatically
- [x] Keep the existing Undotree plugin: Neovim 0.12's built-in `:Undotree` is an inactive optional package, while the configured plugin's richer `:UndotreeToggle` workflow still opens cleanly
## Phase 13.4 — Install Neovim 0.12.6 alongside 0.11.5
- [x] Download the official `nvim-linux-x86_64.tar.gz` release archive
- [x] Verify the archive against the SHA-256 digest published with the release
- [x] Install into a versioned directory without replacing 0.11.5
- [x] Introduce an explicit user-level selector for the active version
- [x] Activate 0.12.6 through the existing `~/.local/bin` PATH entry after verifying both binaries
- [x] Document rollback by repointing `~/.local/bin/nvim` to the 0.11.5 binary
Installed layout:
```text
/opt/neovim/nvim-linux-x86_64/ # 0.11.5 rollback runtime
/opt/neovim/nvim-0.12.6/
~/.local/bin/nvim -> /opt/neovim/nvim-0.12.6/bin/nvim
```
## Phase 13.5 — Test 0.12 with the existing plugin lockfile
- [x] Use isolated `XDG_DATA_HOME`, `XDG_CACHE_HOME`, and `XDG_STATE_HOME` directories
- [ ] Install the currently locked plugin revisions into the isolated data directory
- [x] Keep the production plugin and Mason directories untouched during candidate testing
- [x] Validate headless startup and capture startup time
- [x] Run `:checkhealth` and review every relevant warning/error
- [x] Verify netrw can be loaded and `:Explore` opens the expected tree browser
- [x] Fix core/config compatibility issues before updating plugins
## Phase 13.6 — Update plugins in isolation
- [x] Use a temporary branch or worktree based on the rollback checkpoint
- [x] Run lazy.nvim updates only inside the isolated 0.12 test environment
- [x] Review every lockfile change before adopting it
- [x] Prioritize lazy.nvim, nvim-lspconfig, Treesitter, Telescope, Mason integration, completion, formatting, linting, UFO, and Copilot compatibility
- [x] Rebuild or update Treesitter parsers for the 0.12 runtime and verify custom queries
- [x] Keep Mason-managed language servers, formatters, and linters pinned during this step
- [x] Adopt the tested lockfile only after all plugin-level regressions are resolved
## Phase 13.7 — Validate the complete 0.12 candidate
- [x] Validate startup, lazy loading, commands, and configured keymaps automatically
- [x] Validate netrw tree browsing, previews, alternate-buffer behavior, and file operations
- [ ] Validate Telescope files, grep, buffers, and LSP symbol pickers
- [x] Validate LSP attachment, `gd`, `gr`, `K`, diagnostics, and project-local `.nvim.lua` settings
- [x] Validate the current completion stack before activation; native completion migration follows in Phase 13.9
- [x] Validate conform formatter availability and nvim-lint diagnostics; retain normal-use checks for save-time behavior
- [x] Validate Treesitter parsers and custom HTML/CSS queries; retain interactive checks for highlighting, text objects, autotag, and folding
- [ ] Validate the Paper Tonic colorscheme, plugin highlights, sessions, persistent undo, and shell templates
- [x] Perform a PTY-backed PHP smoke test for native completion selection, acceptance, snippets, LSP settings, and diagnostics
## Phase 13.8 — Activate with rollback available
- [x] Switch the active-version selector from 0.11.5 to 0.12.6
- [x] Repeat a short smoke test through the normal shell/PATH entrypoint
- [x] Keep 0.11.5 and its rollback instructions available during a settling period
- [x] Update AGENTS.md, README.md, and LOG.md with the final supported version and upgrade procedure
- [ ] Remove 0.11.5 only after an explicit later decision
## Phase 13.9 — Consolidate on Neovim 0.12 native features
- [x] Keep lazy.nvim as the plugin manager; do not combine the runtime upgrade with a migration to experimental `vim.pack`
- [x] Replace `mbbill/undotree` with the optional native `nvim.undotree` package while preserving `<leader>u`
- [x] Configure native automatic/LSP completion with explicit selection and built-in snippet expansion for its settling trial
- [x] Enable Copilot inline suggestions with a distinct accept key and hide them while the native completion menu is visible
- [x] Validate PHP, HTML, JavaScript/TypeScript, Markdown, Lua, paths, snippets, autopairs, and Copilot interactively
- [x] Remove nvim-cmp, cmp-nvim-lsp, cmp-buffer, cmp-path, LuaSnip, and copilot-cmp from the 0.12 candidate
- [x] Remove obsolete completion integrations, lockfile entries, highlights, and documentation
## Phase 13.10 — Update external tools separately
- [ ] Review Mason package updates only after Neovim and plugin revisions are stable
- [ ] Update language servers, formatters, and linters in small groups
- [ ] Revalidate PHP, JavaScript/TypeScript, HTML/CSS, Markdown, Lua, and Python after each group
## Phase 14 — Netrw Live Preview and Directory Summaries
## Phase 14.1 — Confirm the final interaction model
- [x] Confirm scope and priorities for this phase after the 0.12 upgrade
- [x] Keep netrw as the sole tree browser and file explorer
- [x] Keep `p` as the preview entry point so stock-netrw muscle memory remains useful on remote systems
- [x] Once a native preview window exists, update it automatically as the netrw cursor moves
- [x] Close the preview automatically when a file is opened for editing or netrw is left
- [x] Treat the existence of the preview window as state; avoid a separate global preview-mode flag
Target workflow:
```text
p on file/directory toggle preview and live updates
j / k replace preview with the selected entry
<CR>, o, v, t open the file and close the preview
:pclose / <C-w>z close the preview and stop live updates
```
## Phase 14.2 — Revalidate netrw integration on Neovim 0.12
- [x] Confirm bundled netrw v184 and its documented `netrw#Call()` bridge
- [x] Confirm `NetrwGetWord`, `NetrwBrowseChgDir`, `NetrwTreePath`, and `NetrwPreview` remain available
- [x] Confirm tree paths, symlinks, directory markers, local paths, and URI paths are classified correctly
- [x] Resolve any interaction with Neovim 0.12's directory startup behavior: a real UI opens the configured netrw tree normally
- [x] Keep a graceful stock-netrw fallback if enhanced preview setup cannot be installed
## Phase 14.3 — Implement live preview lifecycle
- [x] Extend netrw's buffer-local `p` behavior without changing its familiar purpose
- [x] Add a narrowly scoped, buffer-local `CursorMoved` autocmd
- [x] Debounce preview updates by approximately 75–100 ms
- [x] Update only when a preview window exists in the current tab
- [x] Continue using netrw's native preview machinery for regular files
- [x] Close the preview when leaving the netrw buffer to edit a file
- [x] Cancel and close pending timers when the netrw buffer is wiped out
- [x] Avoid focus changes: keep the cursor in the tree while previews update
## Phase 14.4 — Add read-only directory summaries
- [x] Show an informational scratch-buffer preview when the selected entry is a directory
- [x] List immediate children only; do not calculate recursive directory sizes
- [x] Sort directories first and files second, alphabetically within each group
- [x] Show entry type, human-readable file size, modification time, and name
- [x] Show a summary count and total size for immediate files
- [x] Cap output at approximately 200 entries and show a truncation notice
- [x] Handle empty, missing, unreadable, and rapidly changing directories without errors
- [x] Display symlinks distinctly without recursively following directory links
- [x] Mirror netrw's hidden-file visibility where practical
- [x] Support local filesystems when Neovim itself is running over SSH
- [x] Fall back to native behavior for remote netrw URI schemes if directory enumeration is unavailable
Example directory preview:
```text
lua/plugins/
Type Size Modified Name
dir — 2026-10-27 11:42 helpers/
file 4.8K 2026-10-27 13:10 lsp.lua
file 3.2K 2026-10-27 12:55 telescope.lua
1 directory, 2 files, 8.0K
```
## Phase 14.5 — Test preview behavior
- [x] Test file → file, file → directory, directory → file, and directory → directory movement
- [x] Test directory expand/collapse while a preview exists
- [x] Test manual preview closure and confirm cursor movement no longer previews
- [x] Test `<CR>`, horizontal split, vertical split, and tab selection cleanup
- [ ] Test separate preview windows across tabpages
- [x] Test spaces, Unicode, symlinks, unreadable entries, and large directories
- [x] Test rapid cursor movement for flicker, stale timers, and excess filesystem work
- [x] Prevent Tree-sitter parser races during rapid cross-language file preview replacement and restore highlighting on edit
- [x] Hide diagnostics in file previews and restore their prior per-buffer state on edit
- [x] Suppress remaining Vim syntax and indent-guide decoration in file previews, restoring prior state on edit
- [x] Add count-aware `<M-j>` / `<M-k>` preview scrolling without moving focus from netrw
- [x] Make preview scrolling silently clamp at file/window boundaries
- [x] Make `p` toggle an existing preview closed as well as opening it
- [ ] Test the workflow in an actual SSH session
- [ ] Confirm stock netrw remains understandable when this configuration is unavailable
## Phase 14.6 — Document and finalize
- [x] Update README.md and dynamic `:KeymapsGuide` mapping descriptions with the enhanced `p` lifecycle
- [x] Record implementation decisions and limitations in LOG.md
- [ ] Mark Phase 12.4 netrw preview validation complete after interactive use
---
Notes:
- Keep plugin specs minimal; configure in their own `lua/plugins/*.lua` files.
- Avoid adding plugins not listed in the guide unless explicitly requested.
- Prefer simple defaults; only add settings that clearly improve workflow.
- Plugin approval policy: unlisted plugins may be proposed, but must be explicitly confirmed before installation.
Known Issues / Follow-ups:
- lua-language-server (lua_ls) from Mason failed to start due to missing shared library `libbfd-2.38-system.so`. **RESOLVED**: Installed lua-language-server via system package manager (pacman) instead of Mason. Removed `lua_ls` from Mason's ensure_installed list in `lua/plugins/mason-lspconfig.lua`.
- LSP root detection: In some cases, the parent repository is picked as the root (e.g., when a workspace lives inside another repo). Workaround: create an empty `.git` directory (or a marker like `.nvimroot`) in the intended workspace root to pin the project root for LSPs.
Decisions & Changes:
- **Neoconf dropped**: folke/neoconf.nvim incompatible with Neovim 0.11+ vim.lsp.config API (GitHub issue #116, open since May 2024, no resolution). Migrated to native `exrc` + `secure` approach.
- **vim.lsp.config migration**: Migrated from deprecated `require('lspconfig')[server].setup()` to `vim.lsp.config()` + `vim.lsp.enable()` (Neovim 0.11+ native API).
- **Project config format**: `.nvim.lua` files return `{ lsp = { [server_name] = { settings = {...} } } }`.
- **Security model**: `secure` mode prompts user to trust `.nvim.lua` files before execution (one-time per file hash).
- **Settings loading**: An `LspAttach` callback securely reads project settings from the client's actual `root_dir` (not cwd), ensuring correct behavior across different workspace structures.
- **Phase 4 Navigation Strategy**: Use built-in netrw as the sole tree browser and file explorer so the workflow transfers to remote systems. Telescope remains the fuzzy finder. Oil.nvim was evaluated and removed because maintaining a second explorer split muscle memory without providing the preferred tree view.

View file

@ -1,519 +0,0 @@
# Navigation Enhancement Plans
**Status**: Two complementary approaches being considered (not mutually exclusive)
Both approaches aim to reduce repetitive typing when navigating with Neovim's bracket-based pairs (`[c`, `]d`, etc.).
---
## Option 1: Repeat/Reverse Last Bracket Navigation
### Concept
Two simple commands that remember and replay the last `[x` or `]x` navigation:
- **Repeat**: Execute the same navigation again (e.g., `]d` → `.` → `.` → `.`)
- **Reverse**: Execute the opposite direction (e.g., after `]d`, press `,` → `[d`)
Similar to `;` and `,` for repeating/reversing `f/F/t/T` motions.
### User Experience
```vim
" Example 1: Scanning diagnostics
]d " Next diagnostic
. " Next diagnostic (repeat)
. " Next diagnostic (repeat)
. " Next diagnostic (repeat)
, " Previous diagnostic (reverse, oops went too far)
" Example 2: Checking spelling
]s " Next misspelling
. " Next misspelling
. " Next misspelling
" Example 3: Quickfix workflow
]q " Next quickfix item
. " Next quickfix
. " Next quickfix
```
### When This Works Best
- Repeatedly navigating **same type**: diagnostics, spelling, quickfix, location list
- Linear scanning through items of one kind
- Quick corrections when you overshoot (reverse)
### Implementation
**Module**: `lua/bracket-repeat.lua`
```lua
local M = {}
-- Track last bracket navigation
local last_nav = {
prefix = nil, -- '[' or ']'
key = nil, -- 'c', 'd', 'm', 's', 'q', etc.
}
--- Setup wrapper mappings to track bracket navigation
function M.setup()
-- Common bracket pairs to track
local pairs = {
'c', -- Git hunks (gitsigns)
'd', -- Diagnostics
's', -- Spelling
'q', -- Quickfix
'l', -- Location list
't', -- Tags
'm', -- Methods (treesitter)
'f', -- Functions (treesitter)
'p', -- Parameters (treesitter)
}
for _, key in ipairs(pairs) do
-- Wrap [x to track
vim.keymap.set('n', '[' .. key, function()
last_nav.prefix = '['
last_nav.key = key
return '[' .. key
end, { expr = true, silent = true })
-- Wrap ]x to track
vim.keymap.set('n', ']' .. key, function()
last_nav.prefix = ']'
last_nav.key = key
return ']' .. key
end, { expr = true, silent = true })
end
end
--- Repeat last bracket navigation
function M.repeat_last()
if not last_nav.prefix or not last_nav.key then
vim.notify('No bracket navigation to repeat', vim.log.levels.WARN)
return
end
vim.cmd('normal! ' .. last_nav.prefix .. last_nav.key)
end
--- Reverse last bracket navigation (flip direction)
function M.reverse_last()
if not last_nav.prefix or not last_nav.key then
vim.notify('No bracket navigation to reverse', vim.log.levels.WARN)
return
end
local opposite = last_nav.prefix == '[' and ']' or '['
vim.cmd('normal! ' .. opposite .. last_nav.key)
-- Update tracking to reflect the reversal
last_nav.prefix = opposite
end
return M
```
**Integration**: `init.lua` or `lua/keymaps.lua`
```lua
-- Setup tracking
require('bracket-repeat').setup()
-- Keybindings (choose one option)
-- Option A: Override ; and , (loses f/F/t/T repeat, but very ergonomic)
vim.keymap.set('n', ';', function() require('bracket-repeat').repeat_last() end,
{ desc = 'Repeat bracket navigation' })
vim.keymap.set('n', ',', function() require('bracket-repeat').reverse_last() end,
{ desc = 'Reverse bracket navigation' })
-- Option B: Use z prefix (keeps ; and , for f/t motions)
vim.keymap.set('n', 'z.', function() require('bracket-repeat').repeat_last() end,
{ desc = 'Repeat bracket navigation' })
vim.keymap.set('n', 'z,', function() require('bracket-repeat').reverse_last() end,
{ desc = 'Reverse bracket navigation' })
-- Option C: Use leader
vim.keymap.set('n', '<leader>.', function() require('bracket-repeat').repeat_last() end,
{ desc = 'Repeat bracket navigation' })
vim.keymap.set('n', '<leader>,', function() require('bracket-repeat').reverse_last() end,
{ desc = 'Reverse bracket navigation' })
```
### Pros & Cons
**Pros:**
- ✅ Very simple (~40 lines)
- ✅ No mode switching, stays in normal mode
- ✅ Familiar pattern (like `;`/`,` for `f`/`t`)
- ✅ Works with natural workflow
- ✅ Easy to add more tracked pairs
**Cons:**
- ⚠️ Only handles one "type" at a time (can't easily switch between `]d` and `]c`)
- ⚠️ Requires calling `.setup()` to track pairs
- ⚠️ Might want `;`/`,` for `f`/`t` repeat (depends on keybinding choice)
### Estimated Complexity
- **Total**: ~40 lines
- **Time**: 15-30 minutes
---
## Option 2: Navigation Mode (getchar Loop)
## User Experience
### Entry
- `z[` - Enter navigation mode with `[` prefix active (backward)
- `z]` - Enter navigation mode with `]` prefix active (forward)
### In Mode
- All letter keys (`a-z`, `A-Z`) get prefixed with current bracket
- Examples:
- Press `c` → executes `[c` or `]c` (git hunks)
- Press `d` → executes `[d` or `]d` (diagnostics)
- Press `m` → executes `[m` or `]m` (methods)
- Press `f` → executes `[f` or `]f` (functions)
- Press `b` → executes `[b` or `]b` (buffers)
- Press `q` → executes `[q` or `]q` (quickfix)
### Toggle Prefix
- `[` - Switch to `[` prefix (backward navigation)
- `]` - Switch to `]` prefix (forward navigation)
### Exit
- `<Esc>` - Exit navigation mode and return to normal editing
### When This Works Best
- Switching between **different types** of navigation (`]d` → `]c` → `]m`)
- Want visual feedback showing current direction
- Prefer a dedicated "navigation state"
- Mixed workflow: `]q` to quickfix, then multiple `]c` for hunks (stay in mode, switch keys)
### Example Workflow
```vim
" Mixed navigation scenario
z] " Enter forward navigation mode (shows: NAV ] →:)
q " Execute ]q (next quickfix)
c " Execute ]c (next hunk)
c " Execute ]c (next hunk)
[ " Toggle to backward (shows: NAV [ ←:)
c " Execute [c (previous hunk)
d " Execute [d (previous diagnostic)
<Esc> " Exit mode
```
## Technical Implementation
### Approach: getchar() Loop (No Remapping)
Instead of remapping keys, use a `while` loop with `vim.fn.getchar()` to read keypresses and manually execute the prefixed commands.
**Why this approach:**
- ✅ Zero mapping conflicts (never touches existing keymaps)
- ✅ Simpler implementation (~50-80 lines vs ~150-250)
- ✅ Built-in visual feedback via `vim.api.nvim_echo()`
- ✅ Impossible to leak state (no cleanup needed if crashed)
- ✅ Predictable behavior (each keypress isolated)
- ✅ Naturally handles special keys
**The "blocking" behavior is actually desired** - you're in a focused navigation mode, press `<Esc>` to exit anytime.
### Common Bracket Navigation Pairs
- `[c`/`]c` - Previous/next git hunk (gitsigns)
- `[d`/`]d` - Previous/next diagnostic
- `[b`/`]b` - Previous/next buffer (custom mapping)
- `[q`/`]q` - Previous/next quickfix item
- `[l`/`]l` - Previous/next location list item
- `[m`/`]m` - Previous/next method (treesitter textobjects)
- `[f`/`]f` - Previous/next function (treesitter textobjects)
- `[p`/`]p` - Previous/next parameter (treesitter textobjects)
- `[t`/`]t` - Previous/next tag
## Implementation Details
### Module Structure
Create `lua/navigation-mode.lua`:
```lua
local M = {}
--- Enter navigation mode with getchar() loop
--- @param prefix string Either '[' or ']'
function M.enter(prefix)
prefix = prefix or '['
while true do
-- Display prompt
local hl = prefix == '[' and 'DiagnosticInfo' or 'DiagnosticHint'
local arrow = prefix == '[' and '←' or '→'
vim.api.nvim_echo({{string.format('NAV %s %s: ', prefix, arrow), hl}}, false, {})
-- Get next keypress
local ok, char = pcall(vim.fn.getchar)
if not ok then break end -- Handle <C-c> gracefully
-- Convert to string
local key = type(char) == 'number' and vim.fn.nr2char(char) or char
-- Handle special keys
if key == '\27' then -- ESC
break
elseif key == '[' then
prefix = '['
elseif key == ']' then
prefix = ']'
else
-- Execute prefix + key as normal mode command
local cmd = prefix .. key
vim.cmd('normal! ' .. vim.api.nvim_replace_termcodes(cmd, true, false, true))
end
end
-- Clear prompt
vim.api.nvim_echo({{'', 'Normal'}}, false, {})
end
return M
```
**Key Points:**
- No state management needed (self-contained loop)
- `pcall(vim.fn.getchar)` handles `<C-c>` interrupts gracefully
- `vim.api.nvim_replace_termcodes()` ensures special key sequences work
- Visual feedback built into the loop (shows `NAV [ ←:` or `NAV ] →:`)
- Press `[` or `]` to toggle prefix without exiting
- Press `<Esc>` (or `<C-c>`) to exit
### Integration in keymaps.lua
```lua
-- Navigation mode
vim.keymap.set('n', 'z[', function()
require('navigation-mode').enter('[')
end, { desc = 'Enter navigation mode (backward)' })
vim.keymap.set('n', 'z]', function()
require('navigation-mode').enter(']')
end, { desc = 'Enter navigation mode (forward)' })
```
## Visual Feedback
Built into the getchar() loop:
- Shows `NAV [ ←:` (in blue) when in backward mode
- Shows `NAV ] →:` (in teal) when in forward mode
- Prompt updates immediately when toggling with `[` or `]`
- Clears when exiting with `<Esc>`
No additional statusline integration needed - the command line prompt is clear and non-intrusive.
## Design Decisions
### Mapping Conflicts: Solved
No mapping conflicts possible - getchar() reads raw input without touching keymaps.
### Buffer-local Mappings: Not Applicable
Loop executes `normal! [key` which uses whatever mappings exist naturally.
### Visual Feedback: Built-in
Command line prompt is sufficient and non-intrusive.
### Number Keys
Currently not prefixed - this allows using counts if a prefixed command accepts them.
Example: `3c` → executes `[3c` or `]3c` (may not be useful, but won't break anything)
Could add special handling if needed:
```lua
if key:match('^%d$') then
-- Handle numbers specially
end
```
### Operators (d, c, y, etc.)
In navigation mode, `d` executes `[d` (diagnostic navigation), not delete operator.
This is desired behavior - use `<Esc>` to exit and edit normally.
### Error Handling
If a command doesn't exist (e.g., `[z`), Vim will show an error but mode continues.
User can press `<Esc>` to exit or try another key.
### Pros & Cons
**Pros:**
- ✅ Switch between different navigation types easily (`c` → `d` → `m`)
- ✅ Visual feedback (command line prompt)
- ✅ No mapping conflicts
- ✅ Clean state (nothing to cleanup if interrupted)
- ✅ Natural for rapid mixed navigation
**Cons:**
- ⚠️ Requires mode switching (mental overhead)
- ⚠️ Blocking loop (though this is by design)
- ⚠️ Need to remember entry/exit keys
### Estimated Complexity
- **Total**: ~50-80 lines
- **Time**: 30-60 minutes
---
## Comparison & Recommendation
| Aspect | Repeat/Reverse | Navigation Mode |
|--------|---------------|----------------|
| **Best for** | Same-type scanning | Mixed navigation |
| **Complexity** | ~40 lines | ~50-80 lines |
| **Mental model** | Like `;`/`,` | New mode |
| **Typing (4× same nav)** | `]d ...` (4 keys) | `z] dddd <Esc>` (9 keys) |
| **Typing (mixed nav)** | `]d ]d ]c ]c` (8 keys) | `z] ddcc <Esc>` (9 keys) |
| **Mode switching** | No | Yes |
| **Visual feedback** | No (unless added) | Yes (built-in) |
### Use Cases
**Repeat/Reverse excels at:**
- Scanning diagnostics: `]d . . . .`
- Spell checking: `]s . . . .`
- Reviewing quickfix: `]q . . . .`
- Going back: `. . . , , ,`
**Navigation Mode excels at:**
- Mixed workflow: `]q` → multiple `]c` hunks → check `]d` diagnostic
- When you want visual confirmation of direction
- Exploring unfamiliar code (trying different navigation types)
### Implementation Strategy
**Both can coexist!** They solve slightly different problems:
1. **Start with Repeat/Reverse** (simpler, covers 80% of cases)
- Use for linear scanning (diagnostics, spelling, quickfix)
- Bind to `z.` and `z,` (or `;`/`,` if you don't use `f`/`t` repeat often)
2. **Add Navigation Mode later** (optional, for mixed navigation)
- Use when you need to rapidly switch types
- Bind to `z[` and `z]`
You'll naturally reach for whichever fits the situation better.
---
## Common Bracket Pairs Reference
- `[c`/`]c` - Previous/next git hunk (gitsigns)
- `[d`/`]d` - Previous/next diagnostic
- `[s`/`]s` - Previous/next misspelling
- `[q`/`]q` - Previous/next quickfix item
- `[l`/`]l` - Previous/next location list item
- `[m`/`]m` - Previous/next method (treesitter textobjects)
- `[f`/`]f` - Previous/next function (treesitter textobjects)
- `[p`/`]p` - Previous/next parameter (treesitter textobjects)
- `[t`/`]t` - Previous/next tag
- `[b`/`]b` - Previous/next buffer (if custom mapping exists)
---
## Testing Checklists
### Repeat/Reverse Testing
- [ ] Setup completes without errors
- [ ] `]d` followed by `.` repeats diagnostic navigation
- [ ] `]s` followed by `.` repeats spelling navigation
- [ ] `]q` followed by `.` repeats quickfix navigation
- [ ] `,` reverses last navigation direction
- [ ] Warning shown when no navigation to repeat/reverse
- [ ] Works across different buffers
- [ ] Multiple reverses work: `. . . , , ,`
### Navigation Mode Testing
- [ ] Enter mode with `z[` and `z]`
- [ ] Verify visual prompt shows `NAV [ ←:` or `NAV ] →:`
- [ ] Press `c` → navigates to previous/next git hunk
- [ ] Press `d` → navigates to previous/next diagnostic
- [ ] Press `m` → navigates to previous/next method
- [ ] Press `f` → navigates to previous/next function
- [ ] Toggle with `[` → prompt updates to `NAV [ ←:`
- [ ] Toggle with `]` → prompt updates to `NAV ] →:`
- [ ] Exit with `<Esc>` → prompt clears, back to normal mode
- [ ] Exit with `<C-c>` → handles gracefully
- [ ] Works across different buffers
- [ ] Invalid keys (e.g., `z`) show error but don't crash
- [ ] Existing keymaps still work after exit
---
## Implementation Priority
**Recommended order:**
1. **Phase 1: Repeat/Reverse** (start here)
- Simpler, faster to implement
- Covers most common use cases
- Get immediate value
2. **Phase 2: Navigation Mode** (optional, evaluate need)
- Implement only if you find yourself wanting mixed navigation
- Can be added anytime without conflicts
- Both features work together
**Time estimate:**
- Phase 1: 15-30 minutes
- Phase 2: 30-60 minutes
- Total: 45-90 minutes if both implemented
---
## Implementation Steps
### For Repeat/Reverse (Start Here)
1. **Create `lua/bracket-repeat.lua`** (~40 lines)
- Implement tracking state
- Implement `setup()`, `repeat_last()`, `reverse_last()`
2. **Add to `init.lua`**
```lua
require('bracket-repeat').setup()
```
3. **Add keymaps** (`lua/keymaps.lua`)
```lua
vim.keymap.set('n', 'z.', function() require('bracket-repeat').repeat_last() end)
vim.keymap.set('n', 'z,', function() require('bracket-repeat').reverse_last() end)
```
4. **Test** with diagnostics, spelling, quickfix
5. **Document** in README.md
### For Navigation Mode (Optional Later)
1. **Create `lua/navigation-mode.lua`** (~50 lines)
- Implement `M.enter(prefix)` with getchar() loop
- Handle ESC, `[`, `]`, and general keys
- Add visual feedback via `nvim_echo`
2. **Add keymaps** (`lua/keymaps.lua`)
```lua
vim.keymap.set('n', 'z[', function()
require('navigation-mode').enter('[')
end, { desc = 'Navigation mode (backward)' })
vim.keymap.set('n', 'z]', function()
require('navigation-mode').enter(']')
end, { desc = 'Navigation mode (forward)' })
```
3. **Test basic functionality**
- Enter with `z[` / `z]`
- Navigate with `c`, `d`, `m`, `f`, `q`
- Toggle prefix with `[` / `]`
- Exit with `<Esc>`
4. **Polish** (optional)
- Add help text on first use
- Handle `<C-c>` gracefully (already done with `pcall`)
- Consider adding common navigation cheatsheet
5. **Document**
- Update `README.md` with new keymaps
- Add navigation pairs reference

View file

@ -4,6 +4,9 @@ Living reference for session management, keymaps, commands, and plugin-specific
The active runtime is Neovim 0.12.6 through `~/.local/bin/nvim`. Neovim 0.11.5 remains available at `/opt/neovim/nvim-linux-x86_64/bin/nvim` for emergency rollback; the config starts there with 0.12-only native completion and Undotree disabled.
Persistent undo files are stored outside this repository in
`stdpath('state')/undo` (normally `~/.local/state/nvim/undo`).
## Session Management
Session support is automatic but user-controlled:
@ -274,17 +277,22 @@ Buffer-local keymaps available when inside a git repository:
### Treesitter `lua/plugins/treesitter.lua`
The Neovim 0.12-compatible `main` branches are used for both nvim-treesitter
and nvim-treesitter-textobjects. Highlighting and incremental selection use
Neovim's native APIs; textobjects use explicit plugin mappings. Parser builds
require `tree-sitter-cli` 0.26.1 or newer (`tree-sitter --version`).
#### Keymaps
##### Incremental selection
| Key | Description |
| --- | --- |
| `+` | Initialize/expand selection |
| `+` | Initialize/expand selection to the parent node |
| `g+` | Expand to scope |
| `-` | Shrink selection |
| `-` | Shrink selection to the child node |
##### Textobject selection (`select.keymaps`)
##### Textobject selection
| Key | Target |
| --- | --- |
@ -295,7 +303,7 @@ Buffer-local keymaps available when inside a git repository:
| `al` / `il` | Loop outer / inner |
| `a/` | Comment outer |
##### Textobject movement (`move` mappings)
##### Textobject movement
| Key | Action |
| --- | --- |

View file

@ -1,129 +0,0 @@
# Critical Regression Fix: LSP Project Settings Not Loading (2025-12-07)
## Summary
`gd` (goto definition) stopped working for external library references in `WORKSPACE_TEST/site/external.php`. Even restoring to a git commit where it previously worked didn't fix it, indicating an **environment change** rather than a code regression.
## Root Cause
**Neovim 0.11+ removed support for the `on_new_config` callback in `vim.lsp.config()`.**
The previous implementation used `on_new_config` to load project-local settings from `.nvim.lua`:
```lua
vim.lsp.config(server_name, {
on_new_config = function(new_config, root_dir)
-- Load project settings and merge into new_config.settings
local project_settings = load_project_lsp_settings(server_name, root_dir)
if project_settings.settings then
new_config.settings = vim.tbl_deep_extend("force",
new_config.settings or {},
project_settings.settings)
end
end,
})
```
**Problem**: This callback was **silently ignored** in Neovim 0.11+, resulting in:
- Empty `client.settings` (confirmed via `:LspInfo` showing `Settings: {}`)
- No `includePaths` sent to intelephense
- `gd` failing with "No locations found" for external library symbols
## Symptoms
1. `:LspInfo` showed `Settings: {}` for intelephense
2. `gd` on `\ExtLib\Src\Util::greetExternal()` returned "No locations found"
3. Local (workspace) symbol navigation worked fine
4. Git history restore didn't help (environment issue, not code issue)
## Solution
Use the `LspAttach` autocmd instead of `on_new_config` to load and apply project settings:
```lua
vim.api.nvim_create_autocmd('LspAttach', {
group = vim.api.nvim_create_augroup('lsp_project_settings', { clear = true }),
callback = function(args)
local client = vim.lsp.get_client_by_id(args.data.client_id)
if not client then return end
-- Load project-specific settings from .nvim.lua at client.root_dir
local project_settings = load_project_lsp_settings(client.name, client.root_dir)
if project_settings.settings then
-- Merge into client.settings
client.settings = vim.tbl_deep_extend("force",
client.settings or {},
project_settings.settings)
-- Notify server of updated settings
vim.schedule(function()
client.notify("workspace/didChangeConfiguration",
{ settings = client.settings })
end)
end
end,
})
```
## Validation
After fix:
```bash
cd WORKSPACE_TEST
nvim --headless +'e site/external.php' +'lua vim.wait(3000); local clients = vim.lsp.get_clients({name="intelephense"}); if clients[1] then print("Settings:", vim.inspect(clients[1].settings)) end' +quit
```
Output:
```lua
Settings: {
intelephense = {
environment = {
includePaths = { "/home/ray/.config/nvim/EXTERNAL_TEST" }
}
}
}
```
✅ Settings now correctly loaded and `gd` works for external symbols.
## Key Differences: Neovim 0.10 vs 0.11 LSP API
### Old API (lspconfig plugin, Neovim < 0.11)
```lua
require('lspconfig').intelephense.setup({
on_new_config = function(new_config, root_dir)
-- Called when creating new client
end,
})
```
### New API (native vim.lsp.config, Neovim 0.11+)
```lua
-- Define config
vim.lsp.config('intelephense', { ... })
-- Enable server
vim.lsp.enable('intelephense')
-- Handle dynamic settings via autocmd
vim.api.nvim_create_autocmd('LspAttach', {
callback = function(args)
-- Access client, load settings, notify server
end,
})
```
## Documentation Updated
- `LOG.md`: Added decision log entry for 2025-12-07
- `.github/copilot-instructions.md`: Now a simple pointer to AGENTS.md
- `AGENTS.md`: Already notes "Native exrc + vim.lsp.config migration done"
## Prevention
- Always test LSP functionality after Neovim version upgrades
- Check `:help news` for API changes
- Validate `:LspInfo` settings are populated correctly
- Test with external library references, not just workspace files
## Files Modified
- `lua/plugins/lsp.lua`: Replaced `on_new_config` with `LspAttach` autocmd
## Timeline
- **Before 2025-12-07**: `on_new_config` worked in older Neovim version
- **2025-12-07**: Neovim upgraded to 0.11.5, `on_new_config` silently ignored
- **2025-12-07**: Diagnosed via `:LspInfo` showing empty settings
- **2025-12-07**: Fixed with `LspAttach` pattern, verified working

View file

@ -1,93 +0,0 @@
# LSP Diagnostic Test Files
These files are designed to trigger LSP diagnostics of all types to test the Paper Tonic Modern colorscheme's diagnostic virtual text colors.
## Test Files
### test-diagnostics.lua
Lua file with intentional errors for lua_ls (Lua Language Server).
**Expected diagnostics:**
- **Errors** (red): Undefined variables/functions, type mismatches, invalid operations, wrong argument counts
- **Warnings** (orange): Unused variables, shadowing, unreachable code, lowercase globals
- **Hints** (green): Redundant code, style issues
**Note**: lua_ls provides the best mix of diagnostic levels.
### test-diagnostics.php
PHP file with intentional errors for Intelephense (PHP Language Server).
**Expected diagnostics:**
- **Errors** (red): Most issues appear as errors by default in Intelephense
- Undefined functions/variables
- Type mismatches
- Wrong argument counts
- Invalid method calls
**Note**: Intelephense is strict and reports most issues as errors. To see warnings/hints, configure in `.nvim.lua`:
```lua
return {
lsp = {
intelephense = {
settings = {
intelephense = {
diagnostics = {
undefinedSymbols = true,
undefinedVariables = true,
unusedSymbols = "hint", -- Show unused as hints
}
}
}
}
}
}
```
### test-diagnostics.js
JavaScript file with intentional errors for ts_ls (TypeScript Language Server).
**Expected diagnostics:**
- **Errors** (red): Undefined variables/functions, invalid property access, missing parameters
- **Warnings** (orange): Unreachable code, type comparison issues, duplicate cases
- **Hints** (green): const vs let suggestions
- **Info** (blue): Unnecessary operations
## How to Use
1. Open any test file in Neovim:
```bash
nvim test-diagnostics.lua
# or
nvim test-diagnostics.php
# or
nvim test-diagnostics.js
```
2. Wait for LSP to attach and analyze the file (1-2 seconds)
3. Check the virtual text diagnostics at the end of lines with issues
4. Use `:LspInfo` to verify the LSP server is attached
## Color Reference
The Paper Tonic Modern colorscheme uses these colors for diagnostics:
- **DiagnosticError** (virtual text): `#d70000` (bright red) on `#ffefef` background
- **DiagnosticWarn** (virtual text): `#d75f00` (orange) on `#ece0e0` background
- **DiagnosticInfo** (virtual text): `#8989af` (blue) on `#e0e0ec` background
- **DiagnosticHint** (virtual text): `#89af89` (green) on `#e0ece0` background
## Testing Checklist
- [ ] Errors show in red with red undercurl
- [ ] Warnings show in orange with orange undercurl
- [ ] Hints show in green
- [ ] Info messages show in blue
- [ ] Virtual text is readable against light background
- [ ] Sign column icons show correct colors
- [ ] Diagnostic floating windows display correctly
## Debug Command
Use the `<leader>hi` keymap to inspect highlight info under cursor and verify diagnostic colors are applied correctly.

View file

@ -1,3 +0,0 @@
snippet tp "{% partial ... " i
{% partial '$1'$0 %}
endsnippet

View file

@ -1,265 +0,0 @@
snippet abs "pabs position: absolute;"
position: absolute;
endsnippet
snippet fix "position: fixed;"
position: fixed;
endsnippet
snippet rel "position: relative;"
position: relative;
endsnippet
snippet row "flex-direction: row;"
flex-direction: row;
endsnippet
snippet col "flex-direction: column;"
flex-direction: column;
endsnippet
snippet over "overflow: hidden;"
overflow: $0;
endsnippet
snippet style "/* stylelint-disable-next-line ... */"
/* stylelint-disable-next-line ${1:declaration-block-no-shorthand-property-overrides} */
endsnippet
snippet @m "@media ( ..."
@media (${1:min-width}: ${2:$bp-${3:s}-min}) {
$0
}
endsnippet
snippet @max "@media (max-width: ..."
@media (max-width: ${2:$bp-${3:s}-max}) {
$0
}
endsnippet
snippet @min "@media (min-width: ..."
@media (min-width: ${2:$bp-${3:s}-min}) {
$0
}
endsnippet
snippet lg "linear-gradient( ... )"
linear-gradient(
${1:to bottom},
${2:transparent},
${3:transparent}
)$0
endsnippet
snippet bglg "background: linear-gradient ..."
background-image: linear-gradient(
${2:to bottom},
${3:transparent},
${4:transparent}
);
endsnippet
snippet flex "display: flex ..."
display: flex;${1:
flex-direction: ${2:column};}
justify-content: ${3:center};
align-items: ${4:center};
endsnippet
snippet w "width: ;"
width: ${1:100%};
endsnippet
snippet h "height: ;"
height: ${1:100%};
endsnippet
snippet wh "width: ; height: ;"
width: ${1:100%};
height: $1;
endsnippet
snippet mxw "max-width: ;"
max-width: ${1:100%};
endsnippet
snippet mxh "max-height: ;"
max-height: ${1:100%};
endsnippet
snippet mnw "min-width: ;"
min-width: ${1:100%};
endsnippet
snippet mnh "min-height: ;"
min-height: ${1:100%};
endsnippet
snippet bgc "background-color: ;"
background-color: ${1:transparent};
endsnippet
snippet t "top: ... ;"
top: ${1:0};
endsnippet
snippet b "bottom: ... ;"
bottom: ${1:0};
endsnippet
snippet l "left: ... ;"
left: ${1:0};
endsnippet
snippet r "right: ... ;"
right: ${1:0};
endsnippet
snippet bd "border: ... ;"
border: ${1:1px} ${2:solid} ${3:currentColor};
endsnippet
snippet bdt "border-top: ... ;"
border-top: ${1:1px} ${2:solid} ${3:currentColor};
endsnippet
snippet bdb "border-bottom: ... ;"
border-bottom: ${1:1px} ${2:solid} ${3:currentColor};
endsnippet
snippet bdl "border-left: ... ;"
border-left: ${1:1px} ${2:solid} ${3:currentColor};
endsnippet
snippet bdr "border-right: ... ;"
border-right: ${1:1px} ${2:solid} ${3:currentColor};
endsnippet
snippet br "border-radius: ... ;"
border-radius: ${1:50%};
endsnippet
snippet m "margin: ... ;"
margin: ${1:0};
endsnippet
snippet mt "margin-top: ... ;"
margin-top: ${1:0};
endsnippet
snippet mb "margin-bottom: ... ;"
margin-bottom: ${1:0};
endsnippet
snippet ml "margin-left: ... ;"
margin-left: ${1:0};
endsnippet
snippet mr "margin-right: ... ;"
margin-right: ${1:0};
endsnippet
snippet p "padding: ... ;"
padding: ${1:0};
endsnippet
snippet pt "padding-top: ... ;"
padding-top: ${1:0};
endsnippet
snippet pb "padding-bottom: ... ;"
padding-bottom: ${1:0};
endsnippet
snippet pl "padding-left: ... ;"
padding-left: ${1:0};
endsnippet
snippet pr "padding-right: ... ;"
padding-right: ${1:0};
endsnippet
snippet fs "font-size: ... ;"
font-size: ${1:1}${2:rem};
endsnippet
snippet fw "font-weight: ... ;"
font-weight: ${1:bold};
endsnippet
snippet o "opacity: ... ;"
opacity: ${1:0};
endsnippet
snippet grid "display: grid ..."
display: grid;
grid-template-columns: $1;
grid-template-rows: $0;
endsnippet
snippet gr "grid-row: ... ;"
grid-row: $0;
endsnippet
snippet gc "grid-column: ... ;"
grid-column: $0;
endsnippet
snippet rgbw "rgba( ... )"
rgba(${1:#fff}, ${2:0.5})
endsnippet
snippet rgbb "rgba( ... )"
rgba(${1:#000}, ${2:0.5})
endsnippet
snippet before "::before { ... }"
${1:&}::before {
content: '$2';
display: ${3:block};
position: ${4:absolute};
width: ${5:100%};
height: ${6:100%};
${7:top}: ${8:0};
${9:left}: ${10:0};
}
endsnippet
snippet after "::after { ... }"
${1:&}::after {
content: '$2';
display: ${3:block};
position: ${4:absolute};
width: ${5:100%};
height: ${6:100%};
${7:top}: ${8:0};
${9:left}: ${10:0};
}
endsnippet
snippet befaft "::before, ::after { ... }"
${1:&}::before {
$1::after {
content: '$2';
display: ${3:block};
position: ${4:absolute};
width: ${5:100%};
height: ${6:100%};
${7:top}: ${8:0};
${9:left}: ${10:0};
$0
}
endsnippet
snippet bs "box-shadow ...;"
box-shadow: ${1:0} ${2:0} $3px $4px ${5:#000} ${6:inset};
endsnippet
snippet pabs "Position: absolute ..."
position: absolute;
inset: 0;
endsnippet
snippet v "var(--...)"
var(--$0)
endsnippet
snippet ftscss "/* vim: set filetype=scss: */"
/* vim: set filetype=scss: */
endsnippet

View file

@ -1,3 +0,0 @@
snippet polycolor "${colors.color}"
\$\{colors.${1:foreground}}$0
endsnippet

View file

@ -1,3 +0,0 @@
snippet cldef "Colour definition"
$1 = ["#$2", $3, "$4"]
endsnippet

View file

@ -1,106 +0,0 @@
snippet html5 "HTML% boilerplate."
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge" />${2:
<link rel="stylesheet" href="${3:./assets/css/style.css}">}
<title>$1</title>
</head>
<body>$0 ${4:
<script src="${5:./assets/js/index.js}"></script>}
</body>
</html>
endsnippet
snippet option "<option value=..."
<option value="$1">${2:$1}</option>$0
endsnippet
snippet c "class= ... "
class="$1"$0
endsnippet
snippet plc "<img src='https://via.placeholder.it ..."
<img class="$1" src="https://via.placeholder.com/$2" alt="">
endsnippet
snippet tag "wrap with tag"
<$1$0>
${VISUAL}
</$1>
endsnippet
snippet tagi "wrap with tag inline"
<$1$0>${VISUAL}</$1>
endsnippet
snippet ftphp "<!-- vim: set filetype=php -->"
<!-- vim: set filetype=php: -->
endsnippet
snippet wp "<!-- wp:... {...}"
<!-- wp:$1 ${2:\{"$3":$4\}} -->
$0
<!-- /wp:$1 -->
endsnippet
snippet wp/ "<!-- wp:... {...}"
<!-- wp:$1 ${2:\{"$3":$4\}} /-->$0
endsnippet
snippet wp:spacer "<!-- wp:spacer ..."
<!-- wp:spacer {"height":$1} -->
<div style="height: $1px" aria-hidden="true" class="wp-block-spacer"></div>
<!-- /wp:spacer -->$0
endsnippet
snippet wp:heading "<!-- wp:heading {..."
<!-- wp:heading {"className":"$1"} -->
<h${2:2} class="$1">$3</h$2>
<!-- /wp:heading -->$0
endsnippet
snippet wp:comments "<!-- wp:comments-query-loop"
<!-- wp:comments-query-loop -->
<div class="wp-block-comments-query-loop">
<!-- wp:comment-template -->
<!-- wp:columns -->
<div class="wp-block-columns"><!-- wp:column \{"width":"40px"\} -->
<div class="wp-block-column" style="flex-basis:40px">
<!-- wp:avatar \{"size":40,"style":\{"border":\{"radius":"20px"\}\}\} /--></div>
<!-- /wp:column -->
<!-- wp:column -->
<div class="wp-block-column">
<!-- wp:comment-author-name /-->
<!-- wp:group \{"style":\{"spacing":\{"margin":\{"top":"0px","bottom":"0px"\}\}\},"layout":\{"type":"flex"\}\} -->
<div class="wp-block-group" style="margin-top:0px;margin-bottom:0px">
<!-- wp:comment-date /-->
<!-- wp:comment-edit-link /-->
</div>
<!-- /wp:group -->
<!-- wp:comment-content /-->
<!-- wp:comment-reply-link /-->
</div>
<!-- /wp:column --></div>
<!-- /wp:columns -->
<!-- /wp:comment-template -->
<!-- wp:comments-pagination -->
<!-- wp:comments-pagination-previous /-->
<!-- wp:comments-pagination-numbers /-->
<!-- wp:comments-pagination-next /-->
<!-- /wp:comments-pagination -->
</div>
<!-- /wp:comments-query-loop -->
endsnippet
snippet wp:comment-form "<!-- wp:post-comments-form"
<!-- wp:post-comments-form /-->
endsnippet

View file

@ -1,183 +0,0 @@
snippet todo "// TODO"
// TODO $0
endsnippet
snippet fn "function .."
function $1($2) {
$0
}
endsnippet
snippet if "if ( ... ) { ... }"
if ($1) {
$0
}
endsnippet
snippet cl "console.log( ... )"
console.log($0);
endsnippet
snippet cw "console.warn( ... )"
console.warn($0);
endsnippet
snippet f "for (...)"
for (let index=0; index < $1; index += 1) {
$0
}
endsnippet
snippet fr "for (...)"
for (let index=${1:0}; index ${2:<} $3; index ${4:+=} ${5:1}) {
$0
}
endsnippet
snippet .fe "...forEach( ... );" i
.forEach(($1) => {
$0
});
endsnippet
snippet wae "window.addEventListener( ... );"
window.addEventListener('$1', ($2) => {
$0
});
endsnippet
snippet .ael "...addEventListener( ... );" i
.addEventListener('$1', ($2) => {
$0
});
endsnippet
snippet st "setTimeout( ... )"
setTimeout(() => {$0
}, ${1:1000});
endsnippet
snippet dq "document.querySelector( ... )"
document.querySelector($0)
endsnippet
snippet dqa "document.querySelectorAll( ... )"
document.querySelectorAll($0)
endsnippet
snippet cdq "const ... = document.querySelector( ... )"
const $1 = document.querySelector($0);
endsnippet
snippet cdqa "const ... = document.querySelectorAll( ... )"
const $1 = document.querySelectorAll($0);
endsnippet
snippet jsx "import React ..."
import * as React from "react";${1:
import { css } from "@emotion/react";}
const `!p snip.rv = snip.basename` = ($2) => {
return (
<div>$0
</div>
);
};
export default `!p snip.rv = snip.basename`;
endsnippet
snippet isi "import { StaticImage } ..."
import { StaticImage } from "gatsby-plugin-image";
endsnippet
snippet simg "<StaticImage ... />"
<StaticImage src="$1" alt="$2" />$0
endsnippet
snippet st. "styled."
const $1 = styled.${2:div}\`
$0
\`;
endsnippet
snippet icss "import ... from ..."
import \{ css \} from "@emotion/react";
endsnippet
snippet ccs "const ..Css=css``"
const $1Css = css\`
$0
\`;
endsnippet
snippet cse "css={css``}"
css={css\`$0\`}
endsnippet
snippet css "css={..Css}"
css={$0Css}
endsnippet
snippet th "this.handle..."
this.handle${1:Click} = this.handle$1.bind(this);
endsnippet
snippet tb "this ... = ... .bind(this);"
this.$1 = this.$1.bind(this);
endsnippet
snippet wprb
import { registerBlockType } from '@wordpress/blocks';
const blockStyle = {
color: red,
backgroundColor: pink,
};
registerBlockType( '${1:namespace}/${2:block-name}', {
title: '$3',
icon: '${4:universal-access-alt}',
category: '${5:layout}',
example: {},
edit( { className } ) {
return <div className={ className }>Hello World, step 1 (from the editor).</div>;
},
save() {
return <div style={ blockStyle }>Hello World, step 1 (from the frontend).</div>;
},
} );
endsnippet
snippet rtw "React + twin.macro"
import * as React from "react"
import 'twin.macro'
const `!p snip.rv = snip.basename` = ({ children }) => {
return (
<$1 tw="$0">
{children}
</$1>
)
}
export default `!p snip.rv = snip.basename`
endsnippet
snippet ue "useEffect(() => {"
useEffect(() => {
$0
}, ${1:[]});
endsnippet
snippet ule "useLayoutEffect(() => {"
useLayoutEffect(() => {
$0
}, ${1:[]});
endsnippet
snippet imp "import ... from ..."
import $1 from "${2:.}/$1";
endsnippet

View file

@ -1 +0,0 @@
extends css, javascript

View file

@ -1,33 +0,0 @@
extends html
snippet com "{# .. #}"
{# $0 #}
endsnippet
snippet import "{% import ... %}"
{% import "$1" as $2 %}
endsnippet
snippet macro "{% macro ...%}"
{% macro $1(${2:$3="$4"}) %}
$0
{% endmacro %}
endsnippet
snippet blockin "{% block .. %}"
{% block $1 %}$0{% endblock %}
endsnippet
snippet block "{% block .. %}"
{% block $1 %}
$0
{% endblock %}
endsnippet
snippet include "{% include .. %}"
{% include "$0" %}
endsnippet
snippet extends "{% extends .. %}"
{% extends "$0" %}
endsnippet

View file

@ -1,19 +0,0 @@
snippet req "<%- require( ..."
<%- require('!!ejs-compiled-loader?{}!./$1.ejs')($0) %>
endsnippet
snippet % "<% ... %>"
<% $0 %>
endsnippet
snippet = "<= ... =>"
<%= $0 %>
endsnippet
snippet - "<- ... ->"
<%- $0 %>
endsnippet
snippet # "<# ... #>"
<%# $0 %>
endsnippet

View file

@ -1,83 +0,0 @@
snippet l "[...](...)"
[${1:title}](${2:url})$0
endsnippet
snippet c "``` ..."
\`\`\`$0
\`\`\`
endsnippet
# latex
snippet vec "vector 1x2" i
\\begin{bmatrix} $1 \\\\ $2 \\end{bmatrix}$0
endsnippet
snippet vec3 "vector 1x3" i
\\begin{bmatrix} $1 \\\\ $2 \\\\ $3 \\end{bmatrix}$0
endsnippet
snippet mx "matrix 2x2" i
\\begin{bmatrix} $1 & $2 \\\\ $3 & $4 \\end{bmatrix}$0
endsnippet
snippet mx3 "matrix 3x3" i
\\begin{bmatrix} $1 & $2 & $3 \\\\ $4 & $5 & $6 \\\\ $7 & $8 & $9 \\end{bmatrix}$0
endsnippet
snippet lim "limit" i
\\lim{$1 \\to $2}$0
endsnippet
snippet sum "sum" i
\\sum_{$1}^{$2}$0
endsnippet
snippet fr "fraction" i
\\frac{$1}{$2}$0
endsnippet
snippet sq "square root" i
\\sqrt{$1}$0
endsnippet
snippet rt "root" i
\\sqrt[${1:3}]{${2:x}}$0
endsnippet
snippet br "{}" i
\\lbrace $1 \\rbrace$0
endsnippet
snippet | "|...|"
\\lvert $1 \\rvert$0
endsnippet
snippet || "|...|"
\\lVert $1 \\rVert$0
endsnippet
snippet ds "displaystyle" i
\\displaystyle$0
endsnippet
snippet lmb "lambda" i
\\lambda$0
endsnippet
snippet imp "implies" i
\\Rightarrow
endsnippet
snippet int "integral" i
\\int_{$1}^{$2} $0
endsnippet
snippet web "web snippet"
[$1]($2)
\`\`\`
$3
\`\`\`
---$0
endsnippet

View file

@ -1,3 +0,0 @@
snippet pl "{% partial ... %}"
{% partial "$0" %}
endsnippet

View file

@ -1,95 +0,0 @@
extends html
snippet doc "/**"
/**
* $1
*/$0
endsnippet
snippet pre "<pre>print_r()</pre>"
echo "<pre>";
print_r($0);
echo "</pre>";
endsnippet
snippet if "if () {}"
if ($1) {
$0
}
endsnippet
snippet fe "foreach () {}"
foreach (\$${1:array} as \$${2:item}) {
$0
}
endsnippet
snippet pp "<?php ... ?>"
<?php $0; ?>
endsnippet
snippet pe "<?php ... ?>"
<?php echo "$0"; ?>
endsnippet
snippet ph "<?php ... ?>"
<?php esc_html( $0 ); ?>
endsnippet
snippet pf "public function ..."
public function $1($2) {
$0
}
endsnippet
snippet pt "protected function ..."
protected function $1($2) {
$0
}
endsnippet
snippet pv "private function ..."
private function $1($2) {
$0
}
endsnippet
snippet psf "public static function ..."
public static function $1($2) {
$0
}
endsnippet
snippet prsf "public static function ..."
private static function $1($2) {
$0
}
endsnippet
snippet ''= "'...' => "
'$1' => $0,
endsnippet
snippet apm "add_post_meta(..."
add_post_meta( ${1:2720}, '__DEBUG__$2', $0);
endsnippet
snippet upm "update_post_meta(..."
update_post_meta( ${1:2720}, '__DEBUG__$1', $0);
endsnippet
snippet sw "switch ..."
switch ($1) {
case $2:
$3;
break;
default:
$0
}
endsnippet
snippet cs "case ..."
case $1:
$0;
break;
endsnippet

View file

@ -1,19 +0,0 @@
snippet qxconfig "qutebrowser xResources config"
c.colors.messages.$1 = xresources['*${2:background}']$0
endsnippet
snippet main "if __name__ == .."
def main():
$0
if __name__ == "__main__":
main()
endsnippet
snippet ld "logger.debug()"
logger.debug("$1".format($2))
endsnippet
snippet li "logger.info()"
logger.info("$1".format($2))
endsnippet

View file

@ -1,49 +0,0 @@
extends css
snippet @i "@include"
@include $0;
endsnippet
snippet imt "@include margin-t( <top> );"
@include margin-t(${0:1});
endsnippet
snippet imb "@include margin-b( <bottom> );"
@include margin-b(${0:1});
endsnippet
snippet imv "@include margin-v( <top>, <bottom> );"
@include margin-v($0);
endsnippet
snippet im "@include margin( <top>, <bottom>, <left>, <right> );"
@include margin($0);
endsnippet
snippet ipt "@include pad-t( <top> );"
@include pad-t(${0:1});
endsnippet
snippet ipb "@include pad-b( <bottom> );"
@include pad-b(${0:1});
endsnippet
snippet iph "@include pad-v( <left>, <right> );"
@include pad-h($0);
endsnippet
snippet ipv "@include pad-v( <top>, <bottom> );"
@include pad-v($0);
endsnippet
snippet ipl "@include pad-l( <left> );"
@include pad-l(${0:1});
endsnippet
snippet ipr "@include pad-r( <right> );"
@include pad-r(${0:1});
endsnippet
snippet ip "@include pad( <top>, <bottom>, <left>, <right> );"
@include pad($0);
endsnippet

View file

@ -1,3 +0,0 @@
snippet polybashcolor "%{{F{color}}}" i
%\{\{F\{color${1:4}}}}
endsnippet

View file

@ -1,7 +0,0 @@
snippet scolor "SetColor('', .."
SetColor('$1', '$2', '$3', '$4', '$5', '$6')$0
endsnippet
snippet cscolor "call SetColor('', .."
call SetColor('$1', '$2', '$3', '$4', '$5', '$6')$0
endsnippet

View file

@ -1,154 +0,0 @@
extends html, javascript, scss
snippet vue "Default template"
<template>
$0
</template>
<script>
export default {
props: {
},
data () {
return {
}
},
methods: {
}
}
</script>
<style lang="scss" scoped>
</style>
endsnippet
snippet byinput "Beufy Input Field"
<div class="field"> <!-- $1 -->
<label class="label">$1</label>
<div class="control">
<input class="input"
name="$2"
${3:type="${4:text}"}
v-model="${5:$2}">
</div>
</div>$0
endsnippet
snippet byselect "Buefy Select Field"
<div class="field"> <!-- $1 -->
<label class="label">$1</label>
<div class="control">
<div class="select">
<select name="$2"
:v-model="$2">
$0
</select>
</div>
</div>
</div>
endsnippet
snippet nt "this.$nextTick( () => { ... })"
this.$nextTick( () => {
$0
})
endsnippet
snippet props "props: { ... }"
props: {
$1: {
type: ${2:Boolean},
required: ${3:false},
default() {
return ${4:false};
},
},
},$0
endsnippet
snippet prop "property: { ... }"
$1: {
type: ${2:Boolean},
required: ${3:false},
default() {
return ${4:false};
},
},$0
endsnippet
snippet comps "components { ... }"
components: {
$0,
},
endsnippet
snippet data "data() { return { ... } }"
data() {
return {
$1: $2,$0
};
},
endsnippet
snippet compd "computed: { ... }"
computed: {
$1() {
$0
},
},
endsnippet
snippet meth "methods: { ... }"
methods: {
$1() {
$0
},
},
endsnippet
snippet style "<style ..."
<style ${1:lang="${2:scss}"} ${3:scoped}>
$0
</style>
endsnippet
snippet impc "import ... from '~/components...';"
import $1 from '~/components/$1';$0
endsnippet
snippet tran "<transition ..."
<transition name="$1">
${VISUAL}$0
</transition>
endsnippet
snippet .tran "vue transition selector"
.$1 {
&-enter-active {
transition: ${2:opacity} ${3:1}s;
}
&-leave-active {
transition: $2 ${4:1}s;
}
&-enter,
&-leave-to {
$2: ${5:0};
}
}$0
endsnippet
snippet script "<script> ...</script>"
<script>
export default {
name: '$0',
};
</script>
endsnippet
snippet s ":style='{ ... }"
:style="{ '$1': $2 }"$0
endsnippet

View file

@ -1,44 +0,0 @@
// ESLint 9+ flat config format (global default)
// See: https://eslint.org/docs/latest/use/configure/configuration-files
export default [
{
files: ["**/*.js", "**/*.mjs", "**/*.cjs"],
languageOptions: {
ecmaVersion: "latest",
sourceType: "module",
globals: {
// Browser globals
console: "readonly",
window: "readonly",
document: "readonly",
navigator: "readonly",
// Node.js globals
process: "readonly",
__dirname: "readonly",
__filename: "readonly",
require: "readonly",
module: "readonly",
exports: "readonly",
global: "readonly",
Buffer: "readonly",
},
},
rules: {
// Recommended rules
"no-undef": "error",
"no-unused-vars": "warn",
"no-unreachable": "warn",
"no-constant-condition": "error",
"no-duplicate-case": "error",
// Best practices
"eqeqeq": ["warn", "always"],
"no-implicit-globals": "warn",
// Style (minimal)
"semi": ["warn", "always"],
"quotes": ["warn", "double", { "avoidEscape": true }],
},
},
];

View file

@ -12,8 +12,8 @@
"nvim-lint": { "branch": "master", "commit": "f6230a5c06ba59e6059c14637f1dbe29a7978b9b" },
"nvim-lspconfig": { "branch": "master", "commit": "3bccb6fa49a3a75bfb6d92fed63b13a71a85cfaf" },
"nvim-surround": { "branch": "main", "commit": "2e93e154de9ff326def6480a4358bfc149d5da2c" },
"nvim-treesitter": { "branch": "master", "commit": "cf12346a3414fa1b06af75c79faebe7f76df080a" },
"nvim-treesitter-textobjects": { "branch": "master", "commit": "5ca4aaa6efdcc59be46b95a3e876300cfead05ef" },
"nvim-treesitter": { "branch": "main", "commit": "a2f694478be07f89c2d03cc17858a8745a400c4b" },
"nvim-treesitter-textobjects": { "branch": "main", "commit": "5c7b0263797dfd1bd6202f2b219f3b53a80b2187" },
"nvim-ts-autotag": { "branch": "main", "commit": "d7220b55e16ed3c04e88086256def5d282429493" },
"nvim-ufo": { "branch": "main", "commit": "ab3eb124062422d276fae49e0dd63b3ad1062cfc" },
"plenary.nvim": { "branch": "master", "commit": "74b06c6c75e4eeb3108ec01852001636d85a932b" },

View file

@ -1,21 +0,0 @@
# Legacy Neovim Config Archive
This folder contains the previous Neovim/Vimscript configuration and related files, archived during Phase 1 of the migration. Nothing here should be modified; use it only as historical reference.
Archived on: 2025-12-06
## Contents archived
- Directories: `after/`, `autoload/`, `bundle/`, `colors/`, `ftdetect/`, `ftplugin/`, `lua/`, `tmpdir/`
- Files: `init.auto-window.vim`, `init.commands.vim`, `init.fold-text.vim`, `init.full.vim`, `init.plugins.vim`, `init.tabline.vim`, `init.vim`, `init.vscode.vim`, `Session.ts.vim`, `Session.vim`, `postcss.config.js`, `.netrwhist`, `.tags`
## Kept in place (not archived)
- `undodir/`, `spell/`, `view/`, `UltiSnips/`, `templates/`
- Repo metadata: `.git/`, `.gitignore`
- Migration docs: `AGENTS.md`, `MIGRATION_PLAN.md`, `neovim-migration-guide.md`
## Notes
- The archived `.netrwhist` is historical runtime state; the modern configuration uses netrw for project browsing.
- Colors and Vimscript `after/` settings were archived to avoid runtimepath collisions with the new config.
- The old `lua/` directory was archived to ensure a clean rebuild of the Lua modules using the new structure and lazy.nvim.
- The old `.vimtmp/` backup directory was retired during Phase 12. It contained transient copies of files from across the home directory and was not useful migration reference material.
- The broken `paper-tonic-original` symlink was retired after the replacement colorscheme was incorporated directly into this repository.

View file

@ -1,149 +0,0 @@
let SessionLoad = 1
let s:so_save = &g:so | let s:siso_save = &g:siso | setg so=0 siso=0 | setl so=-1 siso=-1
let v:this_session=expand("<sfile>:p")
silent only
silent tabonly
cd ~/.config/nvim
if expand('%') == '' && !&modified && line('$') <= 1 && getline(1) == ''
let s:wipebuf = bufnr('%')
endif
set shortmess=aoO
badd +36 init.tabline.vim
badd +22 init.auto-window.vim
badd +1 coc-settings.json
badd +184 init.vim
badd +1 ftplugin/php.vim
badd +2 after/ftplugin/php.vim
badd +1 after/ftplugin/html.vim
badd +1 after/ftplugin/javascript.vim
badd +8 after/ftplugin/python.vim
badd +1 after/ftplugin/sass.vim
badd +1 after/ftplugin/vim.vim
badd +1 ftplugin/vue.vim
badd +1 ftplugin/sass.vim
badd +1 ftplugin/javascript.vim
badd +1 ftplugin/css.vim
badd +50 init.plugins.vim
badd +1 after/indent/php.vim
badd +10 init.commands.vim
badd +7 lua/init-plugins.lua
badd +1 after/queries/ecma/highlights.scm
badd +16 after/queries/html/highlights.scm
badd +2 after/queries/css/highlights.scm
argglobal
%argdel
$argadd init.tabline.vim
edit after/queries/css/highlights.scm
let s:save_splitbelow = &splitbelow
let s:save_splitright = &splitright
set splitbelow splitright
wincmd _ | wincmd |
vsplit
1wincmd h
wincmd _ | wincmd |
split
1wincmd k
wincmd w
wincmd w
let &splitbelow = s:save_splitbelow
let &splitright = s:save_splitright
wincmd t
let s:save_winminheight = &winminheight
let s:save_winminwidth = &winminwidth
set winminheight=0
set winheight=1
set winminwidth=0
set winwidth=1
exe '1resize ' . ((&lines * 22 + 25) / 50)
exe 'vert 1resize ' . ((&columns * 103 + 105) / 211)
exe '2resize ' . ((&lines * 22 + 25) / 50)
exe 'vert 2resize ' . ((&columns * 103 + 105) / 211)
exe 'vert 3resize ' . ((&columns * 107 + 105) / 211)
argglobal
balt after/queries/html/highlights.scm
setlocal fdm=indent
setlocal fde=0
setlocal fmr={{{,}}}
setlocal fdi=#
setlocal fdl=99
setlocal fml=1
setlocal fdn=9
setlocal fen
let s:l = 3 - ((2 * winheight(0) + 11) / 22)
if s:l < 1 | let s:l = 1 | endif
keepjumps exe s:l
normal! zt
keepjumps 3
normal! 023|
lcd ~/.config/nvim
wincmd w
argglobal
if bufexists("/usr/share/nvim/runtime/doc/treesitter.txt") | buffer /usr/share/nvim/runtime/doc/treesitter.txt | else | edit /usr/share/nvim/runtime/doc/treesitter.txt | endif
if &buftype ==# 'terminal'
silent file /usr/share/nvim/runtime/doc/treesitter.txt
endif
setlocal fdm=manual
setlocal fde=0
setlocal fmr={{{,}}}
setlocal fdi=#
setlocal fdl=99
setlocal fml=1
setlocal fdn=9
setlocal nofen
silent! normal! zE
let &fdl = &fdl
let s:l = 196 - ((5 * winheight(0) + 11) / 22)
if s:l < 1 | let s:l = 1 | endif
keepjumps exe s:l
normal! zt
keepjumps 196
normal! 050|
lcd ~/.config/nvim
wincmd w
argglobal
if bufexists("~/.config/nvim/after/indent/php.vim") | buffer ~/.config/nvim/after/indent/php.vim | else | edit ~/.config/nvim/after/indent/php.vim | endif
if &buftype ==# 'terminal'
silent file ~/.config/nvim/after/indent/php.vim
endif
setlocal fdm=marker
setlocal fde=0
setlocal fmr={{{,}}}
setlocal fdi=#
setlocal fdl=99
setlocal fml=1
setlocal fdn=9
setlocal fen
let s:l = 4 - ((3 * winheight(0) + 22) / 45)
if s:l < 1 | let s:l = 1 | endif
keepjumps exe s:l
normal! zt
keepjumps 4
normal! 03|
lcd ~/.config/nvim
wincmd w
exe '1resize ' . ((&lines * 22 + 25) / 50)
exe 'vert 1resize ' . ((&columns * 103 + 105) / 211)
exe '2resize ' . ((&lines * 22 + 25) / 50)
exe 'vert 2resize ' . ((&columns * 103 + 105) / 211)
exe 'vert 3resize ' . ((&columns * 107 + 105) / 211)
if exists(':tcd') == 2 | tcd ~/.config/nvim | endif
tabnext 1
if exists('s:wipebuf') && len(win_findbuf(s:wipebuf)) == 0&& getbufvar(s:wipebuf, '&buftype') isnot# 'terminal'
silent exe 'bwipe ' . s:wipebuf
endif
unlet! s:wipebuf
set winheight=1 winwidth=20 shortmess=aoOT
let &winminheight = s:save_winminheight
let &winminwidth = s:save_winminwidth
let s:sx = expand("<sfile>:p:r")."x.vim"
if filereadable(s:sx)
exe "source " . fnameescape(s:sx)
endif
let &g:so = s:so_save | let &g:siso = s:siso_save
set hlsearch
let g:this_session = v:this_session
let g:this_obsession = v:this_session
let g:this_obsession_status = 2
doautoall SessionLoadPost
unlet SessionLoad
" vim: set ft=vim :

View file

@ -1 +0,0 @@
nmap <buffer> q :q<CR>

View file

@ -1 +0,0 @@
setlocal foldnestmax=5

View file

@ -1,107 +0,0 @@
" https://gist.github.com/romainl/1f50c55b0ee92e5420de51e6c4b38491
nnoremap <silent> <space>cF :call CocAction('runCommand', 'eslint.executeAutofix')<CR>
setlocal includeexpr=RESOLVE(v:fname)
function! RESOLVE(module) abort
let built_ins = [
\ "assert",
\ "async_hooks",
\ "child_process",
\ "cluster",
\ "crypto",
\ "dns",
\ "domain",
\ "events",
\ "fs",
\ "http",
\ "http2",
\ "https",
\ "inspector",
\ "net",
\ "os",
\ "path",
\ "perf_hooks",
\ "punycode",
\ "querystring",
\ "readline",
\ "stream",
\ "string_decoder",
\ "tls",
\ "tty",
\ "dgram",
\ "url",
\ "util",
\ "v8",
\ "vm",
\ "zlib" ]
" There's no source file for built-in node modules.
" Example: var http = require('http');
if index(built_ins, a:module) != -1
return 0
endif
" Handling absolute and relative paths.
" Example: var foo = require('./foo.js');
if a:module =~ '^\/' || a:module =~ '^\.\{1,2}\/'
let root = fnamemodify(substitute(finddir("node_modules", ".;"), '/node_modules', '', ''), ':p:h:h')
if a:module =~ '^\.\{1,2}\/'
let module = substitute(a:module, '^\.\{1,2}\/', '', '')
endif
let filename = 0
try
let filename = findfile(module, root)
catch
try
let filename = findfile(module . ".js", root)
catch
try
let filename = findfile(module . "/index.js", root)
catch
let filename = 0
endtry
endtry
endtry
return filename
endif
" Handling vendored-in modules.
" Example: var _ = require('lodash');
for dir in NODE_MODULES_PATHS()
" require('module') => node_modules/module/package.json#main => node_modules/module/**/...
if filereadable(dir . "/" . a:module . "/package.json")
let package = json_decode(join(readfile(dir . "/" . a:module . "/package.json")))
return dir . "/" . a:module . "/" . substitute(get(package, "main", "index.js"), '^\.\{1,2}\/', '', '')
endif
" require('module') => node_modules/module/index.js
if filereadable(dir . "/" . a:module . "/index.js")
return dir . "/" . a:module . "/index.js"
endif
" require('module') => node_modules/module.js
if filereadable(dir . "/" . a:module . ".js")
return dir . "/" . a:module . ".js"
endif
endfor
" well, well, well
return 0
endfunction
function! NODE_MODULES_PATHS() abort
" node_modules/
let node_modules = finddir("node_modules", ".;")
" node_modules/foo/node_modules/
let basic_dirs = extend([node_modules], globpath(node_modules, "*/node_modules", 1, 1))
" node_modules/@foo/bar/node_modules/
let all_dirs = extend(basic_dirs, globpath(node_modules, "@*/*/node_modules", 1, 1))
return all_dirs
endfunction

View file

@ -1 +0,0 @@
setl bufhidden=hide

View file

@ -1,2 +0,0 @@
setlocal iskeyword+=$
setlocal autoindent

View file

@ -1,11 +0,0 @@
setlocal tabstop=4
setlocal textwidth=88
setlocal foldmethod=indent
setlocal foldnestmax=1
setlocal colorcolumn=88
noremap <F4> :w<CR>:silent !clear;python %<CR> :redraw!<CR>
nnoremap <silent> <buffer> <F5> :call SaveAndExecute('python')<CR>

View file

@ -1,2 +0,0 @@
nmap <buffer> o <CR>
nmap <buffer> q :q<CR>

View file

@ -1 +0,0 @@
setlocal includeexpr=substitute(substitute(substitute(v:fname,'\%(.*/\|^\)\zs','_',''),'^[\\~@]\/','./',''),'^[\\~@]','./node_modules/','')

View file

@ -1,2 +0,0 @@
setlocal foldmethod=marker

View file

@ -1,4 +0,0 @@
" https://github.com/nvim-treesitter/nvim-treesitter/issues/462#issuecomment-700278736
setlocal indentexpr =
setlocal autoindent
setlocal smartindent

View file

@ -1,18 +0,0 @@
(id_selector (id_name) @CssIdentifier)
(id_selector (id_name)) @CssIdSelector
(tag_name) @HtmlTagName
(class_selector (class_name) @CssClassName)
(selectors (pseudo_class_selector (class_name) @cssPseudoClass))
(nesting_selector) @cssNestingSelector
; need to find out how to make this more specific?
(universal_selector) @CssUniversalSelector
((property_name) (_)) @CssProp
(unit) @CssUnit
(declaration (property_name) (_) @CssPropertyValue)
(media_statement (feature_query (feature_name) @cssMediaFeatureName (_ (unit) @cssMediaQueryValueUnit) @cssMediaQueryValue) @cssMediaQuery)

View file

@ -1,17 +0,0 @@
(start_tag
(attribute
(attribute_name) @ClassNameAttribute (#eq? @ClassNameAttribute "class")
(quoted_attribute_value
(attribute_value) @CssClassName )))
(start_tag
(attribute
(attribute_name) @IdAttribute (#eq? @IdAttribute "id")
(quoted_attribute_value
(attribute_value) @CssIdentifier )))
(start_tag
(attribute
(attribute_name) @DataAttribute (#match? @DataAttribute "^data-")
(quoted_attribute_value
(attribute_value) @DataAttributeValue )))

View file

@ -1,79 +0,0 @@
README.txt for color scheme files
These files are used for the ":colorscheme" command. They appear in the
Edit/Color Scheme menu in the GUI.
Hints for writing a color scheme file:
There are two basic ways to define a color scheme:
1. Define a new Normal color and set the 'background' option accordingly.
set background={light or dark}
highlight clear
highlight Normal ...
...
2. Use the default Normal color and automatically adjust to the value of
'background'.
highlight clear Normal
set background&
highlight clear
if &background == "light"
highlight Error ...
...
else
highlight Error ...
...
endif
You can use ":highlight clear" to reset everything to the defaults, and then
change the groups that you want differently. This also will work for groups
that are added in later versions of Vim.
Note that ":highlight clear" uses the value of 'background', thus set it
before this command.
Some attributes (e.g., bold) might be set in the defaults that you want
removed in your color scheme. Use something like "gui=NONE" to remove the
attributes.
In case you want to set 'background' depending on the colorscheme selected,
this autocmd might be useful:
autocmd SourcePre */colors/blue_sky.vim set background=dark
Replace "blue_sky" with the name of the colorscheme.
In case you want to tweak a colorscheme after it was loaded, check out the
ColorScheme autocmd event.
To customize a colorscheme use another name, e.g. "~/.vim/colors/mine.vim",
and use `:runtime` to load the original colorscheme:
" load the "evening" colorscheme
runtime colors/evening.vim
" change the color of statements
hi Statement ctermfg=Blue guifg=Blue
To see which highlight group is used where, find the help for
"highlight-groups" and "group-name".
You can use ":highlight" to find out the current colors. Exception: the
ctermfg and ctermbg values are numbers, which are only valid for the current
terminal. Use the color names instead. See ":help cterm-colors".
The default color settings can be found in the source file src/syntax.c.
Search for "highlight_init".
If you think you have a color scheme that is good enough to be used by others,
please check the following items:
- Does it work in a color terminal as well as in the GUI?
- Is "g:colors_name" set to a meaningful value? In case of doubt you can do
it this way:
let g:colors_name = expand('<sfile>:t:r')
- Is 'background' either used or appropriately set to "light" or "dark"?
- Try setting 'hlsearch' and searching for a pattern, is the match easy to
spot?
- Split a window with ":split" and ":vsplit". Are the status lines and
vertical separators clearly visible?
- In the GUI, is it easy to find the cursor, also in a file with lots of
syntax highlighting?
- Do not use hard coded escape sequences, these will not work in other
terminals. Always use color names or #RRGGBB for the GUI.

View file

@ -1 +0,0 @@
autocmd BufRead,BufEnter *.astro set filetype=astro

View file

@ -1 +0,0 @@
setlocal iskeyword+=-

View file

@ -1,2 +0,0 @@
nnoremap <buffer> <F5> :call ft#compileeruby#CompileEruby(0)<CR>
nnoremap <buffer> <F6> :call ft#compileeruby#CompileEruby(1)<CR>

View file

@ -1 +0,0 @@
:compiler fish

View file

@ -1 +0,0 @@
setlocal keywordprg=:help

View file

@ -1 +0,0 @@
setlocal iskeyword+=$

View file

@ -1,20 +0,0 @@
setlocal spell
" markdown : jump to next heading
" https://gist.github.com/romainl/ac63e108c3d11084be62b3c04156c263
function! s:JumpToNextHeading(direction, count)
let col = col(".")
silent execute a:direction == "up" ? '?^#' : '/^#'
if a:count > 1
silent execute "normal! " . repeat("n", a:direction == "up" && col != 1 ? a:count : a:count - 1)
endif
silent execute "normal! " . col . "|"
unlet col
endfunction
nnoremap <buffer> <silent> ]] :<C-u>call <SID>JumpToNextHeading("down", v:count1)<CR>
nnoremap <buffer> <silent> [[ :<C-u>call <SID>JumpToNextHeading("up", v:count1)<CR>

View file

@ -1,8 +0,0 @@
function! StripSpecialM() abort
:%s/ $//e
endfunction
augroup RemoveSpecialM
autocmd BufWritePre <buffer> call StripSpecialM()
augroup END

View file

@ -1,2 +0,0 @@
nnoremap <silent> <buffer> <F5> :call SaveAndExecute('ruby')<CR>

View file

@ -1 +0,0 @@
setlocal iskeyword+=$

View file

@ -1,2 +0,0 @@
setlocal makeprg=shellcheck\ -f\ gcc\ %
nnoremap <buffer> <F5> :w !sh<cr>

View file

@ -1,4 +0,0 @@
setlocal keywordprg=:help
setlocal iskeyword+=:
nnoremap <buffer> <F5> :w \| source %<cr>

View file

@ -1,8 +0,0 @@
setlocal includeexpr=substitute(substitute(v:fname,'^[\\~@]\/','./',''),'^[\\~@]','./node_modules/','')
setlocal suffixesadd=.js,.vue,.scss
setlocal complete=.,w,b,u,i
setlocal include=\\%(\\<require\\s*(\\s*\\\|\\<import\\>[^;\"']*\\)[\"']\\zs[^\"']*
setlocal foldnestmax=3

View file

@ -1,34 +0,0 @@
"auto_window_settings {{{
function! OnWinEnter() abort"{{{
if &buftype != ''
setlocal colorcolumn=0
elseif exists('b:colorcolumn_restore')
execute 'setlocal colorcolumn=' . b:colorcolumn_restore
endif
if &buftype == 'terminal'
setlocal nonumber norelativenumber
else
setlocal number relativenumber
endif
setlocal cursorline
setlocal cursorcolumn
endfunction
"}}}
function! OnWinLeave() abort"{{{
let b:colorcolumn_restore = &colorcolumn
setlocal colorcolumn=0
setlocal nocursorline
setlocal nocursorcolumn
setlocal norelativenumber
endfunction
"}}}
augroup auto_window_settings "{{{
autocmd!
autocmd WinEnter * call OnWinEnter()
autocmd WinLeave * call OnWinLeave()
augroup END
"}}} augroup auto_window_settings
" }}} auto_window_settings

View file

@ -1,27 +0,0 @@
" SpacesToTabs {{{
" TODO - ake a proper regex substitution
function! s:spacestotabs()
%s/^ / /e
%s/^ / /e
%s/^ / /e
%s/^ / /e
%s/^ / /e
%s/^ / /e
endfunction
command SpacesToTabs call s:spacestotabs()
"}}}
" TrimWhitespace {{{
command! -range=% TrimWhitespace let b:wv = winsaveview() |
\ keeppattern <line1>,<line2>s/\s\+$// |
\ call winrestview(b:wv)
"}}}
" Scratch, ScratchVertical {{{
command! Scratch new | setlocal buftype=nofile | setlocal bufhidden=hide | setlocal noswapfile
command! ScratchVertical vnew | setlocal buftype=nofile | setlocal bufhidden=hide | setlocal noswapfile
"}}}
"
"

View file

@ -1,52 +0,0 @@
function! MyFoldText()
if !exists('g:foldtext_column')
let g:foldtext_column = 80 " column to right align foldtext with
endif
if !exists('b:foldtext_column')
let b:foldtext_column = g:foldtext_column " column to right align foldtext with
endif
if !exists('g:foldtext_maxcolumn')
let g:foldtext_maxcolumn = 120
endif
let l:linecount = v:foldend - v:foldstart
" don't display foldmarker braces
" put one of the braces in brackets so vim doesn't treat
" it as an actual fold marker
let l:line = substitute(getline(v:foldstart), '"\?{\({\){', '', '')
" don't display vim comment quotation marks
" TODO other comment markers
let l:line = substitute(l:line, "\^\"\\s\\?", '', '')
" TODO replace spaces with tabs if appropriate
" replace tabs with spaces if expandtab
if &expandtab == 0
let l:tabwidth = &tabstop
let l:tabspace = ' '[1:l:tabwidth]
let l:line = substitute(l:line, ' ', l:tabspace, 'g')
endif
" let l:postfix = l:linecount . ' ' . substitute(v:folddashes, '-', '•', 'g')
let l:postfix = l:linecount . ' ' . substitute(v:folddashes, '-', '↓', 'g')
while strchars(l:postfix) < 7
let l:postfix = ' ' . l:postfix
endwhile
" let l:postfix = ' ↓ ' . l:postfix
let l:len_line = len(l:line)
let l:len_postfix = strchars(l:postfix)
if l:len_line + l:len_postfix <= b:foldtext_column
let l:padding = ' '[l:len_line + l:len_postfix + 0:b:foldtext_column - 1]
let l:foldtext = l:line . l:padding . l:postfix
else
let l:sniptext = ' ⋯'
let l:foldtext = l:line[:b:foldtext_column - 1 - strchars(l:sniptext) - l:len_postfix] . l:sniptext . l:postfix
endif
return l:foldtext
endfunction
set foldtext=MyFoldText()

View file

@ -1,434 +0,0 @@
" set ruby program to global one. Need to investigate if this will cause
" problems if I ever use ruby virtual environments or RVM or similar.
let g:ruby_host_prog = '~/.gem/ruby/2.7.0/bin/neovim-ruby-host'
source ~/.config/nvim/init.plugins.vim
source ~/.config/nvim/init.tabline.vim
source ~/.config/nvim/init.auto-window.vim
source ~/.config/nvim/init.fold-text.vim
source ~/.config/nvim/init.commands.vim
"
" require lua init modules
lua <<EOF
-- require('init-lsp')
EOF
" TODO - maybe separate some of these into own files too
" #functions {{{
function! <SID>SynStack()"{{{
if !exists('*synstack')
return
endif
echo map(synstack(line('.'), col('.')), 'synIDattr(v:val,"name")') '-> ' . synIDattr(synIDtrans(synID(line('.'),col('.'),1)), 'name' )
endfunc
" nmap <space>pp :call <SID>SynStack()<CR>
nmap <silent><space>pp :TSHighlightCapturesUnderCursor<CR>
"}}}
function! s:RunShellCommand(cmdline) abort"{{{
" Shell command
" http://vim.wikia.com/wiki/VimTip1599
let l:expanded_cmdline = a:cmdline
for l:part in split(a:cmdline, ' ')
if l:part[0] =~ '\v[%#<]'
let l:expanded_part = fnameescape(expand(l:part))
let l:expanded_cmdline = substitute(l:expanded_cmdline, l:part, l:expanded_part, '')
endif
endfor
if g:shell_scratch_buffer_nr > -1
let l:win_nr = bufwinnr(g:shell_scratch_buffer_nr)
if l:win_nr < 0
execute 'bdelete' g:shell_scratch_buffer_nr
top new
let g:shell_scratch_buffer_nr = bufnr('%')
else
execute l:win_nr. ' wincmd w'
setlocal modifiable
%delete _
endif
else
top new
let g:shell_scratch_buffer_nr = bufnr('%')
endif
setlocal buftype=nofile bufhidden=wipe nobuflisted noswapfile nowrap
nnoremap <buffer> q :bdelete<CR>
augroup ResetShellBufferNr
autocmd! * <buffer>
autocmd BufUnload <buffer> let g:shell_scratch_buffer_nr = -1
augroup END
" call setline(1, 'You entered: ' . a:cmdline)
" call setline(2, 'Expanded Form: ' .l:expanded_cmdline)
" call setline(3,substitute(getline(2),'.','=','g'))
execute '$read !'. l:expanded_cmdline
1
setlocal nomodifiable
if !exists('b:shell_line_count')
let b:shell_line_count = line('$')
if b:shell_line_count > 25
let b:shell_line_count = 20
endif
execute 'resize' b:shell_line_count + 1
endif
wincmd p
endfunction
command! -complete=shellcmd -nargs=+ Shell call s:RunShellCommand(<q-args>)
let g:shell_scratch_buffer_nr = -1
"}}}
function! SaveAndExecute(ex_command) abort "{{{
" https://stackoverflow.com/a/40195855
" ex_command: command to run to execute file
" SOURCE [reusable window]: https://github.com/fatih/vim-go/blob/master/autoload/go/ui.vim
" save and reload current file
silent execute 'update | edit'
" get file path of current file
let s:current_buffer_file_path = expand('%')
let s:output_buffer_name = 'Output'
let s:output_buffer_filetype = 'output'
" reuse existing buffer window if it exists otherwise create a new one
if !exists('c:buf_nr') || !bufexists(s:buf_nr) || bufwinnr(s:buf_nr) == -1
silent execute 'top new ' . s:output_buffer_name
let s:buf_nr = bufnr('%')
elseif bufwinnr(s:buf_nr) != bufwinnr('%')
silent execute bufwinnr(s:buf_nr) . 'wincmd w'
endif
silent execute 'setlocal filetype=' . s:output_buffer_filetype
setlocal bufhidden=delete
setlocal buftype=nofile
setlocal noswapfile
setlocal nobuflisted
setlocal winfixheight
setlocal cursorline " make it easy to distinguish
" setlocal nonumber
" setlocal norelativenumber
setlocal showbreak=""
nnoremap <silent> <buffer> q :bdelete!<CR>'.zz
" clear the buffer
setlocal noreadonly
" setlocal modifiable
%delete _
" add the console output
silent execute '.!'. a:ex_command . ' ' . shellescape(s:current_buffer_file_path, 1)
" resize window to content length
" Note: This is annoying because if you print a lot of lines then your code buffer is forced to a height of one line every time you run this function.
" However without this line the buffer starts off as a default size and if you resize the buffer then it keeps that custom size after repeated runs of this function.
" But if you close the output buffer then it returns to using the default size when its recreated
"execute 'resize' . line('$')
" make the buffer non modifiable
setlocal readonly
" setlocal nomodifiable
endfunction
"}}}
function! JsIncludeExpr(file)"{{{
" substitute(substitute(v:fname,'^[\\~@]\/','./',''),'^[\\~@]','./node_modules/','')
return substitute(substitute(a:file,'^[\\~@]\/','./',''),'^[\\~@]','./node_modules/','')
endfunction
"}}}
function! Redir(cmd) "{{{
for win in range(1, winnr('$'))
if getwinvar(win, 'scratch')
execute win . 'windo close'
endif
endfor
if a:cmd =~ '^!'
let output = system(matchstr(a:cmd, '^!\zs.*'))
else
redir => output
execute a:cmd
redir END
endif
vnew
let w:scratch = 1
setlocal buftype=nofile bufhidden=wipe nobuflisted noswapfile
call setline(1, split(output, "\n"))
endfunction
command! -nargs=1 -complete=command Redir silent call Redir(<q-args>)
" Usage:
" :Redir hi ............. show the full output of command ':hi' in a scratch window
" :Redir !ls -al ........ show the full output of command ':!ls -al' in a scratch window
"}}}
"}}}
function! ToggleHighlights() abort "{{{
if ! exists('b:toggle_highlights_state')
" state 1 is normal, state 0 is faded
let b:toggle_highlights_state = 1
else
let b:toggle_highlights_state = ! b:toggle_highlights_state
endif
if b:toggle_highlights_state == 1
hi! link Comment None
else
hi! link Comment CommentDim
endif
endfunction
"}}}
"----------------------------------------------------------------------------}}}
" #settings {{{
scriptencoding utf-8
set ttyfast
set dictionary=spell
" set thesaurus+=/usr/share/dict/mthesaur.txt
augroup Dictionary
au!
au FileType markdown,text setlocal dictionary=/usr/share/dict/aspell-dump.txt
augroup END
" disable background color erase
" https://sunaku.github.io/vim-256color-bce.html
set t_ut=
syntax on
set fillchars=stl:\ ,stlnc:\ ,vert:\|,fold:\
set guioptions-=mTrLb
" set guioptions+=c
if exists('+termguicolors')
let &t_8f = "\<Esc>[38;2;%lu;%lu;%lum"
let &t_8b = "\<Esc>[48;2;%lu;%lu;%lum"
set termguicolors
endif
colorscheme paper-tonic
set updatetime=100
set timeoutlen=500
set lazyredraw
" https://parceljs.org/hmr.html#safe-write
set backupcopy=yes
set title
" the ;/home/* tells vim to stop searching at /home/* (I hope!)
set tags=./.tags,.tags,./tags-external,.tags-external;/home/*
" persisitent undo file
set undofile
set undodir=~/.config/nvim/undodir
set backupdir=~/.nvim/tmpdir
set directory=~/.nvim/tmpdir
set viewoptions-=options
set nosplitbelow nosplitright
set switchbuf=uselast
set ignorecase
set smartcase
set wildmenu
set wildmode=longest:full,full
set wildignore+=**/node_modules/**,**/dist/**,**/.git/**,**/build/**
" Use ag over grep
if executable('ag')
set grepprg=ag\ --nogroup\ --nocolor\ --ignore\ node_modules
endif
set hidden
set hlsearch
set completeopt=menuone,noselect
set nospell
set spelllang=en_gb
set diffopt+=vertical
let g:tex_flavor = 'latex'
set rnu nu
set tabstop=2
set softtabstop=-1
set shiftwidth=0
set shiftround
set noexpandtab
set autoindent
set breakindent
set showbreak=\ \ ↳\
set formatoptions=cq
set wrapmargin=0
setlocal cursorline
set foldcolumn=0
set signcolumn=yes
set colorcolumn=80,120
set iskeyword+=-
set scrolloff=4
set scrolljump=4
set showcmd
set incsearch
set inccommand=nosplit
set laststatus=2
set shortmess=aoOT
set cmdheight=3
set foldnestmax=9
set foldlevelstart=99
set showmode
set mouse=a
let g:netrw_preview = 1
set listchars=eol:¬,tab:│\ ,trail:~,extends:>,precedes:<,space:·
set fillchars=stl:\ ,stlnc:\ ,vert:┃,fold:\
set statusline=\
" buffer number
set statusline+=[%n]\ \
" line of total_lines and percentage through file
set statusline+=%-20(%l\ of\ %L\ (%p%%)%)
" column, virtual column
set statusline+=%-10(:%c\ %((%V)%)%)
" separator, highlight color
set statusline+=%=%#StatusLineNC#
" CoC status
if exists('*coc#exists')
set statusline+=%{coc#status()}
endif
" separator
set statusline+=%=%#StatusLine#
set statusline+=%y\
set statusline+=%r\ %m\
set statusline+=%{&buftype==''?expand('%f'):''}
set statusline+=\
set conceallevel=0
"----------------------------------------------------------------------------}}}
" #mappings {{{
let g:mapleader = ' '
" miscallaneous {{{
nnoremap <cr>l :colorscheme paper-tonic<cr>
nnoremap <cr>d :colorscheme monotonous-dark<cr>
nnoremap 0 ^
nnoremap <silent><space>cs :let @/=""<cr>
nnoremap <silent><expr> <space>nh (&hls && v:hlsearch ? ':nohls' : ':set hls')."\n"
" Focus on current fold, close the rest
nnoremap <silent> <space>zz zMzvzt
" open quickfix window of TODOs
nnoremap <space>td :grep -RE '(TODO\\|FIXME)' .<CR>:botright cwindow<CR>:echo len(getqflist()) 'TODOs'<CR>
" sync highlighting from start
"}}}
" location list and quickfix mappings {{{
nnoremap <space>lo :botright lwindow<CR>
nnoremap <up> :lprev<CR>zv
nnoremap <down> :lnext<CR>zv
nnoremap <space>lc :lclose<CR>
nnoremap <space>lh :lhistory<CR>
nnoremap <space>lp :lolder<CR>
nnoremap <space>ln :lnewer<CR>
nnoremap <space>qo :botright cwindow<CR>
nnoremap <left> :cprev<CR>zv
nnoremap <right> :cnext<CR>zv
nnoremap <space>qc :cclose<CR>
nnoremap <space>qh :chistory<CR>
nnoremap <space>qp :colder<CR>
nnoremap <space>qn :cnewer<CR>
nnoremap <space>qt :tabnew \| cwindow<CR>
"}}}
"----------------------------------------------------------------------------}}}
" #abbreviations {{{
iabbrev adn and
iabbrev waht what
iabbrev tehn then
iabbrev functin function
iabbrev positin position
"----------------------------------------------------------------------------}}}
" #autocommands {{{
" template files {{{
augroup Templates
autocmd!
autocmd BufNewFile *.sh 0read ~/.config/nvim/templates/template.sh | normal G
autocmd BufNewFile *.html 0read ~/.config/nvim/templates/template.html | normal gg
autocmd BufNewFile *.css 0read ~/.config/nvim/templates/template.css | normal G
autocmd BufNewFile *.scss 0read ~/.config/nvim/templates/template.css | normal G
augroup END
" }}}
" persistent folds {{{
augroup AutoSaveFolds
autocmd!
autocmd BufWrite ?* mkview
autocmd BufRead ?* silent! loadview
augroup END
" }}}
" Show trailing whitepace and spaces before a tab: {{{
augroup ShowWhiteSpaceErrors
autocmd!
autocmd Syntax * syn match ExtraWhitespace /\s\+$\| \+\ze\t/ containedin=ALL
augroup END
" }}}
" Automatically reload .vimrc if changed {{{
augroup ReloadVimrc
autocmd!
autocmd BufWritePost .vimrc,_vimrc,vimrc,.gvimrc,_gvimrc,gvimrc so $MYVIMRC | if has('gui_running') | so $MYGVIMRC | endif
augroup END
" }}}
" Open quickfix window{{{
" augroup QuickFixAutoload
" autocmd!
" autocmd QuickFixCmdPost [^l]* nested botright cwindow
" autocmd QuickFixCmdPost l* nested botright lwindow
" augroup END
augroup OnTerminalOpen
autocmd!
autocmd TermOpen * setlocal nonumber norelativenumber
augroup END
" }}}
"----------------------------------------------------------------------------}}}
"
"
" require lua init
lua <<EOF
require('init')
EOF
" vim: set foldmethod=marker:

View file

@ -1,364 +0,0 @@
" https://github.com/junegunn/vim-plug
if empty(glob('~/.config/nvim/autoload/plug.vim'))"
silent !curl -fLo ~/.config/nvim/autoload/plug.vim --create-dirs
\ https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim
autocmd VimEnter * PlugInstall --sync | source $MYVIMRC
endif
call plug#begin('~/.config/nvim/bundle')
" evaluating
" https://github.com/simrat39/rust-tools.nvim
Plug 'simrat39/rust-tools.nvim'
" evaluating
" https://github.com/wuelnerdotexe/vim-astro
" do i need this and https://github.com/virchau13/tree-sitter-astro ????
Plug 'wuelnerdotexe/vim-astro'
" https://github.com/kevinhwang91/
Plug 'kevinhwang91/promise-async'
Plug 'kevinhwang91/nvim-ufo'
" colorscheme in develpment paper-tonic
Plug '~/projects/nvim-paper-tonic'
" #nvim-treesitter {{{
" https://github.com/nvim-treesitter/nvim-treesitter
" Plug 'nvim-treesitter/nvim-treesitter', {'do': ':TSUpdate'} " update the parsers on update
" config needs to be after call to plug#end
" Treesitter uses a different parser for every language, which needs to be generated
" If the language is already supported by nvim-treesitter, you can install it with
" :TSInstall <language_to_install>
" - can use tab completion with this
" Parsers not on this list can be added manually
"
" If you update nvim-treesitter and want to make sure the parser is at the latest compatible version (as specified in nvim-treesitter's lockfile.json), use
" :TSUpdate {language}.
" To update all parsers unconditionally, use
" :TSUpdate all or just :TSUpdate.
"
" Each module provides a distinct tree-sitter-based feature such as highlighting, indentation, or folding; see :h nvim-treesitter-modules or "Available modules" below for a list of modules and their options.
" All modules are disabled by default and need to be activated explicitly in your init.vim
"
" Each module can also be enabled or disabled interactively through the following commands:
" :TSBufEnable {module} " enable module on current buffer
" :TSBufDisable {module} " disable module on current buffer
" :TSEnableAll {module} [{ft}] " enable module on every buffer. If filetype is specified, enable only for this filetype.
" :TSDisableAll {module} [{ft}] " disable module on every buffer. If filetype is specified, disable only for this filetype.
" :TSModuleInfo [{module}] " list information about modules state for each filetype
"
" Check :h nvim-treesitter-commands for a list of all available commands. It may be necessary to reload the buffer (e.g., via :e) after enabling a module interactively.
"}}}
" #playground (temporary) {{{
" https://github.com/nvim-treesitter/playground
" Plug 'nvim-treesitter/playground'
"}}}
" #vim-lspconfig {{{
" https://github.com/neovim/nvim-lspconfig
" https://github.com/neovim/nvim-lspconfig/wiki
Plug 'neovim/nvim-lspconfig'
"}}}
" #plenary.nvim {{{
" https://github.com/nvim-lua/plenary.nvim
" required for null-ls
Plug 'nvim-lua/plenary.nvim'
"}}}
" #null-ls.nvim {{{
" https://github.com/jose-elias-alvarez/null-ls.nvim
Plug 'jose-elias-alvarez/null-ls.nvim'
"}}}
" #nvim-cmp {{{
" https://github.com/hrsh7th/nvim-cmp/
" completion
" Plug 'hrsh7th/nvim-cmp', { 'branch': 'main' }
" Plug 'hrsh7th/cmp-nvim-lsp', { 'branch': 'main' }
" Plug 'hrsh7th/cmp-buffer', { 'branch': 'main' }
" Plug 'hrsh7th/cmp-path', { 'branch': 'main' }
" Plug 'uga-rosa/cmp-dictionary', { 'branch': 'main' }
" let g:cmp_dictionary_exact = -1
" Plug 'quangnguyen30192/cmp-nvim-ultisnips', { 'branch': 'main' }
"}}}
" #indent-blankline.nvim {{{
" https://github.com/lukas-reineke/indent-blankline.nvim
Plug 'lukas-reineke/indent-blankline.nvim'
"}}}
" #iamcco/markdown-preview.nvim {{{
" https://github.com/iamcco/markdown-preview.nvim
Plug 'iamcco/markdown-preview.nvim', { 'do': { -> mkdp#util#install() }, 'for': ['markdown', 'vim-plug']}
let g:mkdp_browser = '/usr/local/bin/chromium-app'
let g:mkdp_echo_preview_url = 1
nmap <space>m <Plug>MarkdownPreviewToggle
" commands
" MarkdownPreview
" MarkdownPreviewStop
" MarkdownPreviewToggle
"}}}
" keeping
" #vim-hexokinase {{{
" https://github.com/chrisbra/Colorizer
" display colors asynchronously
Plug 'chrisbra/Colorizer'
" let g:colorizer_use_virtual_text = 1
nnoremap <silent> <cr>cc :ColorToggle<CR>
"}}}
" #nvim-autopairs {{{
" https://github.com/windwp/nvim-autopairs
" automatic quote, paranthesis,etc closing.
Plug 'windwp/nvim-autopairs'
"}}}
" #nvim-ts-autotag {{{
" https://github.com/windwp/nvim-ts-autotag
" automatic html tag closing/renaming.
" Plug 'windwp/nvim-ts-autotag', { 'branch': 'main' }
"}}}
" #emmet-vim {{{
" https://github.com/mattn/emmet-vim
Plug 'mattn/emmet-vim'
let g:user_emmet_leader_key=',,'
let g:user_emmet_settings = {
\ 'indentation': ' ',
\}
"}}}
" #gitgutter {{{
" https://github.com/airblade/vim-gitgutter/blob/master/README.mkd
" show git diff in sign column
Plug 'airblade/vim-gitgutter'
nmap ]h <Plug>(GitGutterNextHunk)
nmap [h <Plug>(GitGutterPrevHunk)
omap ih <Plug>(GitGutterTextObjectInnerPending)
omap ah <Plug>(GitGutterTextObjectOuterPending)
xmap ih <Plug>(GitGutterTextObjectInnerVisual)
xmap ah <Plug>(GitGutterTextObjectOuterVisual)
"}}}
" #MatchTagAlways{{{
" always highlights xml/html tags enclosing cursor
" https://github.com/Valloric/MatchTagAlways
Plug 'Valloric/MatchTagAlways'
let g:mta_filetypes = {
\ 'jinja' : 1,
\ 'html' : 1,
\ 'vue' : 1,
\ 'xhtml' : 1,
\ 'xml' : 1,
\}
"}}}
" #quickscope{{{
" highlights unique characters when using f, F, etc
" https://github.com/unblevable/quick-scope
Plug 'unblevable/quick-scope'
let g:qs_highlight_on_keys = ['f', 'F', 't', 'T']
"}}}
" #switch {{{
"https://github.com/AndrewRadev/switch.vim
Plug 'AndrewRadev/switch.vim'
let g:switch_mapping = '<space>-'
let g:switch_custom_definitions = [
\ ['0', '1'],
\ ['ease-in', 'ease-out', 'ease-in-out', 'linear'],
\ ['auto', 'none'],
\ ['left', 'right'],
\ ['top', 'bottom'],
\ ['row', 'column'],
\ ['relative', 'absolute', 'fixed'],
\ ['private', 'public', 'protected']
\ ]
"}}}
" #ultisnips {{{
" https://github.com/sirver/UltiSnips
Plug 'SirVer/ultisnips'
" and some snippets
" https://github.com/honza/vim-snippets
" Plug 'honza/vim-snippets'
nnoremap <space>ul :call ListUltisnips()<cr>
inoremap jkul <c-o>:call ListUltisnips()<cr>
let g:UltiSnipsSnippetsDir='~/.vim/UltiSnips'
" Trigger configuration. Do not use <tab> if you use https://github.com/Valloric/YouCompleteMe.
let g:UltiSnipsExpandTrigger='<tab>'
let g:UltiSnipsJumpForwardTrigger='<tab>'
let g:UltiSnipsJumpBackwardTrigger='<s-tab>'
let g:UltiSnipsEditSplit='horizontal'
function! ListUltisnips() abort"{{{
let l:snips = UltiSnips#SnippetsInCurrentScope(1)
let l:keylist = sort(keys(l:snips))
echo ' --------------------------------------------------'
for l:key in l:keylist
echo printf(" %-10s\t%s", l:key, l:snips[l:key])
endfor
echo '---------------------------------------------------'
endfunction
"}}}
function! CompleteSnippets(findstart, base)"{{{
if a:findstart
let l:line = getline('.')
let l:start = col('.') - 1
while l:start > 0 && l:line[l:start - 1] =~ '\a'
let l:start -= 1
endwhile
return l:start
else
let l:res = []
let l:snips = UltiSnips#SnippetsInCurrentScope(1)
let l:keylist = sort(keys(l:snips))
for l:key in l:keylist
if l:key =~ '^' . a:base
let l:item = {'word': l:key, 'menu': l:snips[l:key]}
call add(l:res, l:item)
endif
endfor
return l:res
endif
endfunction
"}}}
set completefunc=CompleteSnippets
"}}}
" #Netrw {{{
let g:netrw_liststyle=3
" let g:netrw_list_hide=netrw_gitignore#Hide()
let g:netrw_preview = 0
let g:netrw_winsize = 50
let g:netrw_altv = &spr
let g:netrw_alto = 0
let g:netrw_altfile = 1
let g:netrw_mousemaps = 0
let g:netrw_keepdir = 0
"}}}
" #Obsession{{{
" fork of tpope/vim-obsession
Plug 'studio-vx/vim-obsession'
"}}}
" #tcomment_vim{{{
" https://github.com/tomtom/tcomment_vim
Plug 'tomtom/tcomment_vim'
"}}}
" #vim-rsi{{{
"https://github.com/tpope/vim-rsi
Plug 'tpope/vim-rsi'
"}}}
" #vim-repeat{{{
" https://github.com/tpope/vim-repeat
" makes repeat . work for more stuff
Plug 'tpope/vim-repeat'
"}}}
" #vim-surround{{{
Plug 'tpope/vim-surround'
"}}}
" #vim-wakatime{{{
Plug 'wakatime/vim-wakatime'
"}}}
" reconfigure and learn to use properly
" #vim-fzf {{{
" https://github.com/junegunn/fzf.vim
Plug 'junegunn/fzf'
Plug 'junegunn/fzf.vim'
nnoremap <space>fg :GFiles<CR>
nnoremap <space>ff :Files<CR>
nnoremap <space>fh :History<CR>
nnoremap <space>fb :Buffers<CR>
nnoremap <space>fH :Helptags<CR>
let g:fzf_preview_window = 'right:60%'
let g:fzf_colors =
\ { 'fg': ['fg', 'Normal'],
\ 'bg': ['bg', 'Normal'],
\ 'hl': ['fg', 'Label'],
\ 'fg+': ['fg', 'CursorLine', 'CursorColumn', 'Normal'],
\ 'bg+': ['bg', 'CursorLine', 'CursorColumn'],
\ 'hl+': ['fg', 'WildMenu'],
\ 'info': ['fg', 'Comment'],
\ 'border': ['fg', 'Comment'],
\ 'prompt': ['fg', 'Constant'],
\ 'pointer': ['fg', 'Special'],
\ 'marker': ['fg', 'Keyword'],
\ 'spinner': ['fg', 'Label'],
\ 'header': ['fg', 'Comment'] }
" Rg that doesn't ignore .gitignore or any other files
command! -bang -nargs=* Rgall
\ call fzf#vim#grep(
\ 'rg -uuu --column --line-number --no-heading --color=always --smart-case -- '.shellescape(<q-args>), 1,
\ fzf#vim#with_preview(), <bang>0)
"}}}
" #vim-shellcheck{{{
" https://github.com/itspriddle/vim-shellcheck
Plug 'itspriddle/vim-shellcheck'
"}}}
" #vim-markdown{{{
" https://github.com/plasticboy/vim-markdown
Plug 'plasticboy/vim-markdown'
let g:vim_markdown_toc_autofit = 1
let g:vim_markdown_fenced_languages = ['bash=sh']
"}}}
" #undotree {{{
Plug 'mbbill/undotree'
nnoremap <space>ut :UndotreeToggle<cr>
"}}}
" #vim-floaterm{{{
" https://github.com/voldikss/floaterm
" allows to open floating terminal
Plug 'voldikss/vim-floaterm'
let g:floaterm_opener = 'edit'
" nnoremap <space>lf :FloatermNew --height=0.9 --width=0.9 lf<CR>
nnoremap <space>lg :FloatermNew --height=0.9 --width=0.9 lazygit<CR>
"}}}
" #vim-Jinja2-Syntax{{{
" https://github.com/studio-vx/Vim-Jinja2-Syntax
" original: https://github.com/Glench/Vim-Jinja2-Syntax
Plug 'studio-vx/Vim-Jinja2-Syntax'
"}}}
" ------------------------------------------------------------------------------
call plug#end()
runtime macros/matchit.vim
" require lua init modules
lua <<EOF
-- require('init-plugins')
-- require('init-treesitter')
-- require('init-indent-blankline')
-- require('init-cmp')
EOF
" vim: set fdm=marker ft=vim:

View file

@ -1,69 +0,0 @@
" Rename tabs to show tab number.
" based on:
" http://stackoverflow.com/questions/5927952/whats-implementation-of-vims-default-tabline-function
function! MyTabLine() "{{{
let l:customtabline = ''
let l:currenttabnum = tabpagenr()
let l:lasttabnumber = tabpagenr('$')
let l:tabnumber = 1
while l:tabnumber <= l:lasttabnumber
let l:buflist = tabpagebuflist(l:tabnumber)
let l:winnr = tabpagewinnr(l:tabnumber)
if l:lasttabnumber > 1
let l:customtabline .= '%' . l:tabnumber . 'T'
let l:customtabline .= (l:tabnumber == l:currenttabnum ? '%1*' : '%2*')
let l:customtabline .= (l:tabnumber == l:currenttabnum ? '%#TabLineNumSel#' : '%#TabLineNum#')
let l:customtabline .= ' ' . l:tabnumber . ' '
let l:customtabline .= (l:tabnumber == l:currenttabnum ? '%#TabLineItemSel#' : '%#TabLineItem#')
endif
let l:bufnr = l:buflist[l:winnr - 1]
let l:file = bufname(l:bufnr)
let l:buftype = getbufvar(l:bufnr, '&buftype')
if l:buftype ==# 'help'
let l:file = 'help:' . fnamemodify(l:file, ':t:r')
elseif l:buftype ==# 'quickfix'
let l:file = 'quickfix'
elseif l:buftype ==# 'nofile'
if l:file =~# '\/.'
let l:file = substitute(l:file, '.*\/\ze.', '', '')
endif
else
let l:file = fnamemodify(l:file, ':p:t')
endif
if l:file ==# ''
let l:file = "''"
endif
let l:customtabline .= l:file . '%T%#TabLineFill# '
let l:tabnumber = l:tabnumber + 1
endwhile
let l:customtabline .= '%T%#TabLineFill#%='
let l:customtabline .= '%#TabLineItem# %{getcwd()}% '
if exists('*ObsessionStatus')
let l:customtabline .= "%#TabLineItem# %{ObsessionStatus(fnamemodify(v:this_session,':t'),'---')} %*"
endif
return l:customtabline
endfunction
"}}}
set tabline=%!MyTabLine()
set showtabline=2
" vim: set foldmethod=marker:

View file

@ -1,6 +0,0 @@
if exists('g:vscode')
" VSCode extension
source ~/.config/nvim/init.vscode.vim
else
source ~/.config/nvim/init.full.vim
endif

View file

@ -1,11 +0,0 @@
set undofile
set undodir=~/.config/nvim/undodir
set backupdir=~/.nvim/tmpdir
set directory=~/.nvim/tmpdir
set ignorecase
set smartcase
set iskeyword+=-
set scrolloff=4

View file

@ -1,49 +0,0 @@
local cmp = require 'cmp'
cmp.setup({
window = {documentation = cmp.config.window.bordered({border = "single"})},
formatting = {
format = function(entry, vim_item)
-- set a name for each source
vim_item.menu = ({
nvim_lsp = "[LSP]",
path = "[Path]",
buffer = "[Buffer]",
ultisnips = "[UltiSnips]"
})[entry.source.name]
return vim_item
end
},
completion = {
keyword_length = 1,
max_item_count = 20
-- autocomplete = false
},
snippet = {expand = function(args) vim.fn["UltiSnips#Anon"](args.body) end},
mapping = {
['<C-u>'] = cmp.mapping.scroll_docs(-4),
['<C-d>'] = cmp.mapping.scroll_docs(4),
["<C-n>"] = cmp.mapping({
i = function()
if cmp.visible() then
cmp.select_next_item({behavior = cmp.SelectBehavior.Insert})
else
cmp.complete()
end
end
})
},
sources = {
{name = 'nvim_lsp', max_item_count = 8, keyword_length = 3},
{name = 'path'},
{name = 'buffer',
option = {
keyword_length = 4,
max_item_count = 20,
get_bufnrs = function()
return vim.api.nvim_list_bufs()
end
}},
{name = 'ultisnips', priority_weight = 10, keyword_length = 1}
}
})

View file

@ -1,5 +0,0 @@
require("indent_blankline").setup {
space_char_blankline = " ",
show_current_context = true,
}

View file

@ -1,230 +0,0 @@
vim.cmd [[
sign define LspDiagnosticsSignError text= texthl= linehl= numhl=LspDiagnosticsLineNrError
sign define LspDiagnosticsSignWarning text= texthl= linehl= numhl=LspDiagnosticsLineNrWarning
sign define LspDiagnosticsSignInfo text= texthl= linehl= numhl=LspDiagnosticsLineNrInformation
sign define LspDiagnosticsSignHint text= texthl= linehl= numhl=LspDiagnosticsLineNrHint
]]
--
-- lspconfig
local nvim_lsp = require('lspconfig')
-- Use a loop to conveniently call 'setup' on multiple servers and
-- map buffer local keybindings when the language server attaches
local servers = {
-- astro
-- npm install -g @astrojs/language-server
'astro', -- npm i -g bash-language-server
-- no formatting support
'bashls', -- npm i -g vscode-langservers-extracted
-- no formatting support
'cssls', -- npm install -g intelephense
-- suports formatting
'intelephense',
-- https://phpactor.readthedocs.io/en/master/usage/standalone.html
'phpactor', -- npm install -g pyright
-- static type checker
'pyright', -- https://github.com/neovim/nvim-lspconfig/wiki
-- 'tailwindcss',
-- npm install -g typescript typescript-language-server
-- supports formatting
'tsserver', -- npm install -g vim-language-server
-- no formatting support
'vimls', -- vue
-- use vetur
'yamlls' -- no formatting support
-- is now automatically started/configured by rust-tools
-- sudo pacman -Syu rust-analyzer
-- 'rust_analyzer'
}
-- Use an on_attach function to only map the following keys
-- after the language server attaches to the current buffer
local on_attach = function(client, bufnr)
local function buf_set_keymap(...)
vim.api.nvim_buf_set_keymap(bufnr, ...)
end
local function buf_set_option(...)
vim.api.nvim_buf_set_option(bufnr, ...)
end
-- Enable completion triggered by <c-x><c-o>
buf_set_option('omnifunc', 'v:lua.vim.lsp.omnifunc')
-- Mappings.
local opts = {noremap = true, silent = true}
-- See `:help vim.lsp.*` for documentation on any of the below functions
buf_set_keymap('n', '[d',
'<cmd>lua vim.diagnostic.goto_prev({float = {...}})<CR>',
opts)
buf_set_keymap('n', ']d',
'<cmd>lua vim.diagnostic.goto_next({float = {...}})<CR>',
opts)
buf_set_keymap('n', 'gd', '<cmd>lua vim.lsp.buf.definition()<CR>', opts)
buf_set_keymap('n', 'gD', '<cmd>lua vim.lsp.buf.declaration()<CR>', opts)
buf_set_keymap('n', 'gi', '<cmd>lua vim.lsp.buf.implementation()<CR>', opts)
buf_set_keymap('n', 'gr', '<cmd>lua vim.lsp.buf.references()<CR>', opts)
buf_set_keymap('n', 'gl',
'<cmd>lua vim.diagnostic.open_float(buffer, {{opts}, scope="line"})<CR>',
opts)
buf_set_keymap('n', 'gh', '<cmd>lua vim.lsp.buf.hover()<CR>', opts)
buf_set_keymap('n', '<C-k>', '<cmd>lua vim.lsp.buf.signature_help()<CR>',
opts)
buf_set_keymap('n', '<space>T',
'<cmd>lua vim.lsp.buf.type_definition()<CR>', opts)
buf_set_keymap('n', '<space>l', '<cmd>lua vim.diagnostic.setloclist()<CR>',
opts)
buf_set_keymap('n', '<space>q', '<cmd>lua vim.diagnostic.setqflist()<CR>',
opts)
buf_set_keymap('n', '<space>ca', '<cmd>lua vim.lsp.buf.code_action()<CR>',
opts)
buf_set_keymap('n', '<space>rn', '<cmd>lua vim.lsp.buf.rename()<CR>', opts)
buf_set_keymap('n', '<space>f', '<cmd>lua vim.lsp.buf.formatting()<CR>',
opts)
-- buf_set_keymap('n', '<space>wa', '<cmd>lua vim.lsp.buf.add_workspace_folder()<CR>', opts)
-- buf_set_keymap('n', '<space>wr', '<cmd>lua vim.lsp.buf.remove_workspace_folder()<CR>', opts)
-- buf_set_keymap('n', '<space>wl', '<cmd>lua print(vim.inspect(vim.lsp.buf.list_workspace_folders()))<CR>', opts)
if client.name == 'phpactor' then
client.server_capabilities.find_references = false;
end
if client.name == 'tsserver' or client.name == 'intelephense' then
client.server_capabilities.document_formatting = false;
-- print(vim.inspect(client.server_capabilities));
end
if client.server_capabilities.document_formatting then
vim.cmd [[augroup lsp_formatting]]
vim.cmd [[autocmd!]]
vim.cmd [[autocmd BufWritePre <buffer> :lua vim.lsp.buf.formatting_seq_sync({}, 3000)]]
vim.cmd [[augroup END]]
end
if client.server_capabilities.document_highlight then
vim.cmd [[
augroup lsp_document_highlight
autocmd! * <buffer>
autocmd CursorHold <buffer> lua vim.lsp.buf.document_highlight()
autocmd CursorMoved <buffer> lua vim.lsp.buf.clear_references()
augroup END
]]
end
end
local capabilities = vim.lsp.protocol.make_client_capabilities()
capabilities = require('cmp_nvim_lsp').update_capabilities(capabilities)
capabilities.textDocument.completion.completionItem.snippetSupport = true
for _, lsp in ipairs(servers) do
nvim_lsp[lsp].setup {
on_attach = on_attach,
capabilities = capabilities,
flags = {debounce_text_changes = 150}
}
end
local runtime_path = vim.split(package.path, ';')
table.insert(runtime_path, "lua/?.lua")
table.insert(runtime_path, "lua/?/init.lua")
require'lspconfig'.sumneko_lua.setup {
settings = {
Lua = {
runtime = {
-- Tell the language server which version of Lua you're using (most likely LuaJIT in the case of Neovim)
version = 'LuaJIT',
-- Setup your lua path
path = runtime_path
},
diagnostics = {
-- Get the language server to recognize the `vim` global
globals = {'vim'}
},
workspace = {
-- Make the server aware of Neovim runtime files
library = vim.api.nvim_get_runtime_file("", true)
},
-- Do not send telemetry data containing a randomized but unique identifier
telemetry = {enable = false}
}
}
}
-- toml
-- 'taplo'
-- -- sudo pacman -Syu taplo-cli
require'lspconfig'.taplo.setup {
on_attach = on_attach,
capabilities = capabilities,
flags = {debounce_text_changes = 150},
cmd = {"taplo", "lsp", "stdio"}
}
-- rust-tools
require('rust-tools').setup({
server = {
on_attach = on_attach,
capabilities = capabilities,
flags = {debounce_text_changes = 150},
settings = {["rust-analyzer"] = {checkOnSave = {command = "clippy"}}}
}
})
-- inlay hints
require('rust-tools').inlay_hints.enable()
------
-- null-ls
local null_ls = require("null-ls")
local null_ls_utils = require("null-ls.utils")
local root = null_ls_utils.get_root()
local eslint_command = root .. "/node_modules/eslint/bin/eslint.js"
-- print(eslint_command);
local sources = {
null_ls.builtins.formatting.prettierd,
null_ls.builtins.diagnostics.eslint.with({
condition = function(utils)
local has_file = utils.root_has_file({
"node_modules/@wordpress/scripts/config/.eslintrc.js"
})
-- print("condition")
-- print(has_file)
return has_file
end,
extra_args = {
"--no-eslintrc", "--config ",
root .. "/node_modules/@wordpress/scripts/config/.eslintrc.js",
"--ignore-path ",
root .. "/node_modules/@wordpress/scripts/config/.eslintignore"
}
}), --
-- null_ls.builtins.diagnostics.eslint.with({
-- filetypes = { "javascript", "javascriptreact", "typescript", "typescriptreact", "vue", "svelte", "astro" },
-- command = eslint_command
-- }),
-- null_ls.builtins.diagnostics.eslint.with({
-- condition = function(utils)
-- local has_file1 = utils.root_has_file({".eslintrc.js"})
-- local has_file2 = utils.root_has_file({"gatsby-config.js"})
-- print("condition")
-- print(has_file1)
-- print(has_file2)
-- return has_file1 and has_file2
-- end
-- }), --
null_ls.builtins.diagnostics.phpcs.with({
condition = function(utils)
return not utils.root_has_file({"vendor/bin/phpcs"})
end,
args = {"--standard=PSR12", "--report=json", "-s", "-"}
}), --
null_ls.builtins.formatting.black, -- black
null_ls.builtins.diagnostics.shellcheck, -- shellcheck,
null_ls.builtins.diagnostics.flake8, -- flake8
null_ls.builtins.formatting.lua_format -- luaFormatter
}
null_ls.setup({sources = sources, on_attach = on_attach})

View file

@ -1,35 +0,0 @@
-- nvim-autopairs
require('nvim-autopairs').setup {}
------
-- cmp
require("cmp").setup({
map_cr = false, -- map <CR> on insert mode
map_complete = false, -- it will auto insert `(` after select function or method item
auto_select = true -- automatically select the first item
})
------
-- nvim-ts-autotag
require'nvim-treesitter.configs'.setup {
autotag = {
enable = true,
filetypes = {
-- not working for astro files
'html', 'javascript', 'typescript', 'javascriptreact', 'typescriptreact', 'svelte', 'vue', 'tsx', 'jsx', 'rescript', 'astro',
'xml',
'php',
'markdown',
'glimmer','handlebars','hbs'
},
}
}
------
-- nvim-ufo
require('ufo').setup({
provider_selector = function(bufnr, filetype, buftype)
return {'treesitter', 'indent'}
end
})
------

View file

@ -1,14 +0,0 @@
require'nvim-treesitter.configs'.setup {
-- ensure_installed = "maintained", -- one of "all", "maintained" (parsers with maintainers), or a list of languages
ignore_install = {"c"}, -- List of parsers to ignore installing
highlight = {
enable = true, -- false will disable the whole extension
disable = {"c", "rust"}, -- list of language that will be disabled
-- Setting this to true will run `:h syntax` and tree-sitter at the same time.
-- Set this to `true` if you depend on 'syntax' being enabled (like for indentation).
-- Using this option may slow down your editor, and you may see some duplicate highlights.
-- Instead of true it can also be a list of languages
additional_vim_regex_highlighting = false
},
indent = {enable = true}
}

View file

@ -1,38 +0,0 @@
vim.o.foldmethod = 'expr'
vim.o.foldexpr = 'nvim_treesitter#foldexpr()'
vim.diagnostic.config({
virtual_text = false,
signs = true,
underline = false,
update_in_insert = false,
severity_sort = true,
float = {
border = "single",
source = "always" -- Or "if_many"
}
})
local signs = {Error = "● ", Warn = "● ", Hint = "● ", Info = "● "}
for type, icon in pairs(signs) do
local hl = "DiagnosticSign" .. type
vim.fn.sign_define(hl, {text = icon, texthl = hl, numhl = hl})
end
local border = {
{"┌", "FloatBorder"}, {"─", "FloatBorder"}, {"┐", "FloatBorder"},
{"│", "FloatBorder"}, {"┘", "FloatBorder"}, {"─", "FloatBorder"},
{"└", "FloatBorder"}, {"│", "FloatBorder"}
}
vim.lsp.handlers["textDocument/hover"] =
vim.lsp.with(vim.lsp.handlers.hover, {border = "single"})
vim.lsp.handlers["textDocument/signatureHelp"] =
vim.lsp.with(vim.lsp.handlers.signature_help, {border = "single"})
local orig_util_open_floating_preview = vim.lsp.util.open_floating_preview
function vim.lsp.util.open_floating_preview(contents, syntax, opts, ...)
opts = opts or {}
opts.border = opts.border or border
return orig_util_open_floating_preview(contents, syntax, opts, ...)
end

View file

@ -1,10 +0,0 @@
module.exports = {
plugins: [
[
"postcss-preset-env",
{
// options
},
],
],
};

View file

@ -1,15 +0,0 @@
html,
body {
padding: 0;
margin: 0;
}
body {
font-size: 100%;
box-sizing: border-box;
background-color: pink;
}
* {
box-sizing: inherit;
}

View file

@ -1,31 +0,0 @@
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="utf-8">
<title>THE TITLE IS THIS!</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="description" content="THE DESCRIPTION IS THIS!">
<meta name="author" content="I AM THE AUTHOR">
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<header>
</header>
<main>
</main>
<footer>
</footer>
<script src="js/script.js"></script>
</body>
</html>

View file

@ -1 +0,0 @@
#!/bin/sh

View file

@ -1,5 +1,5 @@
-- Abbreviations (common typo corrections)
-- Phase 10.2: Insert-mode abbreviations for frequent typos
-- Insert-mode abbreviations for frequent typos
vim.cmd.iabbrev('adn', 'and')
vim.cmd.iabbrev('waht', 'what')

View file

@ -1,7 +1,7 @@
-- Non-plugin autocommands (minimal placeholder for bootstrap)
local aug = vim.api.nvim_create_augroup("UserDefaults", { clear = true })
-- Phase 10.3: Templates (auto-populate new files from templates)
-- Templates (auto-populate new files from templates)
local template_aug = vim.api.nvim_create_augroup("Templates", { clear = true })
vim.api.nvim_create_autocmd("BufNewFile", {
@ -14,7 +14,7 @@ vim.api.nvim_create_autocmd("BufNewFile", {
end,
})
-- Phase 9.4: Per-filetype indentation settings to match formatters
-- Per-filetype indentation settings to match formatters
-- PHP: WordPress coding standards (tabs, displayed as 2 spaces)
vim.api.nvim_create_autocmd("FileType", {
@ -77,7 +77,7 @@ vim.api.nvim_create_autocmd("FileType", {
end,
})
-- Phase 11.8: Colorize diagnostic severity in quickfix/location list
-- Colorize diagnostic severity in quickfix/location list
vim.api.nvim_create_autocmd("FileType", {
group = aug,
pattern = "qf", -- Applies to both quickfix and location list

View file

@ -1,4 +1,4 @@
-- Phase 6.5: nvim-autopairs for auto-closing brackets, quotes, etc.
-- nvim-autopairs for auto-closing brackets, quotes, etc.
return {
'windwp/nvim-autopairs',
event = 'InsertEnter',

View file

@ -1,4 +1,4 @@
-- Phase 6.3: Comment.nvim for commenting
-- Comment.nvim for commenting
return {
'numToStr/Comment.nvim',
event = 'VeryLazy',

View file

@ -1,4 +1,4 @@
-- Phase 6.6: indent-blankline for visual indent guides
-- indent-blankline for visual indent guides
return {
'lukas-reineke/indent-blankline.nvim',
main = 'ibl',

View file

@ -1,4 +1,4 @@
-- Phase 6.4: nvim-surround for surrounding text with quotes, brackets, tags, etc.
-- nvim-surround for surrounding text with quotes, brackets, tags, etc.
return {
'kylechui/nvim-surround',
version = '*', -- Use stable releases

View file

@ -1,151 +1,176 @@
-- Treesitter: Syntax highlighting, incremental selection, textobjects, autotag
return {
{
"nvim-treesitter/nvim-treesitter",
branch = "master", -- The rewritten main branch uses a different configuration API
build = ":TSUpdate",
event = { "BufReadPost", "BufNewFile" },
dependencies = {
{ "nvim-treesitter/nvim-treesitter-textobjects", branch = "master" },
"windwp/nvim-ts-autotag",
},
config = function()
require("nvim-treesitter.configs").setup({
-- Install parsers for primary languages
ensure_installed = {
"lua",
"vim",
"vimdoc",
"php",
"html",
"javascript",
"typescript",
"tsx",
"css",
"scss",
"json",
"markdown",
"markdown_inline",
"bash",
"python",
"regex",
},
-- Auto-install missing parsers
auto_install = true,
-- Syntax highlighting
highlight = {
enable = true,
-- Disable for very large files
disable = function(lang, buf)
local max_filesize = 100 * 1024 -- 100 KB
local ok, stats = pcall(vim.uv.fs_stat, vim.api.nvim_buf_get_name(buf))
if ok and stats and stats.size > max_filesize then
return true
end
end,
additional_vim_regex_highlighting = false,
},
-- Incremental selection
incremental_selection = {
enable = true,
keymaps = {
init_selection = "+",
node_incremental = "+",
scope_incremental = "g+",
node_decremental = "-",
},
},
-- Indentation: Enable for languages with good indent queries
-- PHP requires this because GetPhpIndent() depends on Vim syntax (disabled by Treesitter)
indent = {
enable = true,
-- Disable for languages with poor/incomplete indent queries if needed
disable = {},
},
-- Textobjects
textobjects = {
select = {
enable = true,
lookahead = true, -- Jump forward to next textobject
keymaps = {
-- Functions
["af"] = "@function.outer",
["if"] = "@function.inner",
-- Classes
["ac"] = "@class.outer",
["ic"] = "@class.inner",
-- Parameters/arguments
["aa"] = "@parameter.outer",
["ia"] = "@parameter.inner",
-- Conditionals
["ai"] = "@conditional.outer",
["ii"] = "@conditional.inner",
-- Loops
["al"] = "@loop.outer",
["il"] = "@loop.inner",
-- Comments
["a/"] = "@comment.outer",
},
},
move = {
enable = true,
set_jumps = true, -- Add to jumplist
goto_next_start = {
["]f"] = "@function.outer",
["]c"] = "@class.outer",
["]a"] = "@parameter.inner",
},
goto_next_end = {
["]F"] = "@function.outer",
["]C"] = "@class.outer",
["]A"] = "@parameter.inner",
},
goto_previous_start = {
["[f"] = "@function.outer",
["[c"] = "@class.outer",
["[a"] = "@parameter.inner",
},
goto_previous_end = {
["[F"] = "@function.outer",
["[C"] = "@class.outer",
["[A"] = "@parameter.inner",
},
},
swap = {
enable = true,
swap_next = {
["<leader>a"] = "@parameter.inner",
},
swap_previous = {
["<leader>A"] = "@parameter.inner",
},
},
},
})
-- Setup autotag
require("nvim-ts-autotag").setup({
opts = {
enable_close = false,
enable_rename = false,
enable_close_on_slash = false,
},
-- Enable only in filetypes that can contain HTML-style tags.
per_filetype = {
["html"] = { enable_close = true, enable_rename = true, enable_close_on_slash = true },
["php"] = { enable_close = true, enable_rename = true, enable_close_on_slash = true },
["javascript"] = { enable_close = true, enable_rename = true, enable_close_on_slash = true },
["javascriptreact"] = { enable_close = true, enable_rename = true, enable_close_on_slash = true },
["typescript"] = { enable_close = true, enable_rename = true, enable_close_on_slash = true },
["typescriptreact"] = { enable_close = true, enable_rename = true, enable_close_on_slash = true },
["vue"] = { enable_close = true, enable_rename = true, enable_close_on_slash = true },
},
})
end,
},
local parsers = {
"lua",
"vim",
"vimdoc",
"php",
"html",
"javascript",
"typescript",
"tsx",
"css",
"scss",
"json",
"markdown",
"markdown_inline",
"bash",
"python",
"regex",
}
local filetypes = {
"lua",
"vim",
"help",
"php",
"html",
"javascript",
"javascriptreact",
"typescript",
"typescriptreact",
"css",
"scss",
"json",
"jsonc",
"markdown",
"sh",
"bash",
"python",
}
local function map(modes, lhs, rhs, desc)
vim.keymap.set(modes, lhs, rhs, { desc = desc, silent = true })
end
return {
{
"nvim-treesitter/nvim-treesitter",
branch = "main",
lazy = false,
build = ":TSUpdate",
config = function()
local treesitter = require("nvim-treesitter")
-- Keep the configured parser set present without blocking startup.
treesitter.install(parsers)
local group = vim.api.nvim_create_augroup("treesitter_features", { clear = true })
vim.api.nvim_create_autocmd("FileType", {
group = group,
pattern = filetypes,
desc = "Enable native Tree-sitter highlighting and supported indentation",
callback = function(args)
local path = vim.api.nvim_buf_get_name(args.buf)
local ok, stat = pcall(vim.uv.fs_stat, path)
if ok and stat and stat.size > 100 * 1024 then
return
end
local lang = vim.treesitter.language.get_lang(vim.bo[args.buf].filetype)
if not lang or not pcall(vim.treesitter.start, args.buf, lang) then
return
end
local has_indent, query = pcall(vim.treesitter.query.get, lang, "indents")
if has_indent and query then
vim.bo[args.buf].indentexpr = "v:lua.require'nvim-treesitter'.indentexpr()"
end
end,
})
map({ "n", "x" }, "+", function()
vim.treesitter.select("parent", vim.v.count1)
end, "Tree-sitter: Select parent node")
map("x", "-", function()
vim.treesitter.select("child", vim.v.count1)
end, "Tree-sitter: Select child node")
end,
},
{
"nvim-treesitter/nvim-treesitter-textobjects",
branch = "main",
dependencies = { "nvim-treesitter/nvim-treesitter" },
config = function()
require("nvim-treesitter-textobjects").setup({
select = { lookahead = true },
move = { set_jumps = true },
})
local select = require("nvim-treesitter-textobjects.select")
local move = require("nvim-treesitter-textobjects.move")
local swap = require("nvim-treesitter-textobjects.swap")
local function select_object(capture, query_group)
return function()
select.select_textobject(capture, query_group or "textobjects")
end
end
for lhs, capture in pairs({
af = "@function.outer",
["if"] = "@function.inner",
ac = "@class.outer",
ic = "@class.inner",
aa = "@parameter.outer",
ia = "@parameter.inner",
ai = "@conditional.outer",
ii = "@conditional.inner",
al = "@loop.outer",
il = "@loop.inner",
["a/"] = "@comment.outer",
}) do
map({ "x", "o" }, lhs, select_object(capture), "Tree-sitter: Select " .. capture)
end
map({ "n", "x" }, "g+", select_object("@local.scope", "locals"), "Tree-sitter: Select enclosing scope")
local movements = {
{ "]f", "goto_next_start", "@function.outer" },
{ "]F", "goto_next_end", "@function.outer" },
{ "[f", "goto_previous_start", "@function.outer" },
{ "[F", "goto_previous_end", "@function.outer" },
{ "]c", "goto_next_start", "@class.outer" },
{ "]C", "goto_next_end", "@class.outer" },
{ "[c", "goto_previous_start", "@class.outer" },
{ "[C", "goto_previous_end", "@class.outer" },
{ "]a", "goto_next_start", "@parameter.inner" },
{ "]A", "goto_next_end", "@parameter.inner" },
{ "[a", "goto_previous_start", "@parameter.inner" },
{ "[A", "goto_previous_end", "@parameter.inner" },
}
for _, movement in ipairs(movements) do
local lhs, method, capture = unpack(movement)
map({ "n", "x", "o" }, lhs, function()
move[method](capture, "textobjects")
end, "Tree-sitter: " .. method:gsub("_", " ") .. " " .. capture)
end
map("n", "<leader>a", function()
swap.swap_next("@parameter.inner")
end, "Tree-sitter: Swap with next parameter")
map("n", "<leader>A", function()
swap.swap_previous("@parameter.inner")
end, "Tree-sitter: Swap with previous parameter")
end,
},
{
"windwp/nvim-ts-autotag",
dependencies = { "nvim-treesitter/nvim-treesitter" },
opts = {
opts = {
enable_close = false,
enable_rename = false,
enable_close_on_slash = false,
},
per_filetype = {
html = { enable_close = true, enable_rename = true, enable_close_on_slash = true },
php = { enable_close = true, enable_rename = true, enable_close_on_slash = true },
javascript = { enable_close = true, enable_rename = true, enable_close_on_slash = true },
javascriptreact = { enable_close = true, enable_rename = true, enable_close_on_slash = true },
typescript = { enable_close = true, enable_rename = true, enable_close_on_slash = true },
typescriptreact = { enable_close = true, enable_rename = true, enable_close_on_slash = true },
vue = { enable_close = true, enable_rename = true, enable_close_on_slash = true },
},
},
},
}

View file

@ -1,4 +1,4 @@
-- Phase 6.7: nvim-ufo for better folding with Treesitter and LSP support
-- nvim-ufo for better folding with Treesitter and LSP support
return {
'kevinhwang91/nvim-ufo',
dependencies = {

View file

@ -1,4 +1,4 @@
-- Minimal settings for bootstrap and Phase 3.2
-- Core editor settings
-- Disable unused language providers early; enable later only if a plugin requires them
vim.g.loaded_ruby_provider = 0
@ -64,7 +64,6 @@ utils.tabline_shorten_length = 4
vim.opt.tabline = '%!v:lua.require("utils").custom_tabline()'
vim.opt.showtabline = 1 -- Show tabline only when there are 2+ tabs
-- Phase 3.2: non-plugin settings (legacy values where specified)
-- Native completion popup style
vim.opt.pumblend = 0 -- No transparency
@ -104,12 +103,12 @@ vim.opt.relativenumber = true
-- Scrolloff settings
vim.opt.scrolloff = 4
-- Phase 6.2: UX settings
-- Editor UX
vim.opt.signcolumn = "yes" -- Always show sign column (for LSP diagnostics, git signs, etc.)
vim.opt.cursorline = true -- Highlight current line
vim.opt.colorcolumn = "80,120" -- Visual guides at 80 and 120 characters
-- Phase 9.4: Default indentation (per-filetype overrides in after/ftplugin/)
-- Default indentation (per-filetype overrides in after/ftplugin/)
vim.opt.tabstop = 4 -- Display tabs as 4 spaces
vim.opt.shiftwidth = 4 -- Indent by 4
vim.opt.softtabstop = 4 -- Backspace removes 4 spaces
@ -119,7 +118,9 @@ vim.opt.smartindent = true -- Smart autoindenting (C-like programs, PHP, etc.)
-- Persistent undo
vim.opt.undofile = true -- Enable persistent undo
vim.opt.undodir = vim.fn.stdpath("config") .. "/undodir" -- Store undo files in config directory
local undo_dir = vim.fn.stdpath("state") .. "/undo"
vim.fn.mkdir(undo_dir, "p")
vim.opt.undodir = undo_dir
-- LSP diagnostics configuration
vim.diagnostic.config({

View file

@ -1,225 +0,0 @@
# ✔ **Neovim Migration Guide for AI Assistance**
> **Historical planning input:** this document records the migration's original assumptions and is not an active specification. `AGENTS.md`, `README.md`, `MIGRATION_PLAN.md`, and `LOG.md` describe the current netrw-only, native-completion architecture and supersede conflicting requirements below.
## **Purpose**
I am transitioning from VS Code back to Neovim.
This document describes my goals, constraints, preferences, and what I expect from an AI assistant during this rebuild.
---
## **High-Level Goals**
* Create a clean, modern Neovim setup using Lua.
* Avoid bringing over legacy Vimscript or old config patterns.
* Keep the configuration minimal but powerful.
* Base plugins on **lazy.nvim**.
* Support my workflow: **multiple tabs, each with its own Neo-tree instance**, for working with WordPress plugin development and referencing external codebases (WooCommerce, WordPress core, etc).
* Use LSP, Treesitter, telescope, and modern UX plugins.
* Integrate GitHub Copilot into completion.
* Preserve colour scheme used but modernise it if needed.
---
## **Do NOT Include / Do NOT Recreate**
These are outdated patterns and I *do not* want them reintroduced:
* custom tabline or statusline implemented in Vimscript
* custom foldtext functions
* autocommands that toggle cursorline/cursorcolumn per window
* manual Redir/shell command buffer logic
* CoC or any CoC-specific configuration
* netrw settings (I will be using Neo-tree)
* ruby, perl, node providers (disable them unless a plugin needs them)
* template that reloads vimrc on write
* cursorcolumn
* old folding logic unrelated to UFO
* Vimscript-based UI hacks of any kind
If needed, suggest modern replacements instead.
---
## **Required Plugins (Modern Equivalents Only)**
I want help managing these categories using lazy.nvim:
### **Core**
* nvim-lspconfig
* nvim-cmp
* cmp-nvim-lsp
* cmp-buffer
* cmp-path
* LuaSnip
### **Navigation**
* neo-tree.nvim
* telescope.nvim
* telescope-fzf-native.nvim (optional)
### **Treesitter**
* nvim-treesitter
* nvim-treesitter-textobjects
* nvim-ts-autotag
### **UX / Editing**
* Comment.nvim
* surround.nvim
* nvim-autopairs
* indent-blankline.nvim
* leap.nvim or flash.nvim
* nvim-ufo (folding)
* undotree (optional)
### **Git**
* gitsigns.nvim
### **Markdown**
* render-markdown.nvim
### **Copilot**
* copilot.lua
* copilot-cmp
### **Formatting**
* none-ls.nvim
---
## **Behaviours From My Old Config That I Want to KEEP**
When helping me implement these, please use modern Lua (`vim.api.nvim_*`, `vim.keymap.set`, etc), **not Vimscript**.
### ✔ Keybindings to preserve
### ✔ Templates for new files
* Auto-populate `.sh` from templates
### ✔ Abbreviations
* adn → and
* waht → what
* tehn → then
* functin → function
* positin → position
### ✔ Whitespace highlighting (modern alternatives acceptable)
### ✔ Persistent folds (if not using UFO)
### ✔ Spell & text settings
* `spelllang=en_gb`
* custom listchars and showbreak
---
## **Agent Behaviour Expectations**
### ✔ The AI should:
* provide modern Neovim/Lua solutions
* avoid legacy Vimscript unless explicitly requested
* help translate old behaviours into clean Lua equivalents
* help structure the new config modularly
* help migrate step-by-step
* explain trade-offs briefly if necessary
* prioritise simplicity and maintainability
* ensure plugin configs are minimal and only include what is required
### ✘ The AI should **NOT**:
* reintroduce old Vimscript workarounds
* over-engineer or over-automate
* install any plugin not listed without explicit confirmation
* suggest plugin-heavy “mega-setups”
* attempt to recreate VS Code behaviour unless requested
* produce large complex boilerplate unless requested
---
## **Config Structure I Want**
I strongly prefer very modular config files.
Plugin specific settings should be kept in the plugin config files where possible.
```
~/.config/nvim/
│
├── init.lua → loads everything
│
├── lua/
│ ├── settings.lua → non-plugin options only
│ ├── keymaps.lua → non-plugin keymaps
│ ├── autocmds.lua → non-plugin autocommands
│ ├── utils.lua → helper fns if needed
│ │
│ ├── plugins/
│ │ ├── init.lua → optional, can load automatically
│ │ ├── neo-tree.lua
│ │ ├── telescope.lua
│ │ ├── treesitter.lua
│ │ ├── cmp.lua
│ │ ├── lsp.lua
│ │ ├── copilot.lua
│ │ ├── ufo.lua
│ │ ├── gitsigns.lua
│ │ ├── markdown.lua
│ │ └── …
```
Each plugin file returns one table:
```lua
return {
"nvim-telescope/telescope.nvim",
keys = { ... },
opts = { ... },
config = function(_, opts)
require("telescope").setup(opts)
end
}
```
The AI can help refine this structure but should keep it simple.
---
## **My Workflow Requirements**
* Tab-per-context workflow
* Each tab has its own Neo-tree root
- one keymap for floating Neo-tree
- one keymap neo-tree sidebar toggle
- i would like previews of files activated via keymap (not auto preview)
- i would like previewed files to not clutter the buffer list.
* Splits stay inside tabs
* Telescope + LSP jump for navigation
* Heavy HTML/PHP/JS/Markdown usage (WordPress plugin dev)
* Copilot for completion
* No LSP-overconfiguration
---
## **End Goal**
A clean Neovim setup with:
* fast startup
* minimal but powerful plugins
* strong WordPress/PHP workflow
* organised code navigation
* modern folding & UI
* no legacy cruft
* easy maintenance

View file

@ -229,7 +229,6 @@ KAT
scannability
sympy
numpy
UltiSnips
Complianz
cPanel
mockups

Binary file not shown.

View file

@ -1,37 +0,0 @@
<?php
// PHP should be primary brownish-red
function test_function($param) {
$variable = "string value";
return $variable;
}
$result = test_function("test");
?>
<!DOCTYPE html>
<html>
<head>
<!-- HTML should be blue (c3) -->
<style>
/* CSS should be green (c2) */
.my-class {
color: red;
background: blue;
}
#my-id {
font-size: 16px;
}
</style>
</head>
<body>
<div class="my-class" id="my-id">
<p>Hello World</p>
</div>
<?php
// Back to PHP (primary)
echo "Mixed content";
?>
</body>
</html>

View file

@ -1,38 +0,0 @@
-- Test file for Paper Tonic Modern colorscheme
-- This file tests various syntax highlighting
-- Comments should be light gray, italic, bold
local function test_function()
-- Strings should be dark gray
local my_string = "Hello, world!"
-- Numbers and booleans
local my_number = 42
local my_bool = true
-- Keywords and conditionals
if my_bool then
print(my_string)
end
-- Loops
for i = 1, 10 do
print(i)
end
return my_number
end
-- Test HTML colors (should be blue - c3)
local html = [[
<div class="test">
<p>Hello</p>
</div>
]]
-- Test CSS colors (should be green - c2)
local css = [[
.test {
color: red;
}
]]

View file

@ -1,25 +0,0 @@
.my-class {
color: red;
background-color: blue;
font-size: 16px;
}
#my-id {
margin: 10px;
}
div.special {
padding: 5px;
}
* {
box-sizing: border-box;
}
.parent > .child {
display: block;
}
a:hover {
color: green;
}

View file

@ -1,73 +0,0 @@
/**
* Test file for JavaScript/TypeScript LSP diagnostics
* Tests error, warning, info, and hint virtual text colors
*/
// ERROR: Undefined variable
console.log(undefinedVariable);
// ERROR: Undefined function
nonexistentFunction();
// WARNING: Unused variable
const unusedVariable = "I'm never used";
// ERROR: Type error (if using TypeScript or JSDoc)
/**
* @param {string} name
* @param {number} age
*/
function greet(name, age) {
console.log(`Hello ${name}, you are ${age}`);
}
greet("Alice", "not a number"); // Type mismatch
// WARNING: Unreachable code
function earlyReturn() {
return "done";
console.log("Never executed"); // Unreachable
}
// ERROR: Invalid property access
const obj = {};
console.log(obj.nonexistent.nested.property);
// WARNING: Comparison with different types
if ("5" == 5) { // Should use ===
console.log("loose equality");
}
// ERROR: Missing parameter
greet("Bob"); // Missing age parameter
// INFO: Unnecessary type assertion (TypeScript)
const num = 123;
const str = String(num); // Could be simplified
// HINT: Variable can be const instead of let
let neverReassigned = "should be const";
console.log(neverReassigned);
// ERROR: Division by zero (some linters catch this)
const result = 10 / 0;
// WARNING: Duplicate case label
const value = 1;
switch (value) {
case 1:
console.log("one");
break;
case 1: // Duplicate case
console.log("one again");
break;
}
// ERROR: Invalid this context
const obj2 = {
name: "test",
greet: () => {
console.log(this.name); // Arrow function doesn't bind this
}
};
console.log("JavaScript diagnostic test complete!");

View file

@ -1,86 +0,0 @@
-- Test file for LSP diagnostics - lua_ls
-- This file intentionally contains different diagnostic levels
-- to test diagnostic virtual text colors in paper-tonic-modern
-- Define some valid code first
local valid_function = function()
return "valid"
end
---@diagnostic disable-next-line: unused-local
local _ = valid_function()
-- ERROR: Undefined global (lua_ls marks this as error)
print(undefined_global_variable)
-- ERROR: Undefined function
undefined_function()
-- WARNING: Unused local variable (lua_ls warning level)
local unused_variable = "I'm never used"
-- WARNING: Lowercase global (should be local)
lowercase_global = "This should be local or uppercase"
-- HINT: Redundant parentheses (some configs treat as hint)
local x = (5)
print(x)
-- ERROR: Wrong number of arguments
local function takes_two_args(a, b)
return a + b
end
takes_two_args(1) -- Missing second argument (lua_ls error)
-- ERROR: Attempting to call a non-function
local not_a_function = "string"
not_a_function()
-- WARNING: Shadowing outer local
local shadow_me = 1
do
local shadow_me = 2 -- Shadows outer local (warning)
print(shadow_me)
end
-- ERROR: Invalid table access
local empty_table = {}
print(empty_table.nonexistent.deeply.nested.property)
-- WARNING/HINT: Can be simplified
if true == true then -- Redundant comparison
print("always true")
end
-- ERROR: Type annotation mismatch
---@type string
local should_be_string = 123 -- Assigning number to string type
-- WARNING: Unreachable code after return
local function has_dead_code()
if true then
return "done"
end
print("This will never execute") -- Unreachable
end
-- Valid function call
print(takes_two_args(1, 2))
-- ERROR: Calling vim API that doesn't exist
vim.nonexistent_function()
-- HINT: Trailing whitespace or style issues (if configured)
local with_trailing_space = "value"
print(with_trailing_space)
-- ERROR: Parameter type mismatch
---@param name string
---@param age number
local function greet(name, age)
print("Hello, " .. name .. ", you are " .. age)
end
greet(123, "not a number") -- Wrong types
print("Diagnostic test complete!")

View file

@ -1,70 +0,0 @@
<?php
/**
* Test file for PHP LSP diagnostics
* Tests error, warning, info, and hint virtual text colors
*
* Note: Configure Intelephense to show different diagnostic levels:
* - diagnostics.undefinedSymbols = true (errors)
* - diagnostics.undefinedVariables = true (warnings)
* - diagnostics.unusedSymbols = "hint" (hints)
*/
// Define some valid functions and variables first to avoid cascading errors
function validFunction(): void {
echo "This is valid\n";
}
$definedVariable = 'I exist';
// ERROR: Undefined function
someUndefinedFunction();
// ERROR: Undefined variable
echo $completelyUndefined;
// WARNING/HINT: Unused variable (depends on Intelephense config)
$unused = 'Never used anywhere';
// Valid code to separate errors
validFunction();
// ERROR: Wrong number of arguments
function requiresTwoArgs( string $a, string $b ): void {
echo "$a $b\n";
}
requiresTwoArgs( 'only one' ); // Missing second argument
// ERROR: Type mismatch
function expectsString( string $param ): void {
echo $param;
}
expectsString( 123 ); // Passing int to string parameter
// WARNING: Variable might not be defined in all code paths
if ( rand( 0, 1 ) ) {
$maybeUndefined = 'sometimes defined';
}
// Commenting out to reduce errors: echo $maybeUndefined;
// Valid usage
echo $definedVariable . "\n";
// ERROR: Calling method on non-object
$notAnObject = 'string';
$notAnObject->someMethod();
// ERROR: Invalid array access (multiple levels)
$emptyArray = array();
echo $emptyArray['key']['nested']['deep'];
// Valid function call
requiresTwoArgs( 'hello', 'world' );
// HINT/WARNING: Unreachable code (some configs)
function hasDeadCode(): string {
return 'done';
echo 'This is unreachable'; // Dead code.
}
echo "Test complete!\n";

View file

@ -1,19 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<style>
.test-class {
color: red;
}
#test-id {
background: blue;
}
</style>
</head>
<body>
<div class="test-class" id="test-id" data-value="test">
<p>Hello World</p>
</div>
</body>
</html>

View file

@ -1,5 +0,0 @@
#!/bin/bash
# Test semantic highlights in a real Neovim session
# This will open test-html.html and check if custom captures are applied
nvim test-html.html -c "normal! 15Gf\"" -c "lua vim.defer_fn(function() vim.cmd('normal! \\<leader>hi'); vim.cmd('quitall!'); end, 500)"

View file

@ -1,11 +0,0 @@
.test-class {
color: red;
}
#test-id {
background: blue;
}
.another:hover {
border: 1px solid green;
}

View file

View file