# Neovim Config Reference Living reference for session management, keymaps, commands, and plugin-specific features in this config. 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: **Manual session creation** (one-time): ```vim :mksession # Creates Session.vim in current directory ``` **Auto-load/save** (via `lua/autocmds.lua`): - On startup: auto-loads `Session.vim` if it exists (unless files specified on command line) - On exit: auto-saves to `Session.vim` if it already exists - Netrw and its preview windows are omitted from the saved layout; generated `NetrwTreeListing` buffers are not restorable - Missing files are removed from restored buffers and argument lists, so deleted files cannot become persistent empty session buffers - Sessions are per-directory and opt-in (just create one to start using) **Stop using a session**: ```bash rm Session.vim # Won't auto-create a new one ``` ## Keymaps ### `:KeymapsGuide` (`lua/keymaps_reference.lua`) | Command | Description | | --- | --- | | `:KeymapsGuide` | Open a floating window with a dynamically generated list of all user-defined keymaps | ### `lua/keymaps.lua` Core keymaps available globally (not plugin-specific). These provide fallbacks for LSP features and diagnostic navigation. | Mode | Key | Description | Notes | | --- | --- | --- | --- | | n | `gd` | Vim goto-definition fallback | Executes `normal! gd` for tags/include jumps when no LSP | | n | `gD` | Vim goto-declaration fallback | Executes `normal! gD` | | n | `gr` | LSP references placeholder | `` so LSP buffers can override cleanly | | n | `gI` | LSP implementation placeholder | `` so LSP buffers can override cleanly | | n | `K` | Keyword help fallback | Uses `keywordprg` (e.g., `man`) when LSP hover is unavailable | | n | `co` | Quickfix: Open | Opens quickfix window | | n | `cc` | Quickfix: Close | Closes quickfix window | | n | `lo` | Location list: Open | Opens location list window | | n | `lc` | Location list: Close | Closes location list window | | n | `xx` | Diagnostics → location list | Populates current buffer diagnostics | | n | `xX` | Diagnostics → quickfix | Populates project-wide diagnostics | | n | `xe` | Diagnostics → buffer errors | Location list filtered to errors | | n | `xE` | Diagnostics → all errors | Quickfix filtered to errors | | n | `[d` | Diagnostics: previous item | Uses `vim.diagnostic.jump` with a negative count | | n | `]d` | Diagnostics: next item | Uses `vim.diagnostic.jump` with a positive count | | n | `xd` | Diagnostic float | Opens hover window for cursor diagnostic | | n | `xt` | Toggle diagnostics | Flips `vim.diagnostic.enable()` | | n | `gg` | Git: Changed files → quickfix | Lists all modified/deleted/untracked files with status | | n | `hi` | Highlight inspector | Shows highlight/capture stack under cursor | | n | `bg` | Toggle background (light/dark) | Switches between light and dark colorscheme modes | ### `lua/netrw-config.lua` #### `:Ex` Command Variants | Command | Opens netrw at | | --- | --- | | `:Ex` | Current working directory (`:pwd`) | | `:Ex .` | Current file's directory | | `:Ex %:h` | Current file's directory (explicit) | | `:Ex /path/to/dir` | Specific path | #### Custom Keymaps | Mode | Key | Description | | --- | --- | --- | | n | `nt` | Open netrw in new tab at current file's directory | | n | `nT` | Open netrw in new tab at project root | | n | `nr` | Open netrw in current window at project root | | n | `` / `` | Jump to alternate file, skipping netrw explorer buffers | **Note:** Project root is stored as the initial working directory when Neovim starts. This allows navigation back to the project root even after following symlinks to external directories. #### Default Netrw Keymaps ##### Navigation & View | Key | Description | | --- | --- | | `` | Open file/directory under cursor | | `-` | Go up to parent directory | | `gh` | Toggle hidden files visibility (dotfiles) | | `i` | Cycle through view types (thin/long/wide/tree) | | `s` | Cycle sort order (name/time/size/extension) | | `r` | Reverse current sort order | | `I` | Toggle netrw banner (help text) | ##### Preview & Splits | Key | Description | | --- | --- | | `p` | Toggle the selected file/directory preview and live cursor updates | | `j` / `k` | Update an existing preview to the newly selected entry | | `` / `` | Scroll the preview down/up without leaving netrw; accepts a count | | `:pclose` / `z` | Close the preview and stop live updates | | `P` | Open file in previous window | | `o` | Open file in horizontal split below | | `v` | Open file in vertical split | | `t` | Open file in a new tab | Regular files use netrw's native preview. Directories show a read-only summary of their immediate children, including type, file size, modification time, and a total for immediate files. Directories appear first, output is capped at 200 entries, and symbolic links are displayed without following them recursively. File previews retain Tree-sitter or Vim syntax highlighting while suppressing diagnostics and indent guides. The buffer's prior diagnostic and indent-guide state returns automatically when a previewed file is opened for editing. Preview-only file buffers remain loaded but unlisted until Neovim exits, retaining the lifecycle protection added for rapid preview replacement. Opening a file with ``, `o`, `v`, or `t`, or otherwise leaving netrw, closes the preview. Closing it manually or pressing `p` again disables live updates until `p` is pressed again. Enhanced directory summaries apply to local paths (including local paths when Neovim runs over SSH); netrw URI browsing retains its native preview behavior. ##### File Operations | Key | Description | | --- | --- | | `%` | Create new file (prompts for name) | | `d` | Create new directory (prompts for name) | | `D` | Delete file/directory under cursor | | `R` | Rename/move file under cursor | ##### Marking & Batch Operations | Key | Description | | --- | --- | | `mf` | Mark file (for batch operations) | | `mr` | Mark files using regex pattern | | `mu` | Unmark all marked files | | `mt` | Set mark target directory (for move/copy destination) | | `mc` | Copy marked files to target directory | | `mm` | Move marked files to target directory | | `qf` | Display file info | ## Plugin Reference ### LSP `lua/plugins/lsp.lua` #### Keymaps Buffer-local keymaps available when an LSP client attaches: | Mode | Key | Description | | --- | --- | --- | | n | `gd` | LSP: go to definition | | n | `gr` | LSP: references | | n | `gD` | LSP: declaration | | n | `gI` | LSP: implementation | | n | `K` | LSP hover | ### Conform (Formatting) `lua/plugins/conform.lua` #### Keymaps | Mode | Key | Description | | --- | --- | --- | | n | `lt` | Toggle format-on-save flag | | n | `lf` | Format current buffer (synchronous) | | v | `lf` | Format visual selection | ### Nvim-lint `lua/plugins/nvim-lint.lua` #### Commands | Command | Description | | --- | --- | | `:MarkdownLintEnable` | Enable automatic markdown linting (runs on BufEnter, BufWritePost, InsertLeave) | | `:MarkdownLintDisable` | Disable automatic markdown linting and clear diagnostics | **Note:** Markdown linting is disabled by default. Spellcheck is always enabled for markdown files. ### Gitsigns `lua/plugins/gitsigns.lua` #### Keymaps Buffer-local keymaps available when inside a git repository: | Mode | Key | Description | | --- | --- | --- | | n | `]h` | Next hunk (`expr` mapping that respects `diff` windows) | | n | `[h` | Previous hunk | | n | `hs` | Stage current hunk | | n | `hr` | Reset current hunk | | v | `hs` | Stage visually selected range as hunk | | v | `hr` | Reset visually selected range | | n | `hS` | Stage entire buffer | | n | `hu` | Undo last staged hunk | | n | `hR` | Reset entire buffer | | n | `hp` | Preview hunk | | n | `hd` | Diff against index | | n | `hD` | Diff against previous commit (`~`) | | n | `hq` | Send all hunks to quickfix list | | o/x | `ih` | Text object: select git hunk | ### Telescope `lua/plugins/telescope.lua` #### Keymaps ##### Launcher mappings (normal mode) | Key | Description | | --- | --- | | `ff` | Find files | | `fg` | Live grep | | `fb` | Open buffers picker (`` deletes buffers in picker) | | `fh` | Help tags | | `fr` | Recent files (oldfiles) | | `/` | Fuzzy search current buffer | | `fk` / `?` | Telescope keymaps picker | | `fc` | Commands picker | | `fs` | LSP document symbols | | `fS` | LSP workspace symbols | ##### Telescope prompt mappings (`defaults.mappings`) | Mode | Key | Description | | --- | --- | --- | | i | `` / `` | Move selection down | | i | `` / `` | Move selection up | | i | `` | Close picker | | i | `` | Accept selection | | i | `` | Open selection in horizontal split | | i | `` | Open selection in vertical split | | i | `` | Open selection in tab | | n | `` | Close picker | | n | `` | Accept selection | | n | `` | Horizontal split | | n | `` | Vertical split | | n | `` | New tab | | n | `j` | Move selection down | | n | `k` | Move selection up | ##### Picker-specific overrides | Context | Mode | Key | Description | | --- | --- | --- | --- | | `buffers` picker | i | `` | Delete highlighted buffer | ### UFO (Folding) `lua/plugins/ufo.lua` #### Keymaps | Mode | Key | Description | | --- | --- | --- | | n | `zR` | Open all folds | | n | `zM` | Close all folds | | n | `zr` | Open folds except configured kinds | | n | `zm` | Close folds with configured kinds | | n | `K` | Peek fold under cursor; falls back to LSP hover | | preview window | `` / `` | Scroll within UFO preview | | preview window | `[` / `]` | Jump to top/bottom of preview | ### Native Undotree `lua/keymaps.lua` #### Keymaps | Mode | Key | Description | | --- | --- | --- | | n | `u` | Toggle Neovim's native Undotree panel (`:Undotree`) | ### 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 to the parent node | | `g+` | Expand to scope | | `-` | Shrink selection to the child node | ##### Textobject selection | Key | Target | | --- | --- | | `af` / `if` | Function outer / inner | | `ac` / `ic` | Class outer / inner | | `aa` / `ia` | Parameter outer / inner | | `ai` / `ii` | Conditional outer / inner | | `al` / `il` | Loop outer / inner | | `a/` | Comment outer | ##### Textobject movement | Key | Action | | --- | --- | | `]f` / `]F` | Next function start / end | | `[f` / `[F` | Previous function start / end | | `]c` / `]C` | Next class start / end | | `[c` / `[C` | Previous class start / end | | `]a` / `]A` | Next parameter start / end | | `[a` / `[A` | Previous parameter start / end | ##### Parameter swapping | Key | Description | | --- | --- | | `a` | Swap parameter with next | | `A` | Swap parameter with previous | ### Comment.nvim `lua/plugins/comment.lua` #### Keymaps | Mapping | Description | | --- | --- | | `gcc` | Toggle line comment | | `gbc` | Toggle block comment | | `gc` | Operator-pending line comment | | `gb` | Operator-pending block comment | | `gcO` / `gco` / `gcA` | Insert comment above / below / end-of-line | ### Nvim-surround `lua/plugins/surround.lua` The configuration uses nvim-surround v4's default mappings. #### Keymaps | Mode | Mapping | Description | | --- | --- | --- | | normal | `ys{motion}{char}` | Add surround to motion | | normal | `yss` | Surround current line | | normal | `yS` | Surround motion with linewise behavior | | normal | `ySS` | Surround current line linewise | | insert | `s` | Surround following text object | | insert | `S` | Surround current line | | visual | `S` | Surround selection | | visual line | `gS` | Surround visual-line selection | | normal | `ds{char}` | Delete surround | | normal | `cs{old}{new}` | Change surround | | normal | `cS{old}{new}` | Change surround (linewise) | ### Native Completion `lua/completion.lua` #### Keymaps | Mode | Key | Description | | --- | --- | --- | | insert | `` | Manually trigger LSP completion | | insert | `` | Next completion item | | insert | `` | Previous completion item | | insert | `` | Accept the explicitly selected completion item | | insert | `` | Dismiss the completion menu | | insert | `` | Complete words from the current buffer | | insert | `` | Complete a filesystem path | | insert/select | `` / `` | Jump forward/backward through native snippet tabstops | Completion opens automatically after a 150 ms delay, uses fuzzy matching, and does not preselect an item. LSP buffers prioritize language-aware results exclusively; buffer words remain available explicitly with ``. Buffers without an LSP autocomplete from a bounded set of nearby words. Native completion is disabled in Telescope prompts so it does not obscure picker results. ### Copilot Inline Suggestions `lua/plugins/copilot.lua` Copilot appears as ghost text rather than as an item in the native completion menu. Suggestions are hidden while that menu is visible. | Mode | Key | Description | | --- | --- | --- | | insert | `` | Accept the visible Copilot suggestion | | insert | `` | Show the next Copilot suggestion | | insert | `` | Show the previous Copilot suggestion | | insert | `` | Dismiss the Copilot suggestion | ### Nvim-autopairs `lua/plugins/autopairs.lua` #### Keymaps | Mode | Key | Description | | --- | --- | --- | | insert | `` | Fast wrap the previous text with a pair | ## Configuration ### Colorscheme `paper-tonic-modern` is built into this repository and loaded from `colors/paper-tonic-modern.lua`. Its modular highlight definitions live under `lua/paper-tonic-modern/` and cover the editor UI, traditional syntax, Tree-sitter captures, LSP diagnostics, and the configured plugins. The theme follows the system light/dark preference at startup. Use `bg` to toggle the background manually. Custom HTML and CSS Tree-sitter queries keep matching classes and IDs visually consistent across both languages. ### Project-Local LSP Settings Native `exrc` and `secure` support are enabled. A trusted `.nvim.lua` can return an `lsp` table keyed by server name; settings are securely read from the attached LSP client's root and sent through `workspace/didChangeConfiguration`. ```lua return { lsp = { intelephense = { settings = { intelephense = { environment = { includePaths = { "vendor/package/src" }, }, }, }, }, }, } ``` ### Formatting & Linting This config uses **conform.nvim** for formatting and **nvim-lint** for diagnostics. Both prefer project-local tools over global installations. #### Executable Resolution Order When looking for formatters/linters, the config searches in this priority: 1. **Project-local** (e.g., `node_modules/.bin/`, `vendor/bin/`) 2. **Mason-managed** (`~/.local/share/nvim/mason/bin/`) 3. **System PATH** (globally installed tools) Conform.nvim handles this resolution automatically via its built-in `util.find_executable()`. nvim-lint uses a custom `find_executable()` helper in `lua/plugins/nvim-lint.lua`. #### Configured Tools **Formatters** (`lua/plugins/conform.lua`): - **JavaScript/TypeScript/CSS/JSON/HTML/Markdown**: `prettier` - **PHP**: `phpcbf` (WordPress standard by default) - **Lua**: `stylua` - **Python**: `ruff_format` **Linters** (`lua/plugins/nvim-lint.lua`): - **JavaScript/TypeScript**: `eslint_d` - **PHP**: `phpcs` (WordPress standard by default) - **Markdown**: `markdownlint` (disabled by default; use `:MarkdownLintEnable`) - **Python**: handled by `ruff` LSP (not nvim-lint) #### Project-Specific Overrides Both formatters and linters respect project-level configuration files: **PHP** (phpcbf + phpcs): - Create `phpcs.xml` or `phpcs.xml.dist` in your project root - When present, this file controls the coding standard (e.g., PSR-12, WordPress, custom) - When absent, defaults to `--standard=WordPress` Example `phpcs.xml`: ```xml Project-specific PHP rules ``` **JavaScript/TypeScript** (prettier + eslint): - Project config files: `.prettierrc`, `.eslintrc.json`, `eslint.config.js`, etc. - Global fallback: `~/.eslintrc.json` (when no project config exists) **Lua** (stylua): - Project config: `stylua.toml` or `.stylua.toml` - Falls back to stylua defaults if not present **Markdown** (markdownlint): - Project config: `.markdownlint.json`, `.markdownlintrc` #### Changing Standards Per-Project To switch a PHP project from WordPress to PSR-12: 1. Create `phpcs.xml` in project root: ```xml ``` 2. Restart Neovim (or reload config: `:source $MYVIMRC`) Both `phpcs` and `phpcbf` will now use PSR-12 rules in that project. #### Format-on-Save - **Enabled by default** for all supported filetypes - **Toggle**: `lt` (see keymaps below) - **Manual format**: `lf` (buffer or visual selection) #### Linting Behavior - **Automatic**: Runs on `BufEnter`, `BufWritePost`, `InsertLeave` - **Per-filetype**: Configured in `lint.linters_by_ft` table - **Markdown**: Opt-in only (`:MarkdownLintEnable` / `:MarkdownLintDisable`) ## Configuration Options ### Tabline Display Custom tabline shows intelligent path shortening with two configurable options. **Location:** `lua/settings.lua` (configured via `utils.tabline_full_parents` and `utils.tabline_shorten_length`) **Configuration Options:** 1. **`utils.tabline_full_parents`** (default: `1`) - Number of parent directories to show in full 2. **`utils.tabline_shorten_length`** (default: `3`) - Number of characters to show for shortened directories **Examples:** With `full_parents = 1, shorten_length = 3`: - `/path/to/my/project/src/file.txt` → `pat/to/my/project/src/file.txt` With `full_parents = 2, shorten_length = 3`: - `/path/to/my/project/src/file.txt` → `pat/to/my/project/src/file.txt` With `full_parents = 1, shorten_length = 1`: - `/path/to/my/project/src/file.txt` → `p/t/m/project/src/file.txt` With `full_parents = 0, shorten_length = 3`: - `/path/to/my/project/src/file.txt` → `pat/to/my/pro/src/file.txt` The last N parent directories are shown in full, earlier directories are shortened to the specified number of characters. The filename itself is always shown in full. **To customize:** Edit `utils.tabline_full_parents` and `utils.tabline_shorten_length` values in `lua/settings.lua` ## Working Directory Behavior The working directory (`:pwd`) is locked to the directory where you opened Neovim and does NOT change when switching files: - `autochdir` is disabled (working directory stays fixed at project root) - `netrw_keepdir = 1` prevents netrw from changing directory when browsing - Project root is captured at startup in `vim.g.project_root` (used by Telescope and netrw) - Telescope searches from the initial project root regardless of current buffer - Use `:cd ` to manually change directory if needed (affects Telescope search scope)