Neovim
Neovim — Complete Developer Guide
AstroNvim v6 + lazy.nvim + Nix-provided LSP tools.
Inspired by mic92’s dotfiles. Catppuccin Mocha theme.
Architecture
Nix provides: neovim (bare, no Ruby) + 50+ LSP/formatter/linter packages
Config link: config/nvim/ → ~/.config/nvim/ (via home.configFile, recursive symlink)
Plugin manager: lazy.nvim (downloads to ~/.local/share/nvim/lazy/)
Framework: AstroNvim v6 (keybindings, UI, LSP integration, completion)
Theme: catppuccin-mocha (via astrocommunity)
Key files:
config/nvim/
init.lua Bootstrap lazy.nvim + AstroNvim
lazy-lock.json 63 pinned plugin versions
treesitter-rev Pinned treesitter commit (Nix grammar compat)
lua/plugins/
astrolsp.lua LSP server config (13 servers)
astroui.lua Theme (catppuccin-mocha)
community.lua 14 language packs + editing support
gitsigns.lua Inline git blame
hunk.lua Visual diff editor
icon-picker.lua Emoji/icon picker
languages.lua Custom filetype mappings (Snakemake, Nextflow, Zsh)
luasnip.lua Snippet engine
mappings.lua Custom keybindings
mason.lua Mason (disabled — all tools from Nix)
neo-tree.lua File explorer
none-ls.lua Formatters/linters (stylua, prettier, golangci-lint, shfmt)
spaceless.lua Strip trailing whitespace
treesitter.lua Syntax highlighting (auto-install grammars)
First Launch
After hey sync, open nvim for the first time:
- lazy.nvim clones itself from GitHub
- All 63 plugins are installed automatically
- Treesitter grammars compile from source (C compiler wrapped via Nix)
- LSP servers are already on PATH (installed by Nix)
No manual steps required. If a plugin fails to install, run :Lazy and press I to retry.
Modes (Vim Basics)
| Mode | Enter | Purpose |
|---|
| Normal | Esc | Navigation, commands (default) |
| Insert | i, a, o, I, A, O | Typing text |
| Visual | v, V, Ctrl+v | Selecting text |
| Command | : | Ex commands |
| Replace | R | Overwrite text |
Mode Transitions
Normal ──► Insert: i (cursor), a (after), o (new line below), O (above), I (line start), A (line end)
Insert ──► Normal: Esc or Ctrl+c
Normal ──► Visual: v (char), V (line), Ctrl+v (block)
Visual ──► Normal: Esc
Normal ──► Command: : (type command, Enter to execute)
File Operations
Open Files
| Action | Keybinding | Notes |
|---|
| Find files | <Space><Space> | snacks.nvim picker (fuzzy) |
| Find files (hidden) | <Space><Space> | Auto-shows hidden files inside git repos |
| Open file under cursor | gf | Creates file if it doesn’t exist |
| Recent files | <Space>fr | AstroNvim built-in |
| File explorer | <Space>e | Neo-tree toggle (git status source) |
| Explorer focus | <Space>o | Switch focus to/from neo-tree |
Save & Close
| Action | Command | Notes |
|---|
| Save | :w or Ctrl+s | Write current buffer |
| Save as sudo | :w!! | Custom command (writes via sudo tee) |
| Quit | :q | Close current window |
| Save & quit | :wq or ZZ | |
| Force quit | :q! | Discard changes |
| Close buffer | :bd | Close buffer (keeps window) |
| Close all | :qa | Quit all windows |
Buffer Navigation
| Action | Keybinding |
|---|
| Next buffer | Tab |
| Previous buffer | Shift+Tab |
| Buffer list | <Space>fb (snacks picker) |
| Delete buffer | <Space>bd (AstroNvim) |
Window Management
Splits
| Action | Keybinding | Notes |
|---|
| Vertical split | Ctrl+w v or :vsp | Split current file vertically |
| Horizontal split | Ctrl+w s or :sp | Split horizontally |
| Close window | Ctrl+w c or :q | |
| Close other windows | Ctrl+w o | Only keep current |
Navigate Windows
| Action | Keybinding |
|---|
| Move left | Ctrl+w h |
| Move down | Ctrl+w j |
| Move up | Ctrl+w k |
| Move right | Ctrl+w l |
| Cycle windows | Ctrl+w w |
Resize Windows
| Action | Keybinding |
|---|
| Wider | Ctrl+w > |
| Narrower | Ctrl+w < |
| Taller | Ctrl+w + |
| Shorter | Ctrl+w - |
| Equalize | Ctrl+w = |
Code Intelligence (LSP)
All LSP servers are installed by Nix and available on PATH. AstroNvim’s astrolsp module auto-attaches them to the right filetypes.
Navigation
| Action | Keybinding | Description |
|---|
| Go to definition | gd | Jump to where symbol is defined |
| Go to declaration | gD | Jump to declaration (C/C++) |
| Go to implementation | gi | Jump to interface implementation |
| Find references | gr | Show all references to symbol |
| Hover documentation | K | Popup with docs/type info |
| Signature help | Ctrl+k | Show function signature |
Editing
| Action | Keybinding | Description |
|---|
| Rename symbol | <Space>rn | Rename across entire project |
| Code action | <Space>ca | Quick fixes, imports, refactors |
| Format buffer | <Space>lf | Format with configured formatter |
| Format selection | <Space>lf (visual) | Format selected region |
Diagnostics
| Action | Keybinding | Description |
|---|
| Next diagnostic | ]d | Jump to next error/warning |
| Previous diagnostic | [d | Jump to previous |
| Line diagnostics | gl | Show diagnostics for current line |
| Diagnostics list | <Space>xx | Trouble.nvim toggle |
LSP Servers Installed
| Server | Languages | Notes |
|---|
basedpyright | Python | Type checking |
ruff | Python | Linting + formatting |
gopls | Go | Full Go IDE |
rust_analyzer | Rust | Full Rust IDE |
clangd | C, C++ | With UTF-8 offset encoding |
nixd + nil | Nix | Two servers for coverage |
bashls | Bash, Zsh, Sh | Shell scripts |
lua_ls | Lua | Neovim runtime aware |
vtsls | TypeScript, JavaScript | |
yamlls | YAML | |
taplo | TOML | |
terraformls | HCL, Terraform | |
typos_lsp | All | Typo detection |
zls | Zig | |
jdtls | Java | |
kotlin_language_server | Kotlin | |
ruby_lsp | Ruby | |
nil | Nix | Additional Nix support |
Completion
AstroNvim uses blink.cmp (fast Rust-based completion engine).
Completion Behavior
| Action | Key | Description |
|---|
| Trigger completion | Ctrl+Space | Manually open completion menu |
| Next item | Tab | Select next suggestion |
| Previous item | Shift+Tab | Select previous |
| Confirm | Enter | Accept selected item |
| Scroll docs | Ctrl+f / Ctrl+d | Scroll documentation popup |
| Close | Esc | Dismiss completion |
| Snippet jump | Tab | Jump to next snippet placeholder |
Completion Sources (priority order)
- LSP — code intelligence (definitions, methods, properties)
- Copilot — AI suggestions
- Snippets — LuaSnip + friendly-snippets
- Buffer — words from open buffers
- Path — file paths
- Tmux — words from other tmux panes
Copilot
- Accept suggestion:
Tab (when no completion menu visible)
- Dismiss:
Esc
- Enabled for all filetypes including
gitcommit
File Explorer (Neo-tree)
| Action | Keybinding |
|---|
| Toggle explorer | <Space>e |
| Focus explorer | <Space>o |
Inside Neo-tree
| Action | Key | Description |
|---|
| Open file | Enter | Open in current window |
| Open in split | s | Horizontal split |
| Open in vsplit | v | Vertical split |
| Open in new tab | t | New tab |
| Create file | a | Create new file (use / for dirs) |
| Create directory | a | Type dirname/ |
| Delete | d | Delete file/dir |
| Rename | r | Rename |
| Copy | y | Copy to clipboard |
| Paste | p | Paste from clipboard |
| Toggle hidden | H | Show/hide hidden files |
| Refresh | R | Refresh tree |
| Close | q | Close neo-tree |
Search & Find
AstroNvim uses snacks.nvim for fuzzy finding (replaces Telescope).
File & Text Search
| Action | Keybinding | Description |
|---|
| Find files | <Space><Space> | Fuzzy file finder |
| Live grep | <Space>fw | Search text across project |
| Grep word under cursor | <Space>* | Search for symbol under cursor |
| Find buffers | <Space>fb | Search open buffers |
| Help tags | <Space>fh | Search Neovim help |
| Recent files | <Space>fr | Recently opened files |
| Commands | <Space>fc | Search available commands |
| Keymaps | <Space>fk | Search keybindings |
Inside Picker (snacks)
| Action | Key | Description |
|---|
| Next result | Ctrl+j or Down | |
| Previous result | Ctrl+k or Up | |
| Open | Enter | Open selected |
| Open in split | Ctrl+x | Horizontal split |
| Open in vsplit | Ctrl+v | Vertical split |
| Close | Esc | Dismiss picker |
| Scroll preview | Ctrl+d / Ctrl+u | |
Git Integration
Gitsigns (inline)
| Action | Keybinding | Description |
|---|
| Next hunk | ]c | Jump to next git change |
| Previous hunk | [c | Jump to previous |
| Preview hunk | <Space>gp | Show diff popup |
| Stage hunk | <Space>gs | Stage current hunk |
| Undo stage | <Space>gu | Unstage hunk |
| Reset hunk | <Space>gr | Revert hunk |
| Blame line | <Space>gb | Show git blame for line |
| Toggle blame | <Space>gB | Inline blame (enabled by default) |
| Diff this | <Space>gd | Diff current file |
Hunk (visual diff editor)
:DiffEditor " Open visual diff/conflict resolution
Lazy-loaded — only available when invoked.
Debugging (DAP)
Debug Adapter Protocol
| Action | Keybinding | Description |
|---|
| Continue | F5 | Start/continue debugging |
| Step over | F10 | Execute next line |
| Step into | F11 | Enter function call |
| Step out | F12 | Exit current function |
| Toggle breakpoint | <Space>b | Set/remove breakpoint |
| Debug nearest | <Space>dn | Debug test under cursor |
| Debug last | <Space>dl | Re-run last debug session |
| Terminate | <Space>dT | Stop debugging session |
| Toggle REPL | <Space>dr | Open debug REPL |
| Toggle UI | <Space>du | Show/hide debug UI |
Supported Languages
| Language | Debug Adapter | Notes |
|---|
| Python | debugpy | Via nvim-dap-python |
| Go | delve | Via nvim-dap-go |
| Rust | codelldb | Via rustaceanvim |
| C/C++ | codelldb | Via clangd_extensions |
| Lua | local-lua-debugger | |
Terminal Integration
ToggleTerm
| Action | Keybinding | Description |
|---|
| Toggle terminal | <Space>tt | Floating terminal |
| Terminal (horizontal) | <Space>th | Bottom split |
| Terminal (vertical) | <Space>tv | Right split |
| Terminal (new tab) | <Space>tT | Terminal in new tab |
| Lazygit | <Space>tl | Lazygit in floating terminal |
| Node REPL | <Space>tn | Node.js REPL |
| Python REPL | <Space>tp | Python REPL |
Inside Terminal
| Action | Key | Description |
|---|
| Exit terminal mode | Ctrl+\ Ctrl+n | Return to Normal mode |
| Close terminal | Ctrl+d or exit | |
Plugin Management (lazy.nvim)
Commands
| Command | Description |
|---|
:Lazy | Open lazy.nvim UI |
:Lazy install | Install missing plugins |
:Lazy update | Update all plugins |
:Lazy clean | Remove unused plugins |
:Lazy restore | Restore to lockfile versions |
:Lazy sync | Install + clean + update |
:Lazy health | Check plugin health |
Inside lazy.nvim UI
| Action | Key | Description |
|---|
| Install | I | Install missing |
| Update | U | Update all |
| Clean | X | Remove unused |
| Sync | S | Install + clean + update |
| Restore | R | Restore lockfile |
| Check | C | Check for updates |
| Profile | P | Show startup profile |
| Close | q | Close UI |
Adding a New Plugin
- Create a new file in
config/nvim/lua/plugins/ (e.g., my-plugin.lua):
return {
"author/plugin-name",
opts = {
-- plugin options
},
}
- Reopen Neovim — lazy.nvim auto-installs it
- Commit the updated
lazy-lock.json
Pinning a Plugin Version
In the plugin spec:
return {
"author/plugin-name",
commit = "abc123", -- pin to specific commit
-- or
tag = "v1.0.0", -- pin to tag
-- or
version = "1.*", -- semver range
}
Treesitter (Syntax Highlighting)
Treesitter provides structural syntax highlighting, indentation, and text objects.
Go, Bash, HTML, CSS, C++, Lua, Markdown, Nix, Python, Rust, TOML, YAML, Zig
Additional Grammars
Auto-installed by treesitter when you open a file. Compiled from source (Nix provides the C compiler).
Text Objects (treesitter-based)
| Action | Key | Description |
|---|
| Select function | vaf / vif | Around / inside function |
| Select class | vac / vic | Around / inside class |
| Select loop | val / vil | Around / inside loop |
| Select conditional | vai / vii | Around / inside if/else |
| Select parameter | vaa / via | Around / inside argument |
| Move to next function | ]f | |
| Move to previous function | [f | |
| Move to next class | ]c | |
| Move to previous class | [c | |
Editing Features
Surround (nvim-surround)
| Action | Keys | Example |
|---|
| Add surround | ys{motion}{char} | ysiw" → wrap word in quotes |
| Delete surround | ds{char} | ds" → remove surrounding quotes |
| Change surround | cs{old}{new} | cs"' → change " to ' |
| Visual surround | S{char} | Select text, then S" |
Auto-pairs
Automatically pairs (, [, {, ", ', `. Press Enter to split pairs:
before: {|} (| is cursor)
press Enter:
{
|
}
| Action | Keybinding | Description |
|---|
| Toggle comment | gcc | Toggle line comment |
| Comment motion | gc{motion} | gcip = comment paragraph |
| Visual comment | gc | Comment selected lines |
| Block comment | gbc | Toggle block comment |
Indentation
| Action | Key | Description |
|---|
| Indent | >> | Indent line |
| Unindent | << | Unindent line |
| Visual indent | > / < | Indent/unindent selection |
| Re-indent | = | Auto-indent (treesitter-aware) |
| Re-indent buffer | gg=G | Re-indent entire file |
Whitespace
- spaceless.nvim automatically strips trailing whitespace on save
- indent-blankline shows indent guides
Workflow: Snakemake & Nextflow
Snakemake
Files *.smk, *.snakefile, Snakefile are treated as Python:
- Treesitter Python highlighting
basedpyright + ruff LSP
black + isort formatting
Nextflow
Files *.nf, nextflow.config are treated as Groovy:
- Treesitter Groovy highlighting (auto-installed)
- No dedicated LSP (limited ecosystem)
Customization
Changing Theme
Edit config/nvim/lua/plugins/astroui.lua:
return {
"AstroNvim/astroui",
opts = {
colorscheme = "catppuccin-mocha", -- change here
},
}
Available catppuccin flavors: catppuccin-latte, catppuccin-frappe, catppuccin-macchiato, catppuccin-mocha
Adding Custom Keybindings
Edit config/nvim/lua/plugins/mappings.lua:
mappings = {
n = {
["<leader>xx"] = { "<cmd>echo 'hello'<cr>", desc = "Say hello" },
},
},
Adding LSP Servers
Edit config/nvim/lua/plugins/astrolsp.lua:
vim.list_extend(opts.servers, {
"bashls", "clangd", -- ... existing servers
"new_server", -- add here
})
Also add the Nix package to modules/editors/vim.nix under nvim-lsp-packages.
Edit config/nvim/lua/plugins/none-ls.lua:
config.sources = astrocore.list_insert_unique(config.sources, {
null_ls.builtins.formatting.new_formatter,
null_ls.builtins.diagnostics.new_linter,
})
Quick Reference Card
NAVIGATION LSP
<Space><Space> Find files gd Go to definition
<Space>fw Grep text gr Find references
<Space>* Grep cursor word K Hover docs
<Space>e File explorer <Space>rn Rename
<Space>o Focus explorer <Space>ca Code action
Tab / S-Tab Next/prev buffer ]d / [d Next/prev diagnostic
EDITING GIT
gcc Comment line ]c / [c Next/prev hunk
ys{m}{c} Add surround <Space>gs Stage hunk
ds{c} Delete surround <Space>gp Preview hunk
>> / << Indent/unindent <Space>gb Blame line
WINDOWS DEBUG
Ctrl+w v Vertical split F5 Continue
Ctrl+w s Horizontal split F10 Step over
Ctrl+w h/j/k/l Navigate F11 Step into
Ctrl+w c Close window <Space>b Breakpoint
SEARCH TERMINAL
<Space>fw Live grep <Space>tt Toggle terminal
<Space>fb Buffers <Space>tl Lazygit
<Space>fh Help tags Ctrl+\ Ctrl+n Exit term mode
PLUGIN MANAGEMENT
:Lazy Open UI
I / U / X Install / Update / Clean
R Restore lockfile
Troubleshooting
LSP not attaching
- Check
:LspInfo — shows which servers are attached
- Check
:checkhealth lsp — diagnostic info
- Verify the server is on PATH:
which gopls etc.
Treesitter grammar not found
- Run
:TSInstall <language> to manually install
- Or restart nvim — auto-install should trigger
Plugin not loading
- Run
:Lazy — check plugin status
- Run
:checkhealth lazy — check lazy.nvim health
- Delete
~/.local/share/nvim/lazy/ and restart for clean install
Slow startup
- Run
:Lazy profile — shows load times per plugin
- Check for conflicting plugins
- Verify treesitter grammars are compiled (not downloading)
Copilot not working
- Run
:Copilot setup — authenticate with GitHub
- Check
:Copilot status — verify connection
- Requires
nodejs on PATH (provided by Nix)
| Doc | What it covers |
|---|
editors.md | Multi-editor architecture, VS Code extensions, shared config |
keybindings.md | System-wide keybindings (Hyprland, Niri, Tmux, Zsh) |
toolchain.md | hey CLI, hooks, binscripts |
themes.md | Catppuccin theming across apps |