Personal Neovim configuration repository.
This repo started from the broader "Neovim from scratch" style of setup, but it has diverged heavily and should now be treated as a standalone personal config rather than a tutorial or general-purpose starter.
The configuration is organized around lazy.nvim and split into many small plugin specs under lua/plugins/. User-specific bootstrapping and behavior live under lua/user/.
Highlights of the current setup:
lazy.nvimauto-bootstrap in lua/user/lazy.lua- LSP, completion, treesitter, testing, task, search, terminal, UI, and language-specific modules
- Default completion engine set in lua/user/config.lua (
blinkby default, optionalnvim-cmp) - Mason-based LSP/tool management in lua/plugins/lsp/mason.lua
- Theme-heavy setup with many colorschemes, a randomizer, and theme-aware custom highlight logic
- Frontend-aware behavior for GUI clients and modern terminals
- Extra non-Neovim tool configs under
external/and file templates undertemplates/
- Theme-first workflow: lua/plugins/general/colorscheme-randomizer.lua is wired into a large colorscheme collection, and several custom highlight paths derive their colors from the active scheme instead of pinning a fixed palette.
- Semantic token styling is unusually opinionated: lua/user/lsp/semantic_tokens.lua generates ccls-style
id0..id19rainbow semantic token groups from existing theme colors, so semantic highlighting stays aligned with the current colorscheme. - UI rendering changes based on the current frontend or terminal. lua/util/client.lua detects Neovide, Neovim-Qt, Goneovim, Kitty, WezTerm, Ghostty, Alacritty, and others; lua/plugins/lsp/symbol-usage.lua switches between bubble, label, and plain-text renderers accordingly.
- The repo tracks surrounding tooling as part of the setup, not as an afterthought:
external/config/keeps related GUI and terminal configs, and templates/vim-template stores file templates for common C and C++ entry points. - Personal workflow keymaps are part of the repo identity, especially quick theme rotation and lightweight selection highlighting in lua/user/keymaps.lua.
Use a recent Neovim version. This config uses newer APIs such as vim.lsp.config, vim.lsp.enable, and modern semantic token handling, and it currently tracks nvim-treesitter's main branch, so 0.12+ / nightly is the practical baseline.
Recommended dependencies:
gitcurltar- a Nerd Font
ripgrepfdor another fast file findertree-sitter-cliinstalled via your system package manager, notnpm. This repo usesnvim-treesitter'smainbranch, and parser install/update expects the CLI to be available.- native build tools for plugins and parsers:
- Unix: a C/C++ compiler (
gccorclang),make, andcmake - Windows: MSVC Build Tools or
clang-cl, pluscmake
- Unix: a C/C++ compiler (
node22+ if you keepcopilot.luaenabled. The plugin requires Node.js andcurl; this repo does not callnpmdirectly.rubyif you keep Mason automatic installation enabled, because the default Mason LSP list includessolargraph- language runtimes and external tools you actually use (
python,clangd,latex, etc.)
Depending on platform and feature usage, a Rust toolchain (cargo/rustc) may also be useful for Rust-specific workflows or plugins that need a local Rust build.
Some plugins have extra optional requirements. For example, workspace substitution with nvim-rip-substitute benefits from ripgrep with pcre2 support.
Clone the repo into Neovim's config directory:
git clone https://github.com/tan-wei/neovim-init.lua.git ~/.config/nvimStart Neovim:
nvimBefore first launch, make sure the bootstrap dependencies above are installed. This config will bootstrap lazy.nvim, build native plugins, update Treesitter parsers, and let Mason install its default toolchain on startup.
After startup, these commands are usually the first things worth checking:
:checkhealth
:MasonInstall optional terminal configurations separately:
just install-kitty
just install-ghostty
just install-alacritty
just install-wezterm
just install-neovideThe installer detects Linux, macOS, and WSL, and overwrites the matching files
under $XDG_CONFIG_HOME (or ~/.config). For Kitty, Ghostty, and Alacritty,
set DOTFILES_PLATFORM to linux, macos, or wsl to select a platform
explicitly. WezTerm selects its platform module at runtime. If a tool's config
directory is a symlink directly to its tracked source directory, the installer
replaces that directory symlink with an installed copy.
just install-neovide installs external/config/neovide/config.toml. Neovide's
config file has no include directive, so the installer concatenates the base
file with the matching platform fragment (linux.toml, macos.toml, or
wsl.toml) into $XDG_CONFIG_HOME/neovide/config.toml. The platform fragments
carry the per-OS [font] block that mirrors the guifont branch in
lua/user/neovide.lua; the remaining g:neovide_* globals
have no config file equivalent and stay there. Note that a Windows-side Neovide
reads %APPDATA%\neovide\config.toml, so run the recipe from the environment
that starts Neovide.
The base file also sets startup-message-capture = false. Neovide normally
externalizes ext_messages/ext_cmdline while capturing startup messages, which
makes noice.nvim report You're using a GUI that uses ext_messages. Disabling
the capture avoids that without CLI flags or environment variables. The trade-off
is that startup errors before the first grid render use Neovim's own press-enter
prompt instead of Neovide's overlay.
- init.lua: startup entrypoint
- lua/user: user config, options, keymaps, autocommands, LSP setup, semantic token customization
- lua/plugins: modular plugin specs grouped by domain
- lazy-lock.json: pinned plugin versions, it's intentional ignore in git, to keep everything latest, :-P
external/: related tool configs such as kitty, ghostty, alacritty, wezterm, neovide, and goneovimtemplates/: file templatesspell/: custom spell additions
Auto-session saves the complete window layout, including nvim-tree windows. On Neovim 0.13+, nvim-tree rebuilds its own windows when a session is restored, preserving which tabs had the tree open. Saving a session does not close and reopen the tree. When no session is restored at startup, the tree opens without taking focus; a failed restore does not trigger this fallback.
Auto-session's unsupported-window cleanup preserves the NvimTree filetype.
Otherwise automatic saves on exit would close the tree before saving and
overwrite a manually saved open-tree layout with a closed-tree layout.
The nvim-tree configuration also adapts the current upstream one-shot
SessionLoadPost handler to support repeated session switches, while coalescing
duplicate events. Auto-session loads nvim-tree before restoring any layout.
Sessions previously saved with the close-before-save workaround have no tree window records. Open the tree where desired and save the session again to record that layout.
Run just session-check for the session regression suite. Each group runs in a
fresh Neovim process with temporary session, config, state, cache and fixture
directories. The checks use installed plugins without touching existing sessions
or project repositories. Failures identify the group and return a nonzero status.
| Group | Coverage |
|---|---|
layout |
Named sessions, split orientation, files, active editor, cursor, local options, pinned buffers and title |
startup |
Automatic cwd restore, no-session fallback, no unrelated last-session restore, saved tree visibility |
filters |
Auto-create disabled, existing-session autosave, enable switches, suppressed directories, bypass filetypes and unsupported-window cleanup |
directory |
Active-buffer guard, clean directory restore, LSP stop and separator/statusline hooks |
git |
Branch-specific session files and restore, named-session autosave; uses a temporary Git repository |
scope |
Real Scope tab-local buffer membership save and restore |
overseer |
Task serialization, quoting, opt-in at save/restore, disposal, invalid tasks and stale companion-file cleanup |
hooks |
Outline close, project-local config sourcing, dropbar preload and CMake/statusline refresh |
errors |
Missing/corrupt sessions, error reporting, autosave safety and no startup fallback after failure |
commands |
AutoSession save, restore, delete and toggle |
terminal |
Terminal split preservation and job recreation |
tree |
Per-tab visibility, repeated and fresh-process restores, focus preservation and no blank placeholders |
shutdown |
q, qa, wq, tree focus, multiple tabs/splits, exit autosave, and last-buffer deletion through real Snacks bufdelete |
The session engine, nvim-tree, Scope, terminal handling and buffer deletion run against real installed code. External-effect boundaries (task execution, LSP clients, trusted project-config loading, Outline, dropbar loading, CMake and UI refresh) use recording test doubles. These checks verify the configured hooks, not actual language servers, builds, task processes or picker UI. Git branch watcher automation is not tested because it is not enabled in this config.
Install Jujutsu (jj) on
PATH. Existing Git plugins remain available; no repository is automatically
initialized or migrated.
-
NicolasGB/jj.nvim is the main JJ interface, loaded by
:Jand its companion commands. Use:J log,:J status,:J describe,:J new,:J bookmark create,:J split, or:J resolve.:Jdiffcompares the current file with its parent using native Neovim diff. Destructive-action confirmations remain enabled. No global keymaps are added; the existing<leader>jjump namespace is unchanged. -
MrDwarf7/lazyjui.nvim opens jjui, a lazygit-like terminal interface, with
:LazyJui. It uses a 90% width/height floating window with no transparency. Default global keymaps are disabled to preserve the jump namespace. Run it from your JJ workspace. Install the separatejjuiexecutable onPATH, for examplebrew install jjui,paru -S jjui-binon Arch, orgo install github.com/idursun/jjui/cmd/jjui@latest(add$(go env GOPATH)/bintoPATH). Use:checkhealth lazyjuito check dependencies. -
julienvincent/hunk.nvim adds file/hunk/line selection for interactive splitting and squashing. It loads on
:HunkDiffEditor/:HunkDiffViewand uses a compact file tree with quit confirmation. To let JJ launch it, merge this into your JJ user config (jj config edit --user):[ui] diff-editor = [ "nvim", "-c", 'lua vim.api.nvim_cmd({cmd="HunkDiffEditor", args=vim.fn.argv()}, {})', "--", "$left", "$right", "$output", ]
This uses Neovim's argument list for paths, including paths containing spaces. JJ launches a separate Neovim instance, including when invoked from
:J split. In hunk,aselects a line,Aselects a hunk,<leader><CR>accepts, andqaborts. The JJ user config is not changed automatically.
Lualine keeps the existing Git branch/status components in Git-only repositories.
Inside a JJ workspace (including colocated Git/JJ repositories), they are replaced
by a theme-aware JJ badge: change ID, * for a nonempty change or ∅ for an empty
one, and prominent conflict/divergence warnings. Bookmarks appear above 100 columns;
the first description line appears above 150 columns. Long text is truncated
without breaking UTF-8. JJ ... means loading and JJ ? means the query failed.
Click the badge to open status for that workspace, even when the editor's current
directory points elsewhere.
Git blame is hidden there because Git HEAD is not JJ's working-copy change.
JJ status queries are asynchronous, cached per workspace, and throttled to at most
once per second on buffer entry, save, focus return, terminal leave, directory
change, or cursor idle. Like jj status, the query snapshots saved working-copy
changes; unsaved buffer edits are not included. Redrawing Lualine never runs JJ.
Other community options include jiejie.nvim (Fugitive-style), neojj (Magit-style), and jj-diffconflicts (dedicated merge tool). These are not installed alongside the primary interface to avoid overlapping workflows. vcsigns.nvim is worth considering for native JJ gutter signs, especially in non-colocated repositories; the existing Gitsigns setup is retained, so its Git-based signs/actions are not JJ-aware.
The lowest-friction entry points are:
- lua/user/config.lua: top-level user switches such as completion engine
- lua/user/keymaps.lua: personal mappings
- lua/user/options.lua: editor defaults
- lua/user/lsp: LSP handlers, per-server settings, semantic token styling
If you want to remove or swap functionality, the corresponding plugin specs are usually under a matching folder in lua/plugins/.
This section is the repo-level source of truth for repo-owned keymaps.
Maintenance contract:
- Any change that adds, removes, or repurposes a keymap in lua/user/keymap/plain.lua, lua/user/keymap/lazy.lua, lua/user/keymap/buffer.lua, lua/user/keymap/which_key.lua, lua/user/autocommands.lua, or plugin specs with
M.keysmust update this section in the same change. - If a key replaces a core Neovim mapping, keep the
Overrides builtinandReplaced meaningcolumns in sync. For builtin-like normal-mode slots (g*,z*,<C-w>*, single-key,Ctrl-letter), addconflict.builtinor at leastconflict.notein the registry entry so the audit knows the slot was reviewed. - Centralized
[/]entries must declare whether they are bracketmotionor bracketactionviasymbol = { ... }. Bracket motions are expected to be previous/next pairs and repeat through demicolon; bracket actions must opt out withsymbol.repeatable = false. - Centralized
>/</=entries are treated as operator-style actions, not navigation prefixes. They must declaresymbol = { family = "operator", role = "action", repeatable = false, ... }. (/)/{/}stay reserved for native motions rather than repo-defined prefix families.- Buffer-local mappings should be documented with their scope, not only by key.
Scope notes:
- This inventory focuses on repo-owned mappings and repo-generated prefixes.
- It does not fully expand upstream default plugin mappings inherited from plugins, such as
nvim-tree'sdefault_on_attach()defaults. mapleaderandmaplocalleaderare both\, configured in lua/user/config.lua.- Plugin-local bracket families that are still generated outside the centralized registry, such as toggle.nvim's
[o/]o, are documented here but are not yet covered by the symbol-family audit.
[/]are the repo's navigation family. Use them for previous/next style motions like[b/]b; centralized motion entries should be repeatable with demicolon.[/]may still host actions when Neovim or a plugin already uses that syntax, such as Yanky's[p/]p, but those entries should explicitly opt out of repeatability.>/</=are operator-style action families. Keep them for transforms such as Yanky's shifted or filtered puts, not for next/previous navigation.(/)/{/}are kept for native motions rather than repo-owned prefix namespaces.
| Mode | Key | Current meaning | Overrides builtin | Replaced meaning / notes |
|---|---|---|---|---|
n |
<C-Up>, <C-Down>, <C-Left>, <C-Right> |
Resize splits | No | Repo-owned resize shortcuts |
n |
<C-h>, <C-j>, <C-k>, <C-l> |
Treewalker structural navigation | No | Uses nonstandard control slots for syntax-aware movement |
all |
<C-\\> |
Toggle floating terminal | No | Set by toggleterm open_mapping |
n |
<C-w>z, <C-w>_, <C-w>|, <C-w>= |
windows.nvim maximize / equalize helpers | Yes | Replaces core window commands with plugin implementations |
n, v |
<C-a>, <C-x> |
dial.nvim increment / decrement | Yes | Replaces core numeric increment / decrement with dial logic |
n |
<C-n>, <C-p> |
Yank history next / previous | Yes | Replaces normal-mode slots with Yanky ring navigation |
i, s |
<C-n>, <C-p> |
LuaSnip next / previous choice | Yes | Replaces insert/select completion-style navigation |
n, v, x |
<A-j>, <A-k> |
Move line / block up or down | No | Repo-owned move.nvim mappings |
n, v |
<A-h>, <A-l> |
Move character / block left or right | No | Repo-owned move.nvim mappings |
n, o, x |
<A-w>, <A-e>, <A-b> |
Spider subword motions | No | Repo-owned alternative word motions |
n, x |
<A-q> |
Toggle multicursor | No | Repo-owned multicursor entrypoint |
i |
<A-e> |
nvim-autopairs fast-wrap | No | Repo-owned insert helper |
n, x |
<Up>, <Down> |
Add cursor above / below | Yes | Replaces plain cursor movement with multicursor actions |
n |
<C-LeftMouse>, <C-LeftDrag>, <C-LeftRelease> |
Multicursor mouse interactions | Yes | Replaces core mouse selection behavior |
n |
<S-h>, <S-l> |
Previous / next buffer | Yes | Replaces H / L screen-line motions |
n |
<F1> |
Toggle profiling | No | Repo-owned profile.nvim helper |
n |
<F2> |
Live rename | No | Repo-owned rename helper |
v |
<F3>, <F4> |
Add / remove highlight | No | Repo-owned highlighting helpers |
n |
<F5> |
OverseerRun |
No | Repo-owned task runner shortcut |
n |
<F6> |
DAP continue | No | Repo-owned debug helper |
n |
<F8> |
Randomize colorscheme | No | Repo-owned theme rotation shortcut |
n |
<F9>, <F10>, <F11> |
DAP breakpoint / step over / step into | No | Repo-owned debug helpers |
n |
<F17>, <F23> |
DAP terminate / step out | No | Repo-owned debug helpers |
| Mode | Key | Current meaning | Overrides builtin | Replaced meaning / notes |
|---|---|---|---|---|
n |
gD |
LSP declaration | Yes | Replaces core declaration jump with LSP declaration |
n |
gd |
LSP definition | Yes | Replaces core local-definition jump with LSP definition |
n |
gI |
LSP implementation | No | Repo-owned LSP slot |
n |
gr |
LSP references | No | Repo-owned LSP slot |
n |
gl |
Diagnostic float | No | Repo-owned diagnostics slot |
n, x |
ga |
EasyAlign | Yes | Replaces core character info display |
n, x |
gx |
Browse open under cursor |
Yes | Replaces builtin open-under-cursor behavior with gx.nvim's :Browse |
n, v |
g<C-a>, g<C-x> |
dial.nvim gnormal / gvisual increment / decrement | Yes | Replaces core g<C-a> / g<C-x> numeric operations |
n, x |
gcr |
coerce motion / visual transform entrypoint | No | Repo-owned transform slot |
n, x |
gS |
mini.splitjoin toggle split/join | No | Split or join function arguments, arrays, dicts |
n, x |
g= |
mini.operators evaluate text | Yes | Replaces core g= format with Lua expression evaluation |
n, x |
gm |
mini.operators multiply (duplicate) text | No | Repo-owned duplicate operator |
n, x |
gs |
mini.operators sort text | Yes | Replaces core gs sleep with sort operator |
| Mode | Key | Current meaning | Overrides builtin | Replaced meaning / notes |
|---|---|---|---|---|
n |
zR, zM, zr, zm |
ufo fold open / close helpers | Yes | Replaces core fold controls with ufo implementations |
n |
zC |
fold-cycle close_all() |
Yes | Replaces core recursive fold close |
n |
K |
Peek folded lines, else hover | Yes | Replaces core keywordprg / help behavior; also shadowed by LSP buffer-local K |
n |
<Tab>, <S-Tab> |
fold-cycle open / close | Yes for <Tab> |
<Tab> replaces jump-list forward (<C-i> equivalent); <S-Tab> is a repo-owned slot |
| Mode | Key | Current meaning | Overrides builtin | Replaced meaning / notes |
|---|---|---|---|---|
n |
[b, ]b |
Previous / next buffer | No | Bracket motion family; repeatable with demicolon |
n, x |
[e, ]e |
Previous / next delimiter | No | sort.nvim bracket motion family; repeatable with demicolon |
n |
[S, ]S |
Previous / next scrollview mark | No | Bracket motion family; repeatable with demicolon |
n |
[g, ]g |
Previous / next git hunk | No | Bracket motion family; repeatable with demicolon |
n |
[x, ]x |
Previous / next merge conflict | No | diffs.nvim buffer-local maps in conflicted files |
n |
[r, ]r |
Previous / next reference | No | Refjump motion family; repeatable with demicolon |
n |
[p, ]p, [P, ]P |
Yanky indent-aware put | Yes | Bracket action family; intentionally non-repeatable |
n |
>p, <p, >P, <P, =p, =P |
Yanky shift / filter put helpers | Yes | Operator-style action family; intentionally non-repeatable |
n, x |
[m, ]m, [M, ]M |
Multicursor match add / skip | No | Repo-owned multicursor navigation |
n |
[t, ]t, [T, ]T |
Previous / next test, previous / next failed test | No | Repo-owned neotest motions; custom demicolon repeat wrapper |
n |
[o{option}, ]o{option} |
toggle.nvim previous / next option state | No | Plugin-generated toggle prefix family |
| Mode | Key | Current meaning | Overrides builtin | Replaced meaning / notes |
|---|---|---|---|---|
n, x |
y |
Yanky yank | Yes | Replaces core yank with yank-ring aware yank |
n |
p, P, gp |
Yanky put family | Yes | Replaces core put family with yank-ring aware put |
n |
gzd, gzt, gzi, gzr |
goto-preview definition / type / implementation / references | No | Requires LSP support for the requested method |
n |
gzP |
Close goto-preview windows | No | Closes all goto-preview windows, not only the current one |
n |
n, N |
hlslens-enhanced next / previous match | Yes | Replaces builtin n / N with hlslens overlay |
n |
*, # |
hlslens-enhanced next / previous word match | Yes | Replaces builtin * / # with hlslens overlay |
n |
g*, g# |
hlslens-enhanced next / previous partial-word match | Yes | Replaces builtin g* / g# with hlslens overlay |
n, x, o |
f, F, t, T |
Flash character motions | Yes | Replaces builtin character motions; repeats through demicolon |
n |
cr |
coerce current word | No | Repo-owned transform entrypoint |
n |
co, ct, cb, c0 |
Resolve conflict with ours / theirs / both / neither | No | diffs.nvim buffer-local maps in conflicted files |
i |
jk, kj |
Exit insert mode | No | Repo-owned insert escape shortcuts |
v |
<, > |
Reindent and keep selection | Yes | Extends core indent behavior to preserve selection |
v |
p |
Black-hole delete then paste | Yes | Avoids clobbering unnamed register |
x |
J, K |
Move selected block down / up | Yes | Replaces core visual/block behavior |
n |
- |
Open Oil float | Yes | Replaces core first-nonblank line motion |
n |
q in qf, help, man, lspinfo buffers |
Close auxiliary window | Yes | Buffer-local override of macro recording key |
n |
yo{option}, yos |
toggle.nvim toggle option / dashboard | No | Plugin-generated option prefix family |
o, x |
various-textobjs family | Extra text objects for indentation, subword, brackets, quotes, values, keys, numbers, diagnostics, folds, chain members, notebook cells, filepaths, colors, and more | Mixed | Exact leaf list lives in lua/plugins/edit/nvim-various-textobjs.lua |
<leader> is \\. The table below lists repo-owned namespaces and leaf keys.
| Prefix | Leaf keys | Current meaning | Overrides builtin | Notes |
|---|---|---|---|---|
<leader>[, <leader>] |
[, ] |
Swap syntax sibling left / right | No | sibling-swap.nvim; repeatable with . |
<leader>A |
A |
Alpha dashboard | No | Standalone action |
<leader>n |
na |
NodeAction |
No | Tree-sitter node actions |
<leader>b |
bb, bn, bi, bI, bc, bp, bP, bf, bh, bl, bm, bM, bsd, bsl, bst, bsr |
Buffer navigation, close, pick, menu, sort, indent-blankline toggle | No | Buffer namespace |
<leader>C |
Cs, Ci, CI, Ca, CS, Ct, Cm, CD, Cf, Cc, C3, C5 |
clangd / C++ helper actions | No | C++ namespace |
<leader>c |
c |
Close current buffer | No | Standalone action |
<leader>d |
d |
Dropbar pick | No | Plain d is a standalone action, but d* also hosts DAP keys |
<leader>d* |
dp, dP, dR, dl |
DAP condition breakpoint, log point, REPL, run last | No | Debug namespace piggybacks on <leader>d |
<leader>e |
e |
Toggle NvimTree | No | Standalone action |
<leader>F |
F |
Live grep with args | No | Standalone action |
<leader>f |
f |
Find files | No | Standalone action |
<leader>g |
gB, gb, gc, gd, gl, gj, gk, gp, gr, gR, gs, gu, go, gv |
Git blame, branches, commits, diff, LazyGit, hunk operations, status, VGit previews | No | Git namespace; gv opens the VGit group |
<leader>gv |
gvd, gvf, gvb, gvh, gvl, gvc, gvs |
VGit project/file diff, blame, file history, commit log/overview, stashes | No | Read-only view entry points; staging/resetting stays with Gitsigns |
<leader>h |
h |
Clear search highlight | No | Standalone action |
<leader>H |
H |
Clear search highlight and export last search to quickfix | No | Standalone action |
<leader>j |
jj, jk, jcj, jck, jgj, jgk, jhj, jhk, jqj, jqk, jv, jl |
Portal jumplist / changelist / grapple / harpoon / quickfix jumps, mini.jump2d visible word / line | No | Jump namespace; jv / jl from mini.jump2d |
<leader>L |
Ld, Lr |
Linediff and reset | No | Line-diff namespace |
<leader>l |
la, ld, lD, lf, lF, lh, li, lI, lj, lk, ll, lo, lq, lr, ls, lS |
LSP code actions, diagnostics, symbols, format, hover, rename, signature, outline | No | LSP namespace |
<leader>M |
Mg, Mj, Ms, Mt |
Grapple mark / select / scopes / tags | No | Marks namespace |
<leader>m |
ma, mm, mn, mp, m1, m2, m3, m4 |
Harpoon toggle, menu, prev/next, select slot | No | Harpoon namespace |
<leader>o |
o |
Smart open (frecency) | No | Standalone action |
<leader>p |
pd, pc, pu, pU, pf, ps, pv, pt, po |
Overlook peek / close / restore / focus / split / vsplit / tab / current window | No | Popup namespace |
<leader>q |
qq, qp, qs, qe, qy, qd |
Macro start/stop, play, switch slot, edit, yank, delete | No | Macro namespace |
<leader>R |
Rr, Rs, RS, Rf, Rh, Rc, Rl |
REPL run / restart / sniprun / focus / hide / send file / send until cursor | No | REPL namespace |
<leader>r |
rc, rf, rs |
RunCode / RunFile / stop runner | No | Run namespace |
<leader>s |
ss, sS, sy, sg, sf, si, sa, sb, sc, sC, sh, sk, sM, so, sp, sr, sR |
Flash, grug-far, yank history, AST grep, buffer search, colorschemes, commands, help, keymaps, man, frecent files, pickers, recent files, registers | No | Search namespace |
<leader>T |
Tf, Th, Tv |
Float / horizontal / vertical terminal | No | Terminal namespace |
<leader>t |
ta, tA, tm, tg, tr, tu, tn, td, tl, tc, ts, to, tp, tw, tj, tk |
CSV column alignment, table mode, TOC, neotest run / Rust-only debug / output / panel / watch / failed-test jumps | No | ta / tA are CSV/TSV buffer-local; tj / tk currently look typo-prone in config |
<leader>w |
wl, ws, wd, wt, wf, wb |
Session management plus MoveWord forward / backward | No | Namespace drift: workspace/session and MoveWord share the same prefix |
<leader>x |
xg, xr |
CellularAutomaton effects | No | Repo-owned extras/effects namespace |
<leader>v |
vv, vl, vj, vk |
mini.visits select path / label / next / previous | No | Visits namespace |
<leader>y |
yc, yy, yt |
Yazi cwd / open / toggle | No | Yazi namespace |
<leader><Up>, <leader><Down> |
↑, ↓ |
Multicursor skip cursor above / below | No | Only meaningful for multicursor workflow |
| Scope | Key | Current meaning | Overrides builtin | Notes |
|---|---|---|---|---|
| CSV/TSV buffer | <leader>ta, <leader>tA |
Align / clear virtual column spacing | No | Buffer-local registry entries applied by decisive.nvim on FileType |
| LSP-attached buffer | K |
Pure LSP hover | Yes | Buffer-local registry entry in lua/user/keymap/buffer.lua, applied from lua/user/lsp/handlers.lua and shadowing the global ufo K |
| Non-LSP buffer | K |
Peek folded lines, else hover | Yes | Global lazy-registry entry from lua/user/keymap/lazy.lua |
qf, help, man, lspinfo, transient nofile floats |
q |
Close window | Yes | Buffer-local helper from lua/user/autocommands.lua |
checkhealth tab |
q |
Close tab | Yes | Buffer-local helper from lua/user/autocommands.lua with a safe fallback to close the window if it is the last tab |
| Terminal buffers | <Esc>, jk, <C-h>, <C-j>, <C-k>, <C-l> |
Leave terminal mode or move between windows | Yes | Buffer-local helpers from lua/plugins/terminal/toggleterm.lua |
| NvimTree buffer | P, <Esc>, <C-f>, <C-b>, <Tab> |
Preview, close preview, preview scroll, smart expand / preview | Mixed | Repo-local additions only; upstream default_on_attach() maps are not expanded here |
- Global
Kfrom lua/user/keymap/lazy.lua is shadowed by buffer-local LSPKfrom lua/user/keymap/buffer.lua, so fold-preview-on-Kdisappears after LSP attach. <leader>dis both a standalone Dropbar action and the parent prefix for DAP leaf keys.<leader>wmixes workspace/session actions with MoveWord (wf,wb), so the namespace is not semantically pure.
Manual tools currently available in this repo:
just keymap-auditruns the repo-owned headless audit and prints a report without failing the shell.just keymap-audit-checkruns the same audit but exits non-zero when duplicate repo registrations or required conflict annotations are missing.just keymap-docsreports central mappings that do not appear in the README inventory tables.just keymap-docs-checkexits non-zero when a central registry or which-key mapping is missing from the README inventory tables.:KeyAnalyzer <leader>,:KeyAnalyzer <C->, and:KeyAnalyzer <M->visualize occupied vs free keys by prefix.:FzfLua keymapsshows the runtime keymap list after lazy loading.:verbose nmap {lhs},:verbose xmap {lhs},:verbose imap {lhs}, and friends show which mapping currently wins and where it was defined.
Practical limitations:
- lua/plugins/keymap/key-analyzer.lua installs
meznaric/key-analyzer.nvim, but that plugin is an analysis / visualization aid, not an automatic conflict warning system. just keymap-audit/just keymap-audit-checkcurrently focus on repo-internal duplicate registrations that survive startup and lazy loading, plus missing builtin-conflict annotations, reviewedconflict.notemetadata for builtin-like normal-mode slots, and missing symbol-family metadata for centralized[/]and>/</=entries. They still do not try to infer every upstream plugin default mapping.just keymap-docs/just keymap-docs-checkcurrently cover the centralized plain, lazy, buffer, and which-key registries that back the README inventory tables. Plugin-generated or attach-time families that are still documented only at a coarse summary level remain outside that strict coverage.- Upstream
key-analyzer.nvimreads mappings viavim.api.nvim_get_keymap(), so it does not fully cover built-in families such as<C-w>andz, and it does not show buffer-local mappings. which-key.nvimimproves discoverability, but it does not validate conflicts or duplicate ownership.- There is currently no plugin in this repo that will reliably warn on every repo-internal conflict as soon as a mapping changes, especially across lazy-loaded, plugin-generated, and buffer-local mappings.
If automatic warnings become a requirement, the more reliable next step is a repo-owned audit command or headless script that:
- collects global and buffer-local mappings,
- groups them by mode and lhs,
- flags duplicate lhs ownership,
- and checks whether builtin overrides or reviewed builtin-like slots are explicitly documented in this section and registry metadata.
This repo also supports project-local configuration through klen/nvim-config-local.
The current setup looks for these files in the current working directory and
its parent directories:
.nvim.lua.nvimrc.exrc.nvim/nvim.lua
The default starting point is .nvim/nvim.lua in your project root.
Use project-local config when something should only apply to one repository, such as:
- setting
vim.g.*globals for Vim plugins - enabling or disabling repo-specific linters
- adding project-only autocommands, keymaps, or environment tweaks
Typical flow:
- Run
:ConfigLocalCreatefrom the project root to prepare an unsaved.nvim/nvim.luabuffer. - Fill the TODO fields and adjust any defaults for the project.
- Write the file, then allow it when prompted.
If the file contents or path change later, Neovim will ask you to trust it again.
Useful commands:
:ConfigLocalCreateto prepare an unsaved.nvim/nvim.luafor an empty project, including TODO project fields plus header/template, linter, formatting, Markdown, and LaTeX defaults:ConfigLocalEditto open or create the local config file:ConfigLocalSourceto source the current project config again:ConfigLocalTrustto mark the current project config as trusted:ConfigLocalDenyto deny the current project config
Template maintenance:
- Project-local fields are declared in lua/util/project_config.lua.
- When adding a new project-level
vim.g.*setting, add it to that registry with a runtimedefaultand, when the generated config should prompt the user, a separatetemplateTODO value. - Runtime consumers should read these values with
require("util.project_config").get "setting_name".:ConfigLocalCreaterenders the template from the same registry.
Example: plugin globals for one project only
vim.g.tex_flavor = "latex"
vim.g.vim_markdown_folding_disabled = 1Example: repo-specific linter toggles
vim.g.linters = {
clangtidy = true,
cppcheck = false,
cpplint = false,
}This config is read by lua/plugins/linter/nvim-lint.lua.
Example: arbitrary project-local Lua
vim.env.CC = "clang"
vim.api.nvim_create_autocmd("FileType", {
pattern = "markdown",
callback = function()
vim.opt_local.wrap = true
vim.opt_local.spell = true
end,
})The main tradeoff is flexibility versus discoverability: these files can run arbitrary Lua or Vimscript, which makes them powerful, but they do not have the schema validation and completion that more structured project-local config systems provide.
Run :DebugConfigCreate from a project root and select a template in
templates/debug. Empty prepares JSONC skeletons; the
other choices cover C, C++, Python, Rust, Go, JavaScript, TypeScript, Lua,
Ruby, and Bash. Check each template's defaults before saving:
- C/C++ offer GDB or CodeLLDB with a CMake build task; set the actual
executable and build directory. Rust uses CodeLLDB and
cargo build; set the binary name intarget/debug. Go uses Delve and expects a Go package at the project root. - Python uses debugpy and
python3; changepythonto the project's interpreter if needed. JavaScript runs the current file with Node.js; TypeScript additionally needstsxinstalled in the project (npm install --save-dev tsx). These are Node scripts, not browser configs. - Lua has separate templates:
Lua (standalone / Lua 5.3)launches the current file withlua5.3and the local Lua debugger; change the interpreter to a supported Lua 5.1-5.3 or LuaJIT if needed (not Lua 5.4/5.5).Lua (Neovim / OSV attach)instead connects to another Neovim instance running:lua require("osv").launch({port = 8086}); it does not start a Lua script. Ruby runs the current file throughrdbg(install the Rubydebuggem). Bash uses the Mason-provided bash-debug-adapter and bashdb; it also needsbash,cat,mkfifo, andpkillonPATH.
New launch templates pause at entry without a breakpoint when supported:
GDB uses stopAtBeginningOfMainSubprogram, while CodeLLDB, Python, Go,
Node.js, and standalone Lua use stopOnEntry. Bash's adapter has no supported entry
pause setting. Neovim Lua and Ruby use attach configurations, so they cannot
generally guarantee a pause before the target starts running. Existing project
.vscode/launch.json files are not changed when templates are updated.
Mason is configured to install debugpy, CodeLLDB, Delve, js-debug-adapter,
and bash-debug-adapter; the standalone Lua debugger is built by lazy.nvim
with npm. GDB, Node.js, Cargo, Go, Ruby/debug, and shell tools
must be available separately. Both
.vscode/launch.json and .vscode/tasks.json are prepared as unsaved buffers:
the command opens launch.json, and you can switch to the tasks.json buffer
to edit it before :write on each file. Canceling the selection creates
nothing; existing files and unsaved drafts are not overwritten. nvim-dap reads
launch configurations and Overseer reads tasks from this fixed directory;
.nvim/nvim.lua remains for trusted project-local Lua settings.
- This is a personal config repo, not a polished distribution.
- The code is a more reliable source of truth than old documentation copied from upstream templates.
lazy-lock.jsonis ignored in git, so plugin versions are always latest (if break, should be fixed ASAP).