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:

  1. lazy.nvim clones itself from GitHub
  2. All 63 plugins are installed automatically
  3. Treesitter grammars compile from source (C compiler wrapped via Nix)
  4. 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)

ModeEnterPurpose
NormalEscNavigation, commands (default)
Inserti, a, o, I, A, OTyping text
Visualv, V, Ctrl+vSelecting text
Command:Ex commands
ReplaceROverwrite 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

ActionKeybindingNotes
Find files<Space><Space>snacks.nvim picker (fuzzy)
Find files (hidden)<Space><Space>Auto-shows hidden files inside git repos
Open file under cursorgfCreates file if it doesn’t exist
Recent files<Space>frAstroNvim built-in
File explorer<Space>eNeo-tree toggle (git status source)
Explorer focus<Space>oSwitch focus to/from neo-tree

Save & Close

ActionCommandNotes
Save:w or Ctrl+sWrite current buffer
Save as sudo:w!!Custom command (writes via sudo tee)
Quit:qClose current window
Save & quit:wq or ZZ
Force quit:q!Discard changes
Close buffer:bdClose buffer (keeps window)
Close all:qaQuit all windows

Buffer Navigation

ActionKeybinding
Next bufferTab
Previous bufferShift+Tab
Buffer list<Space>fb (snacks picker)
Delete buffer<Space>bd (AstroNvim)

Window Management

Splits

ActionKeybindingNotes
Vertical splitCtrl+w v or :vspSplit current file vertically
Horizontal splitCtrl+w s or :spSplit horizontally
Close windowCtrl+w c or :q
Close other windowsCtrl+w oOnly keep current
ActionKeybinding
Move leftCtrl+w h
Move downCtrl+w j
Move upCtrl+w k
Move rightCtrl+w l
Cycle windowsCtrl+w w

Resize Windows

ActionKeybinding
WiderCtrl+w >
NarrowerCtrl+w <
TallerCtrl+w +
ShorterCtrl+w -
EqualizeCtrl+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.

ActionKeybindingDescription
Go to definitiongdJump to where symbol is defined
Go to declarationgDJump to declaration (C/C++)
Go to implementationgiJump to interface implementation
Find referencesgrShow all references to symbol
Hover documentationKPopup with docs/type info
Signature helpCtrl+kShow function signature

Editing

ActionKeybindingDescription
Rename symbol<Space>rnRename across entire project
Code action<Space>caQuick fixes, imports, refactors
Format buffer<Space>lfFormat with configured formatter
Format selection<Space>lf (visual)Format selected region

Diagnostics

ActionKeybindingDescription
Next diagnostic]dJump to next error/warning
Previous diagnostic[dJump to previous
Line diagnosticsglShow diagnostics for current line
Diagnostics list<Space>xxTrouble.nvim toggle

LSP Servers Installed

ServerLanguagesNotes
basedpyrightPythonType checking
ruffPythonLinting + formatting
goplsGoFull Go IDE
rust_analyzerRustFull Rust IDE
clangdC, C++With UTF-8 offset encoding
nixd + nilNixTwo servers for coverage
bashlsBash, Zsh, ShShell scripts
lua_lsLuaNeovim runtime aware
vtslsTypeScript, JavaScript
yamllsYAML
taploTOML
terraformlsHCL, Terraform
typos_lspAllTypo detection
zlsZig
jdtlsJava
kotlin_language_serverKotlin
ruby_lspRuby
nilNixAdditional Nix support

Completion

AstroNvim uses blink.cmp (fast Rust-based completion engine).

Completion Behavior

ActionKeyDescription
Trigger completionCtrl+SpaceManually open completion menu
Next itemTabSelect next suggestion
Previous itemShift+TabSelect previous
ConfirmEnterAccept selected item
Scroll docsCtrl+f / Ctrl+dScroll documentation popup
CloseEscDismiss completion
Snippet jumpTabJump to next snippet placeholder

Completion Sources (priority order)

  1. LSP — code intelligence (definitions, methods, properties)
  2. Copilot — AI suggestions
  3. Snippets — LuaSnip + friendly-snippets
  4. Buffer — words from open buffers
  5. Path — file paths
  6. 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)

ActionKeybinding
Toggle explorer<Space>e
Focus explorer<Space>o

Inside Neo-tree

ActionKeyDescription
Open fileEnterOpen in current window
Open in splitsHorizontal split
Open in vsplitvVertical split
Open in new tabtNew tab
Create fileaCreate new file (use / for dirs)
Create directoryaType dirname/
DeletedDelete file/dir
RenamerRename
CopyyCopy to clipboard
PastepPaste from clipboard
Toggle hiddenHShow/hide hidden files
RefreshRRefresh tree
CloseqClose neo-tree

Search & Find

AstroNvim uses snacks.nvim for fuzzy finding (replaces Telescope).

ActionKeybindingDescription
Find files<Space><Space>Fuzzy file finder
Live grep<Space>fwSearch text across project
Grep word under cursor<Space>*Search for symbol under cursor
Find buffers<Space>fbSearch open buffers
Help tags<Space>fhSearch Neovim help
Recent files<Space>frRecently opened files
Commands<Space>fcSearch available commands
Keymaps<Space>fkSearch keybindings

Inside Picker (snacks)

