This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
This is a Neovim configuration built with lazy.nvim as the package manager. The configuration follows a modular structure:
-
init.lua- Entry point that:- Disables Perl and Ruby providers
- Loads lazy.nvim package manager
- Loads custom configuration modules (transparency, keymaps, options)
-
lua/config/lazy.lua- Bootstraps lazy.nvim and sets:- Leader key: Space
- LocalLeader:
\ - Plugin spec imports from
lua/plugins/ - Git submodules disabled for plugins
-
Plugin configuration is split into semantic modules in
lua/plugins/:ui.lua- Theme, statusline, icons, treesitter, rainbow bracketscmp.lua- Completion system (blink.cmp, Copilot, autopairs)lsp.lua- LSP servers, Mason, diagnostics, Trouble, lspsaga, noicesnacks.lua- fzf-lua and neo-tree configurationtools.lua- Gitsigns, vim-illuminate, neotest, formatters (conform.nvim), wildfire, PEP8 indentdebug.lua- nvim-dap debugging setup (Python debugpy)
This config uses the new Neovim LSP API (vim.lsp.config/enable) instead of the traditional lspconfig setup:
-- New API pattern used in lua/plugins/lsp.lua:
vim.lsp.config(server, server_opts)
vim.lsp.enable(server)Mason auto-installs LSP servers: clangd, pyright, gopls, eslint, ts_ls, lua_ls, rust_analyzer, marksman, html, cssls, jsonls, yamlls, bashls, dockerls, taplo, emmet_language_server, jinja_lsp
Special configurations:
- pyright: Type checking disabled (
typeCheckingMode = "off"), automatic venv discovery (searches up 3 levels for .venv/venv/env) - lua_ls: Configured for Neovim API with
vimglobal recognized
Uses blink.cmp (modern completion engine) with:
- Default preset keybindings (
<C-y>to accept,<C-Space>to toggle docs) - GitHub Copilot integration via blink-copilot (lazy-loaded: use
:Copilotcommand to activate) - LSP capabilities from blink.cmp are passed to all LSP servers
- auto_brackets: blink.cmp handles bracket insertion for function/method completions
- Uses both
kind_resolutionandsemantic_token_resolution(400ms timeout) blocked_filetypescleared to support all languages including Python, TS, Vue
- Uses both
- nvim-autopairs: Handles manual bracket input, formatting, bracket deletion
- Disabled in macros and replace mode
- Special rule for Python f-strings (f' and f" auto-pairing)
conform.nvim handles formatting with auto-format on save (2000ms timeout):
- Python: ruff (ignores F401)
- JS/TS/React: prettier
- HTML/CSS/JSON/Markdown: prettier
- Lua: stylua (2 spaces)
- Shell: shfmt (2 spaces)
- C/C++: clang-format (4 spaces, tabs as spaces)
- YAML: yamlfmt
- SQL: sql_formatter (disabled auto-format on save to avoid syntax errors)
- TOML: taplo
- Dockerfile: dprint
Important options in lua/config/options.lua:
- Tab width: 4 spaces
- Smart indent/C indent: disabled (nosmartindent, nocindent)
- Fold method: indent (level 99, Treesitter takes over via plugins)
- Case-sensitive search (ignorecase=false, smartcase=false)
- Persistent undo in
~/.config/nvim/tmp/undo/ - Transparency effects applied via
lua/config/transparency.lua - Auto-comment disabled via FileType autocmd
- Cursor position remembered on file reopen
- Theme: nord.nvim with italic comments and bold lualine
- Treesitter: Main branch, lazy=false (no lazy-loading supported)
- Auto-installs parsers: lua, vim, python, javascript, typescript, html, css, json, markdown, bash, c, cpp, rust, go, java
- Enables folding via
vim.treesitter.foldexpr() - Excludes markdown/text from treesitter folding
- Rainbow brackets: HiPhish/rainbow-delimiters.nvim with Nord + Catppuccin Frappé colors
- Submodules disabled (testing dependencies not needed)
- Strategy: global by default, local for vim files
- Inline diagnostics: tiny-inline-diagnostic.nvim
- Ghost preset, throttle 150ms, multiline enabled
- Disables default vim virtual_text
- Smart delay: waits 300ms after fast typing before showing diagnostics
- lspsaga: LSP UI with rounded borders, winblend=0 (opaque)
- Hover window: auto position, prefer below, offset_y=1 to avoid covering current line
- Auto-focuses hover window after 50ms delay
- Outline auto-preview disabled to avoid tab-switch float-window height errors
- noice.nvim: Enabled for cmdline/messages/popupmenu beautification
- nvim-dap: Core debugging with Nord-themed breakpoint signs
- Breakpoint signs: ● (red), ◆ (orange condition), ○ (gray rejected), ➜ (green stopped), ◉ (yellow logpoint)
- Signs don't highlight line numbers to avoid interfering with relative numbers
- nvim-dap-view: Unified debug panel with tab-like sections in a single window
- Auto-opens on debug start, auto-closes on terminate/exit
- Configured as a right-side panel with tab-like sections
- Sections: scopes, breakpoints, threads, watches, REPL, console
- Force redraw after DAP events to fix rendering issues
- nvim-dap-python: Uses Mason-installed debugpy at
~/.local/share/nvim/mason/packages/debugpy/venv/bin/python - mason-nvim-dap: Auto-installs debugpy
- Terminal split shortcuts:
<C-w>topens a horizontal terminal split and<C-w>Topens a vertical terminal split, intentionally overriding the built-inCTRL-W_t/CTRL-W_Twindow commands
- gitsigns.nvim: Inline Git hunk workflow
- Navigation:
<leader>gj/<leader>gk - Hunk actions:
<leader>gs,<leader>gr,<leader>gp,<leader>gi - Buffer actions:
<leader>gS,<leader>gR - Review actions:
<leader>gb,<leader>gd,<leader>gD,<leader>gq - Toggles:
<leader>gl,<leader>gw
- Navigation:
- neotest: Test runner with Python, Go, and Vitest adapters
- Run nearest/file/project:
<leader>tn,<leader>tf,<leader>ta - Debug nearest test through DAP:
<leader>td - Python-only test debugging:
<leader>tm,<leader>tc - Test UI:
<leader>ts,<leader>to,<leader>tO - Watch/stop:
<leader>tw,<leader>tS
- Run nearest/file/project:
After modifying plugin config:
nvim # Just restart Neovim - lazy.nvim auto-loads changesTo manually update plugins:
:Lazy sync " Update all plugins
:Lazy clean " Remove unused plugins:Mason " Open Mason UI to manage LSP servers
:LspInfo " Show attached LSP clients
:Trouble diagnostics " View all diagnostics:Lazy " Open lazy.nvim UI
:checkhealth lazy " Check lazy.nvim health
:checkhealth lsp " Check LSP configuration
:checkhealth fzf_lua " Check fzf-lua integration and external binary supportFormat current buffer:
<leader>F " Uses conform.nvim formatters:DapInstall " Install debug adapters via Mason
<leader>ds " Start debugging
<leader>dc " Continue debugging
<leader>dn " Step over
<leader>di " Step into
<leader>do " Step out
<leader>db " Toggle breakpoint
<leader>du " Toggle debug view
<leader>dp " Open debug REPL
<leader>dq " Terminate debugging<leader>tn " Run nearest test
<leader>tf " Run current file
<leader>ta " Run current project
<leader>td " Debug nearest test
<leader>tm " Debug current test method (Python only)
<leader>tc " Debug current test class (Python only)
<leader>ts " Toggle neotest summary
<leader>to " Open latest outputCopilot is lazy-loaded and requires manual activation:
:Copilot " Authenticate and activate CopilotWhen adding new plugins:
- UI/visual plugins →
lua/plugins/ui.lua - Completion/snippets →
lua/plugins/cmp.lua - LSP/diagnostics →
lua/plugins/lsp.lua - Search/file navigation →
lua/plugins/snacks.lua - File operations/utilities →
lua/plugins/tools.lua - Debugging →
lua/plugins/debug.lua
Core keybindings are in lua/config/keymaps.lua, but many plugins define their own in their config:
- Buffer:
<leader>bb(buffer list),<leader>bn/<leader>bp(next/prev),<leader>bd(delete) - Gitsigns:
<leader>g* - vim-illuminate:
]r/[r(next/prev reference),<leader>ch(toggle current buffer highlighting) - Neotest:
<leader>t* - Trouble:
<leader>x*prefix (diagnostics) - fzf-lua: primary search mappings (
<leader><space>,<leader>bb,<leader>/,<leader>:,<leader>ff,<leader>fg,<leader>fb,<leader>fc,<leader>fr,<leader>fs,<leader>fS,<leader>ft,<leader>fT,<leader>fR) - Neo-tree:
<leader>e(filesystem reveal left toggle),o(open in new tab),H(toggle hidden/gitignored) - LSP/lspsaga:
gh(hover),gd(definition),gp(peek),gr(references),<leader>rn(rename),<leader>ca(code action),<leader>o(outline) - DAP:
<leader>d*prefix (all debug operations) - LSP is defined in plugin specs (see
keys = {}tables)
To add a new LSP server:
- Add to Mason's ensure_installed in
lua/plugins/lsp.lua:
ensure_installed = {
"clangd", "pyright", ..., "new_server",
}- If special config needed, add to the loop in mason-lspconfig config:
vim.lsp.config.new_server = {
capabilities = capabilities,
settings = { ... }
}- Mason will auto-install on next Neovim start
Transparency is managed separately in lua/config/transparency.lua and applied via autocmd after ColorScheme load. To disable transparency, comment out the require in init.lua.
Use fzf-lua as the default picker layer for files, buffers, grep, command history, and recent files.
File explorer is neo-tree:
<leader>e::Neotree filesystem reveal left toggle<CR>/l: open in current windowo: open in a new tabs/S: vertical / horizontal splitH: toggle hidden and gitignored files- Hidden files and gitignored files are filtered by default
follow_current_fileis enabled so the tree can reveal the active buffertis intentionally unmapped inside neo-tree so tab navigation keeps working elsewhere
If LSP not working:
- Check
:LspInfo- is server attached? - Check
:Mason- is server installed? - Check
~/.local/share/nvim/mason/packages/for actual installation - Verify using new API:
vim.lsp.config.*notrequire("lspconfig").*.setup()
If completion not working:
- Check if blink.cmp loaded:
:lua require('blink.cmp') - For Copilot: Did you run
:Copilotto authenticate? - Check auto_brackets blocked_filetypes is empty for your filetype
If formatting not working:
- Check conform setup:
:lua vim.print(require('conform').list_formatters()) - Check if formatter installed in Mason or system PATH
- For SQL files, auto-format on save is disabled to prevent syntax errors
If autopairs not working with blink.cmp:
- Verify blink.cmp auto_brackets is enabled with empty blocked_filetypes
- Check nvim-autopairs is not disabled for your filetype
- Remember: blink handles function/method completions, autopairs handles manual input
If debugging not working:
- Check
:DapInstallshows debugpy installed - For Python: verify Mason debugpy path exists at
~/.local/share/nvim/mason/packages/debugpy/venv/bin/python - Check DAP UI opens automatically when debug starts
- Verify breakpoint signs are visible in sign column
Problem: Type errors like Cannot access attribute "aclose" shown but code runs fine.
Solution: This config disables Pyright type checking via:
vim.lsp.config.pyright = {
settings = {
python = {
analysis = {
typeCheckingMode = "off",
diagnosticSeverityOverrides = {
reportAttributeAccessIssue = "none",
-- ... other disabled rules
},
},
},
},
}If config not applying:
- Confirm using
vim.lsp.config.*notlspconfig.*.setup() - Clean Mason symlinks:
rm -f ~/.local/share/nvim/mason/bin/pyright* - Reinstall:
:MasonInstall pyright
Problem: Functions don't get () after completion, or manual brackets don't pair.
Solution: This config uses a combined approach:
- blink.cmp auto_brackets: Handles function/method completions
- Ensure
kind_resolution.blocked_filetypes = {}(empty) - Ensure
semantic_token_resolution.blocked_filetypes = {}(empty)
- Ensure
- nvim-autopairs: Handles manual bracket input and formatting
- Check your filetype is not in
disable_filetype
- Check your filetype is not in
Test scenarios:
# Type "pri", select "print" → print(|) (blink.cmp)
# Type "(" → (|) (nvim-autopairs)
# In {|}, press <CR> → multi-line format (nvim-autopairs)Problem: Pyright can't find project dependencies.
Solution: This config auto-discovers venvs by searching up 3 levels for .venv, venv, or env directories. The venv must have a bin/python executable. If not found, pyright uses system Python.
Problem: Warning about git submodules during plugin update.
Solution: Submodules are intentionally disabled in lazy.nvim config (git.submodules = false) because most plugin submodules are testing dependencies users don't need. The warning is safe to ignore.
Problem: Command line behaves unexpectedly.
Solution: Noice is enabled for cmdline beautification. If causing issues, disable by setting enabled = false in the noice plugin spec in lua/plugins/lsp.lua. The config uses command_palette = false to avoid conflicts.
Problem: Hover documentation covers the line being edited.
Solution: Lspsaga is configured with offset_y = 1 and prefer_above = false to prefer showing hover below and offset by 1 line. If still covering, increase offset_y value in lua/plugins/lsp.lua.
Problem: CursorMoved in the outline buffer can trigger a float-window error like 'height' key must be a positive Integer after switching tabs.
Solution: Keep outline.auto_preview = false in lua/plugins/lsp.lua. This disables outline's automatic preview float, which avoids the tab-switch height calculation bug while preserving <leader>o outline navigation.