nvim/README.md

19 KiB

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.

Session Management

Session support is automatic but user-controlled:

Manual session creation (one-time):

: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:

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>co Quickfix: Open Opens quickfix window
n <leader>cc Quickfix: Close Closes quickfix window
n <leader>lo Location list: Open Opens location list window
n <leader>lc Location list: Close Closes location list window
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.jump with a negative count
n ]d Diagnostics: next item Uses vim.diagnostic.jump with a positive count
n <leader>xd Diagnostic float Opens hover window for cursor diagnostic
n <leader>xt Toggle diagnostics Flips vim.diagnostic.enable()
n <leader>gg Git: Changed files → quickfix Lists all modified/deleted/untracked files with status
n <leader>hi Highlight inspector Shows highlight/capture stack under cursor
n <leader>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 <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
n <C-6> / <C-^> 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
<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 the selected file or directory below and enable live cursor updates
j / k Update an existing preview to the newly selected entry
:pclose / <C-w>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.

Opening a file with <CR>, o, v, or t, or otherwise leaving netrw, closes the preview. Closing it manually also 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 <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
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

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

Native Undotree lua/keymaps.lua

Keymaps

Mode Key Description
n <leader>u Toggle Neovim's native Undotree panel (:Undotree)

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

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 <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)

Native Completion lua/completion.lua

Keymaps

Mode Key Description
insert <C-Space> Manually trigger LSP completion
insert <C-n> Next completion item
insert <C-p> Previous completion item
insert <C-y> Accept the explicitly selected completion item
insert <C-e> Dismiss the completion menu
insert <C-x><C-n> Complete words from the current buffer
insert <C-x><C-f> Complete a filesystem path
insert/select <Tab> / <S-Tab> 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 <C-x><C-n>. Buffers without an LSP autocomplete from a bounded set of nearby words.

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 <M-l> Accept the visible Copilot suggestion
insert <M-]> Show the next Copilot suggestion
insert <M-[> Show the previous Copilot suggestion
insert <C-]> Dismiss the Copilot suggestion

Nvim-autopairs lua/plugins/autopairs.lua

Keymaps

Mode Key Description
insert <M-e> 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 <leader>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.

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 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 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)