ActionKeyDescription
Next resultCtrl+j or Down
Previous resultCtrl+k or Up
OpenEnterOpen selected
Open in splitCtrl+xHorizontal split
Open in vsplitCtrl+vVertical split
CloseEscDismiss picker
Scroll previewCtrl+d / Ctrl+u

Git Integration

Gitsigns (inline)

ActionKeybindingDescription
Next hunk]cJump to next git change
Previous hunk[cJump to previous
Preview hunk<Space>gpShow diff popup
Stage hunk<Space>gsStage current hunk
Undo stage<Space>guUnstage hunk
Reset hunk<Space>grRevert hunk
Blame line<Space>gbShow git blame for line
Toggle blame<Space>gBInline blame (enabled by default)
Diff this<Space>gdDiff current file

Hunk (visual diff editor)

:DiffEditor    " Open visual diff/conflict resolution

Lazy-loaded — only available when invoked.


Debugging (DAP)

Debug Adapter Protocol

ActionKeybindingDescription
ContinueF5Start/continue debugging
Step overF10Execute next line
Step intoF11Enter function call
Step outF12Exit current function
Toggle breakpoint<Space>bSet/remove breakpoint
Debug nearest<Space>dnDebug test under cursor
Debug last<Space>dlRe-run last debug session
Terminate<Space>dTStop debugging session
Toggle REPL<Space>drOpen debug REPL
Toggle UI<Space>duShow/hide debug UI

Supported Languages

LanguageDebug AdapterNotes
PythondebugpyVia nvim-dap-python
GodelveVia nvim-dap-go
RustcodelldbVia rustaceanvim
C/C++codelldbVia clangd_extensions
Lualocal-lua-debugger

Terminal Integration

ToggleTerm

ActionKeybindingDescription
Toggle terminal<Space>ttFloating terminal
Terminal (horizontal)<Space>thBottom split
Terminal (vertical)<Space>tvRight split
Terminal (new tab)<Space>tTTerminal in new tab
Lazygit<Space>tlLazygit in floating terminal
Node REPL<Space>tnNode.js REPL
Python REPL<Space>tpPython REPL

Inside Terminal

ActionKeyDescription
Exit terminal modeCtrl+\ Ctrl+nReturn to Normal mode
Close terminalCtrl+d or exit

Plugin Management (lazy.nvim)

Commands

CommandDescription
:LazyOpen lazy.nvim UI
:Lazy installInstall missing plugins
:Lazy updateUpdate all plugins
:Lazy cleanRemove unused plugins
:Lazy restoreRestore to lockfile versions
:Lazy syncInstall + clean + update
:Lazy healthCheck plugin health

Inside lazy.nvim UI

ActionKeyDescription
InstallIInstall missing
UpdateUUpdate all
CleanXRemove unused
SyncSInstall + clean + update
RestoreRRestore lockfile
CheckCCheck for updates
ProfilePShow startup profile
CloseqClose UI

Adding a New Plugin

  1. Create a new file in config/nvim/lua/plugins/ (e.g., my-plugin.lua):
    return {
        "author/plugin-name",
        opts = {
            -- plugin options
        },
    }
  2. Reopen Neovim — lazy.nvim auto-installs it
  3. 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.

Installed Language Packs (via astrocommunity)

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)

ActionKeyDescription
Select functionvaf / vifAround / inside function
Select classvac / vicAround / inside class
Select loopval / vilAround / inside loop
Select conditionalvai / viiAround / inside if/else
Select parametervaa / viaAround / 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)

ActionKeysExample
Add surroundys{motion}{char}ysiw" → wrap word in quotes
Delete surroundds{char}ds" → remove surrounding quotes
Change surroundcs{old}{new}cs"' → change " to '
Visual surroundS{char}Select text, then S"

Auto-pairs

Automatically pairs (, [, {, ", ', `. Press Enter to split pairs:

before: {|}     (| is cursor)
press Enter:
{
  |
}

Comment (Comment.nvim)

ActionKeybindingDescription
Toggle commentgccToggle line comment
Comment motiongc{motion}gcip = comment paragraph
Visual commentgcComment selected lines
Block commentgbcToggle block comment

Indentation

ActionKeyDescription
Indent>>Indent line
Unindent<<Unindent line
Visual indent> / <Indent/unindent selection
Re-indent=Auto-indent (treesitter-aware)
Re-indent buffergg=GRe-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.

Adding Formatters/Linters

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

  1. Check :LspInfo — shows which servers are attached
  2. Check :checkhealth lsp — diagnostic info
  3. Verify the server is on PATH: which gopls etc.

Treesitter grammar not found

  1. Run :TSInstall <language> to manually install
  2. Or restart nvim — auto-install should trigger

Plugin not loading

  1. Run :Lazy — check plugin status
  2. Run :checkhealth lazy — check lazy.nvim health
  3. Delete ~/.local/share/nvim/lazy/ and restart for clean install

Slow startup

  1. Run :Lazy profile — shows load times per plugin
  2. Check for conflicting plugins
  3. Verify treesitter grammars are compiled (not downloading)

Copilot not working

  1. Run :Copilot setup — authenticate with GitHub
  2. Check :Copilot status — verify connection
  3. Requires nodejs on PATH (provided by Nix)

DocWhat it covers
editors.mdMulti-editor architecture, VS Code extensions, shared config
keybindings.mdSystem-wide keybindings (Hyprland, Niri, Tmux, Zsh)
toolchain.mdhey CLI, hooks, binscripts
themes.mdCatppuccin theming across apps