Neovim Configuration

July 28, 2026 · View on GitHub

A minimal, fast Neovim configuration for Neovim 0.12+ with lazy-loading, LSP support, and intuitive keybindings.


Installation

1. System Dependencies (Required)

# Core requirements
brew install neovim    # v0.12+ required
brew install git
brew install ripgrep   # Fast grep (used by picker)
brew install fd        # Fast find (used by picker)
brew install lazygit   # Git TUI
brew install node      # Required for some LSPs and tools
brew install npm       # Required for markdown-preview

2. Fonts (Required)

Install a Nerd Font for icons:

brew install --cask font-jetbrains-mono-nerd-font
# or
brew install --cask font-fira-code-nerd-font

Then set your terminal to use the installed font.

3. Language Toolchains (Install what you need)

# Go
brew install go
# After install, run :GoInstallBinaries in nvim

# Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# After install, run :CargoInstallTools in nvim

# Zig
brew install zig

# Python
brew install python
pip install pynvim  # Optional: for some plugins

# PHP
brew install php composer

# Laravel LSP (optional, for Laravel projects — see "Language Servers" below)
composer global require laravel/lsp

# Swift / iOS (macOS only)
# Xcode + Command Line Tools provide sourcekit-lsp and xcodebuild

# Lua (for luarocks, optional)
brew install lua luarocks

4. Optional Dependencies

# Markdown preview (browser-based)
# markdown-preview.nvim will auto-install, but needs npm

# Image rendering (optional)
brew install imagemagick ghostscript

# Mermaid diagrams (optional)
npm install -g @mermaid-js/mermaid-cli

# LaTeX rendering (optional)
brew install tectonic

5. Clone and Start

# Backup 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 this config
git clone <your-repo> ~/.config/nvim

# Start Neovim - plugins will auto-install on first launch
nvim

6. Post-Install Steps

Run these commands in Neovim after first launch:

" Wait for lazy.nvim to finish installing plugins, then:

" Generate help tags
:helptags ALL

" Install treesitter parsers (auto-installs, but can force)
:TSUpdate

" Check health
:checkhealth

" For Go development
:GoInstallBinaries

" For Rust development  
:CargoInstallTools

" Build markdown-preview (if not auto-built)
:Lazy build markdown-preview.nvim

Verify Installation

:checkhealth

All checks should pass. Common fixes:

  • Missing CLI tools: brew install <tool>
  • Treesitter errors: :TSUpdate
  • LSP not working: :LspInfo and :Mason

What Gets Auto-Installed

Via Mason (LSP/Linters/Formatters)

CategoryTools
LSP Serverslua_ls, gopls, zls, ts_ls, rust-analyzer, intelephense, bashls, pyright, cssls, html, jsonls, yamlls, sourcekit-lsp¹
Linterseslint_d, luacheck, golangci-lint, shellcheck, markdownlint, yamllint, jsonlint, htmlhint, stylelint, phpstan, ruff, mypy
Formattersstylua, goimports, prettier, black, isort, shfmt, pint

¹ sourcekit-lsp ships with Xcode (not managed by Mason).

Via Treesitter

Parsers for: bash, c, css, go, html, javascript, json, latex, lua, markdown, php, python, rust, scss, svelte, swift, terraform, tsx, typescript, vim, vue, yaml, zig


Structure

~/.config/nvim/
├── init.lua                 # Entry point
├── lua/
│   ├── core/
│   │   ├── init.lua         # Loads all core modules
│   │   ├── options.lua      # Neovim options + filetype detection
│   │   ├── keymaps.lua      # Core keybindings
│   │   ├── autocmds.lua     # Auto commands
│   │   ├── lazy.lua         # Plugin manager bootstrap
│   │   └── utils.lua        # Utility functions
│   └── plugins/
│       ├── coding.lua       # Completion, treesitter
│       ├── colorschemes.lua # Themes
│       ├── editor.lua       # Flash, mini.nvim, persistence
│       ├── formatting.lua   # Conform.nvim (format on save)
│       ├── git.lua          # Gitsigns, fugitive, diffview
│       ├── linting.lua      # nvim-lint
│       ├── lsp.lua          # Mason + LSP keymaps + diagnostic config
│       ├── snacks.lua       # Picker, explorer, notifications
│       ├── swift.lua        # xcodebuild.nvim (Swift/iOS)
│       ├── tools.lua        # Misc tools
│       └── ui.lua           # Which-key, trouble, markdown
├── lsp/                     # Per-server configs (vim.lsp.config / 0.11+ API)
│   ├── bashls.lua
│   ├── cssls.lua
│   ├── gopls.lua
│   ├── html.lua
│   ├── intelephense.lua
│   ├── jsonls.lua
│   ├── lua_ls.lua
│   ├── pyright.lua
│   ├── rust_analyzer.lua
│   ├── sourcekit.lua
│   ├── ts_ls.lua
│   ├── yamlls.lua
│   └── zls.lua
├── ftplugin/
│   ├── go.lua               # Go commands (:GoTest, :GoBuild, etc.)
│   ├── rust.lua             # Rust commands (:CargoRun, :CargoTest, etc.)
│   ├── swift.lua            # Swift indentation/comment settings
│   └── zig.lua              # Zig commands (:ZigBuild, :ZigTest, etc.)
└── doc/
    ├── go.txt               # :help go.txt
    ├── rust.txt             # :help rust.txt
    └── zig.txt              # :help zig.txt

