14 KiB
Neovim Configuration (LazyVim)
A LazyVim-based setup focused on Go and Zig development, with LSP, debugging, test running, task running, AI chat, database tooling, and a which-key cheat sheet. Everything is lazy-loaded so plugins only activate for the filetype or command that needs them.
Prerequisites
- Neovim >= 0.11 (developed on 0.12.x; 0.11+ is required for the modern
vim.lsp/root_markersAPI used by some servers) - Git
- A Nerd Font (icons in the explorer, statusline, dadbod UI, etc.)
- Node.js — TypeScript/JSON/YAML/web LSPs and
prettier - Go —
gopls,delve,gofumpt,goimports - Zig — the
zigtoolchain on$PATH(for LSP, build/run, tests, debug) - Python (optional) —
pyright+ruffare configured if you use it
Most language servers, linters, formatters, and DAP adapters install automatically through Mason on first launch.
Installation
-
Back up any existing config:
mv ~/.config/nvim ~/.config/nvim.bak mv ~/.local/share/nvim ~/.local/share/nvim.bak mv ~/.local/state/nvim ~/.local/state/nvim.bak mv ~/.cache/nvim ~/.cache/nvim.bak -
Clone:
git clone https://git.samoneal.io/sam_oneal/nvim-config.git ~/.config/nvim -
Launch Neovim. lazy.nvim bootstraps itself and installs all plugins.
-
Install tooling with
:Mason(or:MasonInstall <tool>). Check health with:checkhealthand LSP attachment with:checkhealth lsp.
What's included
Base: LazyVim with leader = <Space>,
localleader = \, colorscheme catppuccin-mocha.
LazyVim extras enabled (in lua/config/lazy.lua): lang.go, lang.json,
lang.yaml, lang.markdown, lang.typescript, lang.tailwind,
dap.core.
Languages (LSP + Treesitter): Go, Zig, Lua, TypeScript/JavaScript, HTML, CSS, JSON, YAML, Markdown, SQL, Dockerfile, Python.
| Concern | Plugin / tool |
|---|---|
| LSP | nvim-lspconfig + Mason (gopls, zls, lua_ls, ts_ls, html, cssls, jsonls, yamlls, marksman, sqlls, dockerls, pyright/ruff) |
| Completion | blink.cmp (LazyVim default; SQL routed to dadbod) |
| Formatting | conform.nvim via LazyVim's format pipeline |
| Debugging | nvim-dap + delve (Go), codelldb (Zig/C/C++) |
| Testing | neotest (Go, Python, Zig) with in-buffer pass/fail signs |
| Coverage | nvim-coverage (Go) |
| Task running | overseer.nvim (+ user templates) |
| AI chat | opencode.nvim (provider-agnostic) |
| Database | vim-dadbod + dadbod-ui + dadbod-completion |
| Git | Neogit + diffview, plus LazyVim's lazygit |
| Explorer/picker | snacks.nvim |
| Symbols | aerial.nvim |
| Diagnostics | trouble.nvim |
| Cheat sheet | which-key.nvim (hold <leader>) |
AI (opencode.nvim)
AI is intentionally environment-agnostic: opencode.nvim drives the external
opencode CLI, so the model/provider (Anthropic,
OpenAI, local models, etc.) is chosen in opencode's own config rather than here.
Install the opencode CLI separately and configure your provider there.
Database (vim-dadbod)
Open the UI with <leader>Du. Add a connection with <leader>Da. Examples:
postgresql://user:pass@localhost:5432/dbname
mysql://user:pass@localhost:3306/dbname
sqlite:path/to/db.sqlite
SQL completion is provided via dadbod inside SQL buffers, and SQL
autoformat-on-save is intentionally disabled (format manually with
<leader>cf).
Key bindings
Hold <leader> (Space) to pop up the which-key menu — it lists every group
below as a live cheat sheet. Mouse is enabled (mouse=a), and the explorer,
dadbod UI, Neogit, DAP UI, trouble, aerial, and Overseer pickers are all
clickable.
Note the deliberate capitalization:
<leader>T*is Terminal (lowercase<leader>t*is the Test group), and<leader>D*is Database (lowercase<leader>d*is Debug).
AI (<leader>a)
| Key | Action |
|---|---|
<leader>aa |
Ask AI about current context (n/v) |
<leader>ax |
Ask AI about selection |
<leader>at |
Toggle AI panel |
go |
Operator: add range to AI chat |
goo |
Add current line to AI chat |
<S-C-u> / <S-C-d> |
Scroll AI chat up/down |
Code › Go (<leader>cg)
| Key | Action |
|---|---|
<leader>cgb |
Run benchmarks (-bench=. -benchmem) |
<leader>cgpc |
CPU profile |
<leader>cgpm |
Memory profile |
<leader>cgpt |
Trace profile |
Code › Zig (<leader>cz)
| Key | Action |
|---|---|
<leader>czb |
zig build |
<leader>czr |
zig build run |
<leader>czt |
zig build test |
Tests (neotest, <leader>t)
Works in Go, Python, and Zig buffers; results show as signs in the gutter.
| Key | Action |
|---|---|
<leader>tt |
Run nearest test |
<leader>tf |
Run test file |
<leader>ts |
Toggle test summary |
<leader>to |
Open test output |
<leader>tc |
Show coverage (Go) |
Debugging (DAP, <leader>d)
Go uses delve; Zig/C/C++ use codelldb. Zig launch configs build with debug
symbols first, then run (Launch (zig build) prompts for the exe under
zig-out/bin; Launch (current file) compiles the open file).
| Key | Action |
|---|---|
<leader>db |
Toggle breakpoint |
<leader>dB |
Conditional breakpoint |
<leader>dc |
Continue / start |
<leader>dC |
Run to cursor |
<leader>di |
Step into |
<leader>dO |
Step over |
<leader>do |
Step out |
<leader>dj / <leader>dk |
Stack down / up |
<leader>dr |
Toggle REPL |
<leader>ds |
Session |
<leader>dt |
Terminate |
<leader>dw |
Inspect widget (hover) |
<leader>du |
Toggle DAP UI |
<leader>de |
Eval (n/v) |
<leader>dT |
Debug Go test |
<leader>dL |
Debug last Go test |
Tasks (Overseer, <leader>o)
| Key | Action |
|---|---|
<leader>or |
Run a task (picker — includes go: and zig: templates) |
<leader>ot |
Toggle task list |
Database (<leader>D)
| Key | Action |
|---|---|
<leader>Du |
Toggle DB UI |
<leader>Da |
Add connection |
<leader>Df |
Find DB buffer |
Git (<leader>g)
| Key | Action |
|---|---|
<leader>gg |
Lazygit (LazyVim default) |
<leader>gn |
Neogit |
<leader>gl |
Lazygit log |
<leader>gf |
Lazygit file history |
Search / Symbols (<leader>s)
| Key | Action |
|---|---|
<leader>so |
Symbols outline (aerial) |
<leader>sh |
Incoming calls |
<leader>sc |
Outgoing calls |
Diagnostics (Trouble, <leader>x)
| Key | Action |
|---|---|
<leader>xx |
Diagnostics |
<leader>xw |
Workspace diagnostics |
<leader>xt |
TODOs |
Terminal (<leader>T)
| Key | Action |
|---|---|
<leader>Th |
Terminal (horizontal split) |
<leader>Tv |
Terminal (vertical split) |
<Esc><Esc> |
Exit terminal mode |
Explorer & windows
| Key | Action |
|---|---|
<C-e> |
Toggle explorer (snacks) |
<C-S-v> / <C-v> |
Open file in vertical split |
<C-S-h> / <C-x> |
Open file in horizontal split |
<C-h/j/k/l> |
Navigate windows |
<C-Up/Down/Left/Right> |
Resize window |
Formatting (LazyVim pipeline)
| Key / Command | Action |
|---|---|
<leader>cf |
Format buffer |
<leader>uf |
Toggle autoformat (buffer) |
<leader>uF |
Toggle autoformat (global) |
:LazyFormat |
Format now |
General editing
| Key | Action |
|---|---|
<C-s> |
Save file |
<S-h> / <S-l> |
Prev / next buffer |
<Esc> |
Clear search highlight |
<A-j> / <A-k> |
Move line/selection down/up |
< / > (visual) |
Indent, keep selection |
Formatters by file type
| File type | Formatter |
|---|---|
| Go | gofumpt, goimports (-local github.com) |
| Lua | stylua (2-space) |
| JS/TS/JSX/TSX | prettier (2-space, single quotes) |
| HTML/CSS/SCSS | prettier |
| JSON/JSONC/YAML | prettier |
| Markdown | prettier |
| SQL | sql-formatter (postgresql; manual only) |
File structure
~/.config/nvim/
├── init.lua # Entry point → require("config.lazy")
├── lua/
│ ├── config/
│ │ ├── lazy.lua # lazy.nvim bootstrap, LazyVim + extras
│ │ ├── options.lua # Neovim options
│ │ ├── keymaps.lua # Custom keymaps
│ │ └── autocmds.lua # Autocommands (yank hl, ft tweaks, SQL no-autoformat…)
│ ├── plugins/
│ │ ├── mason.lua # Tooling installs (LSP/linters/formatters/DAP)
│ │ ├── lspconfig.lua # Per-server LSP config (gopls, zls, …)
│ │ ├── treesitter.lua # Parsers
│ │ ├── formatting.lua # conform.nvim
│ │ ├── dap.lua # Debugging (Go via delve, Zig via codelldb)
│ │ ├── neotest.lua # Test runner (go/python/zig)
│ │ ├── go-coverage.lua # Go coverage signs
│ │ ├── overseer.lua # Task runner
│ │ ├── ai.lua # opencode.nvim
│ │ ├── dadbod.lua # Database
│ │ ├── git.lua # Neogit + diffview
│ │ ├── editor.lua # snacks tweaks + which-key groups
│ │ ├── symbols.lua # aerial
│ │ ├── dashboard.lua # trouble opts
│ │ ├── devcontainer.lua # nvim-remote-containers
│ │ ├── performance.lua # treesitter large-file guard
│ │ ├── theme.lua # catppuccin
│ │ └── zig.lua # Zig ft plugin (toolchain wired across files)
│ └── overseer/template/user/ # go_*, zig_{build,run,test} task templates
Zig notes
- LSP is
zls(lua/plugins/lspconfig.lua), root markersbuild.zig/build.zig.zon, with build-on-save and inlay hints. zig build testand project-wide neotest runs require a standardteststep in yourbuild.zig; individual.zigfiles also work.- Debugging needs
codelldb(:MasonInstall codelldbif it doesn't auto-install). Builds use-O Debugso symbols are present.
Troubleshooting
- LSP not attaching:
:checkhealth lsp— confirm the server appears and is attached (not just installed in Mason). Ifroot_dir/root_markerslook off, the server may not find your project root. - Formatting:
:ConformInfo. - Tests not detected: ensure the Treesitter parser for the language is
installed (
:TSInstall <lang>); Zig needs ateststep inbuild.zig. - Ctrl+Shift keys not firing: some terminals don't transmit them; use the
plain-Ctrl fallbacks (
<C-v>/<C-x>in the explorer). - Nerd Font icons missing: install a Nerd Font and set it in your terminal.
Known issues (in current repo)
Two unrelated typos exist in lua/config/keymaps.lua's opencode block (present
before these docs): the scroll-up command string reads sesion.half.page.up
(should be session.…), and <leader>at is mapped in t (terminal) mode where
n/x is likely intended. Documented here for accuracy; fix when convenient.