nvim/README.md

502 lines
16 KiB
Markdown

# Neovim Config Reference
Living reference for session management, keymaps, commands, and plugin-specific features in this config.
## 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
- 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 | `<Nop>` so LSP buffers can override cleanly |
| n | `gI` | LSP implementation placeholder | `<Nop>` so LSP buffers can override cleanly |
| n | `K` | Keyword help fallback | Uses `keywordprg` (e.g., `man`) when LSP hover is unavailable |
| n | `<leader>xx` | Diagnostics → location list | Populates current buffer diagnostics |
| n | `<leader>xX` | Diagnostics → quickfix | Populates project-wide diagnostics |
| n | `<leader>xe` | Diagnostics → buffer errors | Location list filtered to errors |
| n | `<leader>xE` | Diagnostics → all errors | Quickfix filtered to errors |
| n | `[d` | Diagnostics: previous item | Uses `vim.diagnostic.goto_prev` |
| n | `]d` | Diagnostics: next item | Uses `vim.diagnostic.goto_next` |
| n | `<leader>xd` | Diagnostic float | Opens hover window for cursor diagnostic |
| n | `<leader>xt` | Toggle diagnostics | Flips `vim.diagnostic.enable()` |
| n | `<leader>hi` | Highlight inspector | Shows highlight/capture stack under cursor |
### `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 | `<leader>nt` | Open netrw in new tab at current file's directory |
| n | `<leader>nT` | Open netrw in new tab at project root |
| n | `<leader>nr` | Open netrw in current window at project root |
**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 |
| --- | --- |
| `<CR>` | 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` | Preview file in horizontal split (50% window size) |
| `P` | Open file in previous window |
| `o` | Open file in horizontal split below |
| `v` | Open file in vertical split |
##### 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 | `<leader>lt` | Toggle format-on-save flag |
| n | `<leader>lf` | Format current buffer (synchronous) |
| v | `<leader>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 | `<leader>hs` | Stage current hunk |
| n | `<leader>hr` | Reset current hunk |
| v | `<leader>hs` | Stage visually selected range as hunk |
| v | `<leader>hr` | Reset visually selected range |
| n | `<leader>hS` | Stage entire buffer |
| n | `<leader>hu` | Undo last staged hunk |
| n | `<leader>hR` | Reset entire buffer |
| n | `<leader>hp` | Preview hunk |
| n | `<leader>hd` | Diff against index |
| n | `<leader>hD` | Diff against previous commit (`~`) |
| n | `<leader>hq` | Send all hunks to quickfix list |
| n | `<leader>hl` | Send buffer hunks to location list |
| o/x | `ih` | Text object: select git hunk |
### Telescope `lua/plugins/telescope.lua`
#### Keymaps
##### Launcher mappings (normal mode)
| Key | Description |
| --- | --- |
| `<leader>ff` | Find files |
| `<leader>fg` | Live grep |
| `<leader>fb` | Open buffers picker (`<C-d>` deletes buffers in picker) |
| `<leader>fh` | Help tags |
| `<leader>fr` | Recent files (oldfiles) |
| `<leader>/` | Fuzzy search current buffer |
| `<leader>fk` / `<leader>?` | Telescope keymaps picker |
| `<leader>fc` | Commands picker |
| `<leader>fs` | LSP document symbols |
| `<leader>fS` | LSP workspace symbols |
##### Telescope prompt mappings (`defaults.mappings`)
| Mode | Key | Description |
| --- | --- | --- |
| i | `<C-n>` / `<C-j>` | Move selection down |
| i | `<C-p>` / `<C-k>` | Move selection up |
| i | `<C-c>` | Close picker |
| i | `<CR>` | Accept selection |
| i | `<C-x>` | Open selection in horizontal split |
| i | `<C-v>` | Open selection in vertical split |
| i | `<C-t>` | Open selection in tab |
| n | `<Esc>` | Close picker |
| n | `<CR>` | Accept selection |
| n | `<C-x>` | Horizontal split |
| n | `<C-v>` | Vertical split |
| n | `<C-t>` | New tab |
| n | `j` | Move selection down |
| n | `k` | Move selection up |
##### Picker-specific overrides
| Context | Mode | Key | Description |
| --- | --- | --- | --- |
| `buffers` picker | i | `<C-d>` | Delete highlighted buffer |
### Oil `lua/plugins/oil.lua`
#### Keymaps
##### Global launcher mappings
| Mode | Key | Description |
| --- | --- | --- |
| n | `<leader>fo` | Open Oil in current window |
| n | `<leader>fO` | Open Oil in floating window |
##### Oil buffer mappings (`opts.keymaps`)
| Key | Description |
| --- | --- |
| `g?` | Show Oil help |
| `<CR>` | Open entry in current window |
| `<C-s>` | Open entry in vertical split |
| `<C-h>` | Open entry in horizontal split |
| `<C-t>` | Open entry in new tab |
| `<C-p>` | Preview entry (vertical split belowright) |
| `<C-c>` | Close Oil |
| `<C-l>` | Refresh |
| `-` | Go to parent directory |
| `_` | Open Neovim cwd |
| `` ` `` | `:cd` into entry |
| `~` | `:tcd` into entry |
| `gs` | Change sort mode |
| `gx` | Open entry externally |
| `g.` | Toggle hidden files |
| `g\` | Toggle trash visibility |
### 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 | `<C-u>` / `<C-d>` | Scroll within UFO preview |
| preview window | `[` / `]` | Jump to top/bottom of preview |
### Undotree `lua/plugins/undotree.lua`
#### Keymaps
| Mode | Key | Description |
| --- | --- | --- |
| n | `<leader>u` | Toggle Undotree panel |
### Treesitter `lua/plugins/treesitter.lua`
#### Keymaps
##### Incremental selection
| Key | Description |
| --- | --- |
| `+` | Initialize/expand selection |
| `g+` | Expand to scope |
| `-` | Shrink selection |
##### Textobject selection (`select.keymaps`)
| 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 (`move` mappings)
| 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 |
| --- | --- |
| `<leader>a` | Swap parameter with next |
| `<leader>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`
#### 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 | `<C-g>s` | Surround following text object |
| insert | `<C-g>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) |
### Nvim-cmp (Completion) `lua/plugins/cmp.lua`
#### Keymaps
| Mode | Key | Description |
| --- | --- | --- |
| insert | `<C-Space>` | Manually trigger completion |
| insert | `<CR>` | Confirm selection (selects first item by default) |
| insert | `<C-n>` | Next completion item |
| insert | `<C-p>` | Previous completion item |
| insert | `<C-e>` | Abort completion menu |
### Nvim-autopairs `lua/plugins/autopairs.lua`
#### Keymaps
| Mode | Key | Description |
| --- | --- | --- |
| insert | `<M-e>` | Fast wrap the previous text with a pair |
## Configuration
### 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**: handled by `ruff` LSP (not conform)
**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
<?xml version="1.0"?>
<ruleset name="Custom">
<description>Project-specific PHP rules</description>
<rule ref="PSR12"/>
<!-- or: <rule ref="WordPress-Core"/> -->
<!-- Customize rules -->
<rule ref="Generic.Files.LineLength">
<properties>
<property name="lineLimit" value="120"/>
</properties>
</rule>
</ruleset>
```
**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
<?xml version="1.0"?>
<ruleset name="PSR-12">
<rule ref="PSR12"/>
</ruleset>
```
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**: `<leader>lt` (see keymaps below)
- **Manual format**: `<leader>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 <path>` to manually change directory if needed (affects Telescope search scope)