Keybindings

Leader key: <Space>

Essential (No Prefix)

KeyAction
<C-s>Save file
<C-h/j/k/l>Navigate windows
<C-Up/Down/Left/Right>Resize windows
<Esc>Clear search highlight
jj / jkExit insert mode
H / LStart/End of line
<S-h> / <S-l>Prev/Next buffer
QDelete buffer
KHover documentation
sFlash jump
SFlash treesitter

Quick Access (Leader)

KeyAction
<leader><space>Find files
<leader>/Grep
<leader>,Switch buffer
<leader>.Scratch buffer
<leader>eFile explorer
<leader>qQuit
<leader>QQuit all
<leader>?Buffer keymaps
<leader>KAll keymaps
<C-/>Terminal

Buffers (<leader>b)

KeyAction
<leader>bbSwitch buffer
<leader>bdDelete buffer
<leader>boDelete other buffers

Code (<leader>c)

KeyAction
<leader>caCode action
<leader>crRename symbol
<leader>cdLine diagnostic
<leader>cfFormat
<leader>cvDefinition in vsplit

Diagnostics (<leader>d)

KeyAction
<leader>ddWorkspace diagnostics
<leader>dbBuffer diagnostics
<leader>dtTrouble (workspace)
<leader>dTTrouble (buffer)
<leader>dqQuickfix list
<leader>dlLocation list

Files (<leader>f)

KeyAction
<leader>ffFind files
<leader>frRecent files
<leader>fcConfig files
<leader>fgGit files
<leader>fpProjects
<leader>fRRename file

Git (<leader>g)

KeyAction
<leader>ggLazygit
<leader>gsStatus
<leader>glLog
<leader>gLLog (line)
<leader>gfLog (file)
<leader>gdDiff (picker)
<leader>gDDiff HEAD
<leader>gcCheckout branch
<leader>goOpen in browser
<leader>gbBlame line
<leader>gBBlame buffer
<leader>gRReset buffer
<leader>gSStage buffer
<leader>giGitHub issues
<leader>gpGitHub PRs

Git Hunks (<leader>gh)

KeyAction
<leader>ghpPreview hunk
<leader>ghPPreview hunk inline
<leader>ghsStage hunk
<leader>ghuUndo stage hunk
<leader>ghrReset hunk
]h / [hNext/Prev hunk

LSP (<leader>l)

KeyAction
<leader>lsDocument symbols
<leader>lSWorkspace symbols
<leader>liLSP info
<leader>lrLSP restart
<leader>lhToggle inlay hints
<leader>ltReferences (Trouble)
<leader>lTSymbols (Trouble)

Markdown (<leader>m)

KeyAction
<leader>mpPreview in browser
<leader>mrToggle render in buffer

Notifications (<leader>n)

KeyAction
<leader>nnNotification history
<leader>ndDismiss all

Search (<leader>s)

KeyAction
<leader>sgGrep
<leader>swWord under cursor
<leader>sbBuffer lines
<leader>sBGrep buffers
<leader>shHelp
<leader>smMarks
<leader>sjJumps
<leader>skKeymaps
<leader>scCommands
<leader>s:Command history
<leader>s/Search history
<leader>srRegisters
<leader>sRResume last
<leader>suUndo history

UI/Toggles (<leader>u)

KeyAction
<leader>usToggle spelling
<leader>uwToggle wrap
<leader>urToggle relative numbers
<leader>ulToggle line numbers
<leader>uDToggle diagnostics
<leader>ucToggle conceal
<leader>uTToggle treesitter
<leader>ubToggle background
<leader>uhToggle inlay hints
<leader>uiToggle indent guides
<leader>udToggle dim
<leader>uCColorschemes
<leader>uzZen mode
<leader>uZZoom

Windows (<leader>w)

KeyAction
<leader>wdClose window
<leader>wsSplit horizontal
<leader>wvSplit vertical
<leader>wwOther window
<leader>w=Equal size
<leader>wmMaximize

Goto (g)

KeyAction
gdDefinition
gDDeclaration
grReferences
giImplementation
gyType definition
KeyAction
[d / ]dPrev/Next diagnostic
[h / ]hPrev/Next hunk
[b / ]bPrev/Next buffer
[[ / ]]Prev/Next reference

Editing

KeyModeAction
J / KVisualMove lines down/up
< / >VisualIndent (stay selected)
pVisualPaste (no yank)
XNormalSplit line
YYNormalYank block {}
n / NNormalNext/Prev match (centered)

Surround (mini.surround)

KeyAction
gsaAdd surrounding
gsdDelete surrounding
gsrReplace surrounding
gsfFind surrounding (right)
gsFFind surrounding (left)

Language-Specific Commands

Go (:help go.txt)

CommandAction
:GoBuildgo build
:GoRungo run
:GoTestgo test
:GoTestFuncTest function under cursor
:GoTestFileTest current package
:GoCoverageTest with coverage
:GoModTidygo mod tidy
:GoGet <pkg>go get
:GoVetgo vet
:GoLintgolangci-lint
:GoDoc <sym>go doc
:GoImplGenerate interface stubs
:GoIfErrInsert if err != nil
:GoAddTagsAdd struct tags
:GoAltSwitch test/source
:GoInstallBinariesInstall all Go tools

Rust (:help rust.txt)

CommandAction
:CargoBuildcargo build
:CargoBuildReleasecargo build --release
:CargoRuncargo run
:CargoTestcargo test
:CargoTestFuncTest function under cursor
:CargoCheckcargo check
:CargoClippycargo clippy
:CargoFmtcargo fmt
:CargoAdd <crate>cargo add
:CargoDoccargo doc
:RustDoc <crate>Open docs.rs
:CargoInstallToolsInstall cargo subcommands

Zig (:help zig.txt)

CommandAction
:ZigBuildzig build
:ZigBuildReleasezig build -Doptimize=ReleaseFast
:ZigRunzig build run
:ZigRunFilezig run
:ZigTestzig build test
:ZigTestFilezig test
:ZigFmtzig fmt
:ZigDocOpen Zig docs
:ZigAltSwitch test/source

Swift / iOS (<leader>x)

Powered by xcodebuild.nvim. Requires Xcode + Command Line Tools.

Key / CommandAction
<leader>xsSetup project
<leader>xb / xrBuild / Build & Run
<leader>xtRun tests
<leader>xT / xfTest current class / function
<leader>xS / xdSelect scheme / device
<leader>xoBoot simulator
<leader>xlToggle build logs
:XcodebuildPickerAll commands menu

Language Servers

Server configs live under lsp/ and are activated via vim.lsp.enable() in lua/plugins/lsp.lua.

Auto-installed via Mason:

  • Go: gopls
  • Rust: rust-analyzer
  • Zig: zls
  • Lua: lua_ls
  • TypeScript: ts_ls
  • Python: pyright
  • PHP: intelephense
  • Bash: bashls
  • CSS/HTML/JSON/YAML: vscode servers

Not managed by Mason:

  • Swift / Objective-C: sourcekit-lsp (ships with Xcode)
  • Laravel: laravel-lsp (installed via Composer, see below)

Laravel LSP

laravel/lsp is Laravel's official language server. It is not available through Mason — install it globally with Composer:

composer global require laravel/lsp

Make sure Composer's global bin directory is on your PATH, otherwise Neovim cannot find the laravel-lsp binary:

# Add to ~/.zshrc (macOS default location)
export PATH="$HOME/.config/composer/vendor/bin:$PATH"

# Verify
which laravel-lsp

Config lives in lsp/laravel_lsp.lua. The filename must match the name passed to vim.lsp.enable() in lua/plugins/lsp.lua — laravel_lsp resolves to lsp/laravel_lsp.lua, so a hyphenated filename silently fails to load.

It runs alongside intelephense rather than replacing it. intelephense handles general PHP intelligence (classes, methods, properties); laravel-lsp adds Laravel-aware completion for strings such as config('…'), route('…'), view('…') and env('…'), plus Blade directives. It boots the Laravel application, so it only works in a real Laravel project (one containing artisan).

To verify: open a PHP file in a Laravel project, type config(' in insert mode, and the config keys should appear. :checkhealth vim.lsp lists it as attached.

Formatters (Conform)

LanguageFormatter
Gogoimports, gofmt
Rustrustfmt
Zigzigfmt
Luastylua
JS/TS/JSON/YAML/HTML/CSSprettier
Pythonisort, black
PHPpint
Shellshfmt

Format on save is enabled by default.

Linters (nvim-lint)

LanguageLinter
Gogolangci-lint
JS/TSeslint_d
Lualuacheck
Pythonruff, mypy
PHPphpstan
Shellshellcheck

Health Check

:checkhealth

Common fixes:

  • Missing tools: brew install <tool>
  • Treesitter errors: :TSUpdate
  • Go tools: :GoInstallBinaries
  • Rust tools: :CargoInstallTools

Colorscheme

Default: yukinord

Switch with <leader>uC


Always a WIP.